scanf ignoring, infinite loop

When you enter something that isn't a number, scanf will fail and will leave those characters on the input. So if you enter hello, scanf will see the h, reject it as not valid for a decimal number, and leave it on the input. The next time through the loop, scanf will see the h again, so it just keeps looping forever.

One solution to this problem is to read an entire line of input with fgets and then parse the line with sscanf. That way, if the sscanf fails, nothing is left on the input. The user will have to enter a new line for fgets to read.

Something along these lines:

char buffer[STRING_SIZE];
...
while(...) {
    ...
    fgets(buffer, STRING_SIZE, stdin);
    if ( sscanf(buffer, "%d", &price) == 1 )
        break;   // sscanf succeeded, end the loop
    ...
}

If you just do a getchar as suggested in another answer, then you might miss the \n character in case the user types something after the number (e.g. a whitespace, possibly followed by other characters).

You should always test the return value of sscanf. It returns the number of conversions assigned, so if the return value isn't the same as the number of conversions requested, it means that the parsing has failed. In this example, there is 1 conversion requested, so sscanf returns 1 when it's successful.


The %d format is for decimals. When scanf fails (something other a decimal is entered) the character that caused it to fail will remain as the input.

Example.

    int va;
    scanf("%d",&va);
    printf("Val %d 1 \n", val);

    scanf("%d",&va);
    printf("Val %d 2 \n", val);
    return 0;

So no conversion occurs.

The scanf function returns the value of the macro EOF if an input failure occurs before any conversion. Otherwise, the scanf function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure

7.19.6. The scanf function - JTC1/SC22/WG14 - C

So you should note that scanf returns its own form of notice for success

int scanf(char *format)

so you could have also did the following

do {
        printf("Enter Product \n");
}
while (scanf("%d", &sale.m_price) == 1);

if(scanf("%d", &sale.m_price) == 0)
        PrintWrongInput();

Also keep in the back of your head to try to stay away from scanf. scanf or scan formatted should not be used for interactive user input. See the C FAQ 12.20


After the first number, a '\n' will be in the input buffer (the return you pressed to input the number), so in the second iteration the scanf call will fail (becouse \n isn't a number), scanf will not remove that \n from the buffer, so in the next iteration it will fail again and so on.

You can fix that by reading the '\n' with a getchar() call after scanf.


The "answers" that say it will because there is a '\n' in the buffer are mistaken -- scanf("%d", ...) skips white space, including newlines.

It goes into an infinite loop if x contains 0 and scanf encounters a non-number (not just whitespace) or EOF because x will stay 0 and there's no way for it to become otherwise. This should be clear from just looking at your code and thinking about what it will do in that case.