Scanf returns 0 without waiting for input

2019-02-25 09:40发布

问题:

I have never programmed in C and today I have to write small code. Program is very easy - I want to add two integers. But when I'm trying to check if given input is a number and first scanf returns 0, the second one returns 0 too without waiting for input. Code:

int main()
{
    int a = 0;
    int b = 0;
    printf("Number a:\n");
    if (scanf("%d", &a) != 1)
    {
        printf("Not a number. a=0!\n");
        a = 0;
    }
    printf("Number b:\n");
    if (scanf("%d", &b) != 1)
    {
        printf("Not a number. b=0!\n");
        b = 0;
    }
    printf("%d\n", a+b);
    return 0;
}

回答1:

That is because, once the first scanf() failed, it is probably because of matching failure, and the input which caused the matching failure, remains inside the input buffer, waiting to be consumed by next call.

Thus, the next call to scanf() also try to consume the same invalid input residing in the input buffer immediately, without waiting for the explicit external user input as the input buffer is not empty.

Solution: After the first input fails for scanf(), you have to clean up the input buffer, for a trivial example, something like while (getchar() != '\n'); should do the job.



回答2:

The input that failed to convert to a number for the first fscanf() is still pending in standard input's buffer and causes the second fscanf() to fail as well. Try discarding offending input and re-prompting the user:

#include <stdio.h>

int main(void) {
    int a = 0;
    int b = 0;
    int c;
    printf("Number a:\n");
    while (scanf("%d", &a) != 1) {
        printf("Not a number, try again:\n");
        while ((c = getchar()) != EOF && c != '\n')
            continue;
        if (c == EOF)
            exit(1);
    }
    printf("Number b:\n");
    while (scanf("%d", &b) != 1) {
        printf("Not a number, try again:\n");
        while ((c = getchar()) != EOF && c != '\n')
            continue;
        if (c == EOF)
            exit(1);
    }
    printf("%d\n", a + b);
    return 0;
}

Factorizing the code with a utility function makes it much clearer:

#include <stdio.h>

int get_number(const char *prompt, int *valp) {
    printf("%s:\n", prompt);
    while (scanf("%d", valp) != 1) {
        printf("Not a number, try again:\n");
        while ((c = getchar()) != EOF && c != '\n')
            continue;
        if (c == EOF)
            return 0;
    }
    return 1;
}

int main(void) {
    int a, b;

    if (!get_number("Number a", &a) || !get_number("Number b", &b)) {
         return 1;
    }
    printf("%d\n", a + b);
    return 0;
}


回答3:

It's because of input and output aren't synchronized in C. The program can output some lines after user's input while the input hasn't been read. Try to run this code:

char token;

scanf("%c", &token);
printf("%c\n", token);
printf("line 1\n");

scanf("%c", &token);
printf("%c\n", token);
printf("line 2\n");

scanf("%c", &token);
printf("%c\n", token);
printf("line 3\n");

And input abc in one line.

You can imagine this like there are two separated consoles, one for input and another for output.


For example you want to input asd for a and 3 for b. In this case, the first scanf won't find any number and will return 0. But it also won't read anything from the input. Because of this, the second scanf will see asd too.

To clear the input if a isn't a number, you should input all remaining chars in the line until '\n' (look at the @Sourav's solution)



回答4:

You could do the same thing using strings without problems with scanf. Just take the user input as string and convert it to integer. Then convert the string back to integer to check whether they are the same. If they are the same, treat a and b as integers, if not, do what you do (You will need to include string.h). Here is the working code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
int a;
int b;
char str1[100];
char str2[100];

printf("Number a:\n");  
scanf("%s", &str1); //take input as a string
a = atoi(str1); //convert string to integer
snprintf(str2, 100, "%d", a); //convert integer back to string

//if the integer converted to string is not the same as the string converted to integer
if (strcmp(str1, str2)!= 0)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
scanf("%s", &str1);
b = atoi(str1);
snprintf(str2, 100, "%d", b);

if (strcmp(str1, str2)!= 0)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);

return(0);
}


标签: c scanf stdin