Why is scanf() causing infinite loop in this code?

Viewed 68187

I've a small C-program which just reads numbers from stdin, one at each loop cycle. If the user inputs some NaN, an error should be printed to the console and the input prompt should return again. On input of "0", the loop should end and the number of given positive/negative values should be printed to the console. Here's the program:

#include <stdio.h>

int main()
{
    int number, p = 0, n = 0;

    while (1) {
        printf("-> ");
        if (scanf("%d", &number) == 0) {
            printf("Err...\n");
            continue;
        }
        
        if (number > 0) p++;
        else if (number < 0) n++;
        else break; /* 0 given */
    }

    printf("Read %d positive and %d negative numbers\n", p, n);
    return 0;
}

My problem is, that on entering some non-number (like "a"), this results in an infinite loop writing "-> Err..." over and over. I guess it's a scanf() issue and I know this function could be replace by a safer one, but this example is for beginners, knowing just about printf/scanf, if-else and loops.

I've already read the answers to the questionscanf() skips every other while loop in C and skimmed through other questions, but nothing really answer this specific problem.

16 Answers

The Solution: You need to add fflush(stdin); when 0 is returned from scanf.

The Reason: It appears to be leaving the input char in the buffer when an error is encountered, so every time scanf is called it just keeps trying to handle the invalid character but never removing it form the buffer. When you call fflush, the input buffer(stdin) will be cleared so the invalid character will no longer be handled repeatably.

You Program Modified: Below is your program modified with the needed change.

#include <stdio.h>

int main()
{
    int number, p = 0, n = 0;

    while (1) {
        printf("-> ");
        if (scanf("%d", &number) == 0) {
            fflush(stdin);
            printf("Err...\n");
            continue;
        }

        if (number > 0) p++;
        else if (number < 0) n++;
        else break; /* 0 given */
    }

    printf("Read %d positive and %d negative numbers\n", p, n);
    return 0;
}

try using this:

if (scanf("%d", &number) == 0) {
        printf("Err...\n");
        break;
    }

this worked fine for me... try this.. the continue statement is not appropiate as the Err.. should only execute once. so, try break which I tested... this worked fine for you.. i tested....

To solve partilly your problem I just add this line after the scanf:

fgetc(stdin); /* to delete '\n' character */

Below, your code with the line:

#include <stdio.h>

int main()
{
    int number, p = 0, n = 0;

    while (1) {
        printf("-> ");
        if (scanf("%d", &number) == 0) {
            fgetc(stdin); /* to delete '\n' character */
            printf("Err...\n");
            continue;
        }

        if (number > 0) p++;
        else if (number < 0) n++;
        else break; /* 0 given */
    }

    printf("Read %d positive and %d negative numbers\n", p, n);
    return 0;
}

But if you enter more than one character, the program continues one by one character until the "\n".

So I found a solution here: How to limit input length with scanf

You can use this line:

int c;
while ((c = fgetc(stdin)) != '\n' && c != EOF);
// all you need is to clear the buffer!

#include <stdio.h>

int main()
{
    int number, p = 0, n = 0;
    char clearBuf[256]; //JG:
    while (1) {
        printf("-> ");
        if (scanf("%d", &number) == 0) {
            fgets(stdin, 256, clearBuf); //JG:
            printf("Err...\n");
            continue;
        }

        if (number > 0) p++;
        else if (number < 0) n++;
        else break; /* 0 given */
    }

    printf("Read %d positive and %d negative numbers\n", p, n);
    return 0;
}
Related