Why can't I use scanf on the same variable aga

2019-08-06 08:45发布

问题:

Please see the following code:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int n;
    int i = scanf("%d", &n);
    printf("%d\n", i);
    int j = scanf("%d", &n);
    printf("%d\n", j);
    return 0;
}

Suppose I input a string for n at the first time, scanf will return 0; however, why it won't allow me to input a value for n the second time and j is automatic 0? What should I do to make it allow me to input a value for n again even if I typed a wrong value at the first time?

回答1:

You're almost certainly entering a non-numeric value, which will cause the first scanf to fail, returning zero and (this is the important bit) leaving the stream pointer exactly where it was before the scanf call.

That means the next time you call it, it will simply try to read the same data.

The return value of zero is a dead giveaway - scanf returns the number of items successfully scanned, so zero means you didn't give it a number.

If you enter numbers, it works fine, as per the following code:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int n;
    int i = scanf("%d", &n);
    printf(">> %d %d\n", i, n);
    int j = scanf("%d", &n);
    printf(">> %d %d\n", j, n);
    return 0;
}

When you run that and enter 41 and 32, you see:

41
>> 1 41
32
>> 1 32

Every C programmer at some point in their career comes up against the inadequacies of user input in that language. Your best bet for line based input is to simply find a function that does it well, then use sscanf on the resultant string.

One that ensures lines are the basic unit, and can handle buffer overflows and making sure excess data doesn't "corrupt" future input.

Here's one I prepared earlier.



回答2:

The non-numeric string you entered isn't consumed by scanf.

Instead, you can use fgets and sscanf like this:

#include <stdio.h>

int main(void)
{
    int n;
    char str[100];
    fgets(str, sizeof(str), stdin);
    int i = sscanf(str, "%d", &n);
    printf("%d\n", i);
    fgets(str, sizeof(str), stdin);
    int j = sscanf(str, "%d", &n);
    printf("%d\n", j);
    return 0;
}


回答3:

You can ignore the rest of the line before entering input afresh and reading them. You can ignore the rest of the line using:

scanf("%[^\n]*\n");


回答4:

If you enter numbers your code will work fine. However, when you are entering a string, then you must remove the string from input stream before using it again.


For example:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int n;
    char c;
    int i = scanf("%d", &n);
    printf("%d\n", i);
    //Remove the previous string from the input stream
    while ( (c = getchar()) != '\n' && c != EOF );
    int j = scanf("%d", &n);
    printf("%d\n", j);
    return 0;
}

Output when input is integer

100
1
200
1

Output when input is strings

abcd
0
efghi
0

For further reference: Why does everyone say not to use scanf? What should I use instead?



标签: c scanf