Thread: Checking input in a while loop...

  1. #1
    Registered User
    Join Date
    Jan 2013
    Posts
    5

    Checking input in a while loop...

    This is what I have for this particular function so far...

    Code:
    unsigned long getNum(char prompt[80])
    {
       unsigned long darts;
       printf("%s", prompt);
       while((scanf("%lu", &darts)) != 1)
       {  
          printf("\n\nThis is not an acceptable entry. please try again.\n");
          printf("%s", prompt);
       }
       return darts;
    }
    it works perfectly fine if I enter a number. but if i enter a character or letter or something, i was expecting it to reprompt, but instead it goes into an infinite loop of prompting and error messages. Can someone explain why? How can I fix it?

  2. #2
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    Thus is one of the major problems with directly calling scan* functions on input, rather then on a string you already read from input.

    What's happening is that your scanf() is looking for a "unsigned long value", but the input contains character/non-number characters. So the scanf call fails, returning 0 your while loop runs again and it calls the scanf() again -- heres where the problem comes in the letter/non-number were not CONSUMED by scanf() because it failed, thus they are STILL IN THE INPUT BUFFER. So scanf() sees there's data in the input buffer, attempts to again try to read a unsigned long and again fails, over and over and over.

  3. #3
    Registered User
    Join Date
    Jan 2013
    Posts
    5
    what can i do to "consume" that letter/non number? Ive actually already considered that as a possibilty and tried a couple of things that didnt work.

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    By not using scanf . If scanf is looking for a number, it won't read past any characters, unless they are valid for that type, or a white space. That is, for an unsigned long type, it will skip any leading white space, then try to read digits. If there are no digits, it fails the scan and returns 0, but it does not discard that input.

    A better solution would be to read a line into a temporary char buffer, using fgets, then use a function like strtoul to try to convert the buffer to an unsigned long. You might want to switch to a do-while loop for this.

  5. #5
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    Why do people insist on using SCANF()? So annoying. Professors/schools need to stop teaching this and just teach fgets+sscanf.

  6. #6
    Registered User
    Join Date
    Jan 2013
    Posts
    5
    Okay thanks guys. Its for a class like you mentioned. I was trying to get a bit fancy with the loop and checking input, but since we learned scanf() at this point specifically im not gonna get so fancy that i start using completely different functions. I guess ill just have to cringe and have no input check at all.

  7. #7
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Revise your input function as follows

    Code:
    unsigned long getNum(char prompt[80])
    {
       unsigned long darts;
       printf("%s", prompt);
       while((scanf("%lu", &darts)) != 1)
       {
          printf("\n\nThis is not an acceptable entry. please try again.\n");
          printf("%s", prompt);
          int c;
          while ((c = getchar()) != '\n' && c != EOF)
             ;
       }
       return darts;
    }
    What's happening is this. There is a newline at the end of your buffer which scanf never consumes. So the part after you give the error message should throw away all characters up to and including the newline.

  8. #8
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    @c99tutorial
    scanf() already ignore whitespace (when reading unsigned long at least) that is not the issue. See posts above. He would have to instead do something like this:

    Code:
    #include <ctype.h>
    ...
       while((scanf("%lu", &darts)) != 1)
       {
          printf("\n\nThis is not an acceptable entry. please try again.\n");
          printf("%s", prompt);
          int c;
          while (!isdigit(c = getchar()) && c != EOF)
             ;
          if (isdigit(c)) ungetc(c, stdin);
       }
    Hacky but could work....you could also roll your own 'isdigit()' to prevent having to use a "function you haven't learned yet". However in my experience professors normally appreciate when you take the initiative and learn ahead in the book/etc whatever...

    If you use fgets()+sscanf as we suggested prior, and can explain to your professor WHY you need to use it and the problems you ran into with scanf() he'll probably give you extra points.

  9. #9
    Registered User hex_dump's Avatar
    Join Date
    Dec 2012
    Posts
    88
    Quote Originally Posted by DMD85 View Post
    what can i do to "consume" that letter/non number? Ive actually already considered that as a possibilty and tried a couple of things that didnt work.
    after your call to scanf(), use getchar() to "eat" all the invalid input in the buffer.

    nonpuz, I hear you on the problem with scanf but it does come in handy if you have guaranteed data formatted in a certain way. For example a JSON or CSV file. I do agree though that C still has a few legacy warts that need to be phased out.

  10. #10
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Clear stdin on the event of a fail and your code will work fine.

    Here is a short bit of code that demonstrates the problem

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main(void)
    {
        unsigned long darts;
    
    
        printf(">>");
        fflush(stdout);
    
    
        while((scanf("%lu", &darts)) != 1)
        {
            int c;
            
            while ((c = getchar()) != '\n' && c != EOF)
            {
                continue;
            }
    
    
            printf("!\n>>");
            fflush(stdout);
        }
    
    
         return EXIT_SUCCESS;
    }
    Fact - Beethoven wrote his first symphony in C

  11. #11
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Quote Originally Posted by nonpuz View Post
    Why do people insist on using SCANF()? So annoying. Professors/schools need to stop teaching this and just teach fgets+sscanf.
    There are a few similarities between scanf and sscanf...
    Fact - Beethoven wrote his first symphony in C

  12. #12
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    @Click_here....wrong again, please see c99tutorials post and then READ all the posts above.

  13. #13
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Quote Originally Posted by nonpuz View Post
    @Click_here....wrong again, please see c99tutorials post and then READ all the posts above.
    Have you ran my code...

    ... I bet that you haven't ...
    Fact - Beethoven wrote his first symphony in C

  14. #14
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    1. I don't need to run your code to know that it doesn't solve the problem the OP asked for.
    2. scanf() when reading numbers CONSUMES WHITESPACE ALREADY (including NEWLINES)
    3. Have you run your code and then entered a NON-NUMERIC entry and seen what happened? Do that. That is what the OPs problem is.

  15. #15
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Quote Originally Posted by nonpuz View Post
    1. I don't need to run your code to know that it doesn't solve the problem the OP asked for.
    2. scanf() when reading numbers CONSUMES WHITESPACE ALREADY (including NEWLINES)
    3. Have you run your code and then entered a NON-NUMERIC entry and seen what happened? Do that. That is what the OPs problem is.
    I ran the OP's code where I confirmed that (in the word of the OP)
    Quote Originally Posted by DMD85
    it works perfectly fine if I enter a number. but if i enter a character or letter or something, i was expecting it to reprompt, but instead it goes into an infinite loop of prompting and error messages.
    What do you think happens to the data on stdin when scanf fails?...

    3 - Yes. When I ran my code with the while loop removing all input up to a new line character, it works.

    It frustrates me that you have criticised my code, without testing it. And it appears that you don't understand that the problem is that scanf is not removing any characters from stdin on an unsuccessful attempt.
    Fact - Beethoven wrote his first symphony in C

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. While loop not checking if VE>0
    By JonathanS in forum C Programming
    Replies: 11
    Last Post: 10-02-2011, 10:15 AM
  2. checking input
    By deviousdexter in forum C# Programming
    Replies: 23
    Last Post: 12-19-2008, 05:20 PM
  3. checking input
    By mackol in forum C++ Programming
    Replies: 4
    Last Post: 03-16-2003, 10:47 PM
  4. checking input int
    By hurry up in forum C Programming
    Replies: 4
    Last Post: 03-15-2003, 04:15 AM
  5. Checking input
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 05-26-2002, 03:06 AM