1

Consider the following code snippet:

int n;
int a[100];
int main()
{
    printf("\nThis program will sort a given list of between 1 and 100 integers.\n\n");
    int ready = 0;
    while(!ready)
    {

        printf("How many integers are in your list? ");
        scanf("%d",&n);

        if(n>100)
        {
            printf("\n\nError:\tToo many integers.\n\tThis program can only handle up to 100 integers.\n\n\n"); 
        }
        else if (n<1)
        {
            printf("\n\nError:\tNot enough integers.\n\tThis program requires at least 1 integer to sort.\n\n\n");
        }
        else ready=1;
    }
}

It works as expected if you enter any integer at the prompt, but If you enter a character, it starts to continually output:

How many integers are in your list?

Error: Too many integers.
       This program can only handle up to 100 integers.

...
...
recurse over and over

Obviously it has something to do with the scanf() function, but I would like to know what goes on under the hood that causes this abstraction to leak the way it does.

I am used to languages with floaties and life jackets and I am trying to get used to swimming in the deeper end of the swimming pool with C.

Luke
  • 5,567
  • 4
  • 37
  • 66
  • possible duplicate of [Why is scanf() causing infinite loop in this code?](http://stackoverflow.com/questions/1716013/why-is-scanf-causing-infinite-loop-in-this-code) – Scott Mermelstein Feb 06 '15 at 14:47

2 Answers2

3

If you enter a character then scanf() fails and the results are not defined after that and also the input is not consumed and stays in the buffer recursively fetching the same value causing your scanf() to fail repeatedly.

So you should do

if(scanf("%d",&n) == 1)
// Do your stuff
Gopi
  • 19,784
  • 4
  • 24
  • 36
  • While that will detect the invalid input it will also end up trying to read the same input again if the input was invalid in the next iteration of the loop. One strategy might be to discard the entire line (e.g. with calling getchar() in a loop) if you detect invalid input. – nos Feb 06 '15 at 14:50
  • @nos Very good suggestion.. Thanks for adding it as a comment – Gopi Feb 06 '15 at 14:53
2

Because the scanf function will only extract the input if it's correct. If the input is not correct, the input will still be in the input buffer when the loop iterates, and the next call to scanf will read the exact same input.

You might want to either use the return value of scanf to determine if you should exit the loop, or use e.g. fgets to read and extract the complete line, and then use e.g. strtol (or sscanf) to get the value.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • "If the input is not correct, the input will still be in the input buffer..." . I've read that once data has been read from the `stdin`, it is gone. How is it that `scanf` with `%d` puts data back into the `stdin` once it is an invalid input? – Spikatrix Feb 06 '15 at 16:19
  • @CoolGuy The problem is that `scanf` doesn't even extract the "illegal" characters from the input buffer. If scanning for a number, and the first character in the buffer is not a digit, then `scanf` will return immediately. – Some programmer dude Feb 06 '15 at 16:33
  • So, `scanf` has the ability to "peep" into the `stdin` before *extracting* data? But to "see" the characters, isn't it required to *extract* them? – Spikatrix Feb 06 '15 at 16:36
  • @CoolGuy The characters in the input is *buffered*. That means the file read function reads a large chunk from the input file and stores it in an array in memory. The file handle (the `FILE` structure) has a pointer to this array, and a "current" position in the array where to start reading from next. The `scanf` simply checks this "current" position, and if it's a valid character then it advances the current position, else it does not. – Some programmer dude Feb 06 '15 at 18:55