1

below is my simple code to enter a number and print it. it is inside a while(1) loop so i need to "Enter the number infinite number of time- each time it will print the number and again wait for the input".

#include<stdio.h>
int main()
{
    int i;

    while(1){
        printf("\nenter i \n");
        scanf("%d", &i);
        if(i==1)
        {
            printf("%d \n", i);
        }
    }
    return 0;
}

it was working fine. but suddenly i noticed that IF i ENTER a character(eg: "w") instead of number , from there it won't ask for input!!!** it continuesly prints,

enter i
1
enter i
1
......

when i debug using GDB, i noticed that after i enter "w", that value of character "w" is not stored in &i . before i enter "w" it had 0x00000001 so that "1" is printed through out the process.

  1. Why it doesn't ask for another input? According to my knowledge, when I enter "w" the ascii value of "w" should be stored in &i. But it doesn't happen.

  2. If I put, "int i; " inside while loop it works fine! Why?

Please test my code in following way:

  • Copy and paste and run it
  • When "enter i" prompt will come enter 1
  • Second time enter "w". See what happens...
vgru
  • 49,838
  • 16
  • 120
  • 201
mr.Cracker
  • 211
  • 3
  • 14
  • 1
    Because the bogus input already in the input stream (your `w`) hasn't been *removed*. – WhozCraig Aug 26 '14 at 08:36
  • scanf does not consume stuff it does not match. You must consume it yourself. – MightyPork Aug 26 '14 at 08:37
  • So, basically, you want to say that `scanf` no longer waits for input, after you enter `w` for the first time? – vgru Aug 26 '14 at 08:37
  • `%d` means a number, right? – doctorlove Aug 26 '14 at 08:38
  • @mr-cracker What makes you think reading `w` with `%d` would result in `w`'s ASCII value? – Biffen Aug 26 '14 at 08:39
  • k, that might be wrong. but i wanna know because of that reason for the next loop why don't it ask for an input? is it a bug? what is the logic behind it? – mr.Cracker Aug 26 '14 at 16:16
  • 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) – poolie Apr 07 '15 at 02:29

5 Answers5

3

You need to check the return value of scanf as well, as it will return the number of successfully scanned and parsed values. If it returns zero (or EOF) then you should exit the loop.

What happens when you enter e.g. the character 'w' instead of a number is that the scanf function will fail with the scanning and parsing, and return zero. But the input will not be removed from the input buffer (because it was not read), so in the next loop scanf will again read the non-numeric input and fail, and it will do this infinitely.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    +1 Why the downvotes? This is the first correct answer. – vgru Aug 26 '14 at 08:41
  • @Groo I've edited the answer, I got the downwote before the answer was complete. – Some programmer dude Aug 26 '14 at 08:41
  • @Joachim: that's strange, I am pretty sure the score reduced after I upvoted (that's why I checked the ratio in the first place). Probably there was another downvote already. – vgru Aug 26 '14 at 08:43
  • This answer should be accepted for being best and the first one to answer the question! – Am_I_Helpful Aug 26 '14 at 08:43
  • I would like also to be god, but I am not god. Why upvoting this answer and downvoting the question? Tell me, what is the difference? – nbro Aug 26 '14 at 08:45
  • People on SO are spastic with their downvotes. I think it makes them feel like they have done something important. – David C. Rankin Aug 27 '14 at 15:46
3

scanf with %d format specifier will read everything that "looks like a number", i.e. what satisfies the strictly defined format for a decimal representation of an integer: some optional whitespace followed by an optional sign followed by a sequence of digits. Once it encounters a character that cannot possibly be a part of a decimal representation, scanf stops reading and leaves the rest of the input data in the input stream untouched (to wait for the next scanf). If you enter just w, your scanf will find nothing that "looks like a number". It will read nothing. Instead it will report failure through its return value. Meanwhile your w will remain in the input stream, unread. The next time you try your scanf, exactly the same thing will happen again. And again, and again, and again... That w will sit in the input stream forever, causing each of your scanf calls to fail immediately and your loop to run forever (unless your uninitialized variable i by pure chance happens to start its life with the value of 1 in it).

Your assumption that entering w should make scanf to read ASCII code of w is completely incorrect. This sounds close to what %c format specifier would do, but this is not even close to what %d format specifier does. %d does not read arbitrary characters as ASCII codes.

Note also that every time you attempt to call that scanf with w sitting in the input stream, your scanf fails and leaves the value of i unchanged. If you declare your i inside the loop, the value of i will remain uninitialized and unpredictable after each unsuccessful scanf attempt. In that case the behavior of your program is undefined. It might even produce an illusion of "working fine" (whatever you might understand under that in this case).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
3

You can try this workaround:

int main()
{
    int i;
    char c;
    while (1)
    {
        printf("enter i: ");
        if (scanf("%d",&i) == 0)
            scanf("%c",&c); // catch an erroneous input
        else
            printf("%d\n",i);
    }
    return 0;
}

BTW, when were you planning to break out of that (currently infinite) loop?

barak manos
  • 29,648
  • 10
  • 62
  • 114
2

You need to read up on scanf(), since you seem to be basing your program around some assumptions which are wrong.

It won't parse the character since the conversion format specifier %d means "decimal integer".

Also, note that you must check the return value since I/O can fail. When you enter something which doesn't match the conversion specifier, scanf() fails to parse it.

You would probably be better of reading whole lines using fgets(), then using e.g. sscanf() to parse the line. It's much easier to get robust input-reading that way.

unwind
  • 391,730
  • 64
  • 469
  • 606
1

scanf return type can be checked and based on that inputs can be consumed using getchar to solve your problem.

Example code

    int main()
    {
        int i;
        int ch;
        while(1){

        printf("\nenter i \n");
        if (  scanf("%d", &i) !=1  )
        {
            /*consume the non-numeric characters*/
            for (; (ch = getchar()) != EOF && ch != '\n'; ) { }
        }

        if(i==1)
        {
            printf("%d \n", i);
        }
        }
        return 0;
    }

Description:

When scanf("%d", &i) encounters the character, it will not read it. The character will still remains in the input stream. So to consume those characters, getchar() can used. Then scanf will wait for the next input in further iteration.

mahendiran.b
  • 1,315
  • 7
  • 13