Thread: scanf is also reading the return character when I enter a value and hit return

  1. #1
    Registered User hamsteroid's Avatar
    Join Date
    Mar 2007
    Location
    Waterford, Ireland
    Posts
    62

    scanf is also reading the return character when I enter a value and hit return

    Hi,

    I'm going through loops at the moment in C. This example is simply an infinite loop which takes a value from the user and then asks do they want to continue and if so take another value and so on. When the user says no, the loop breaks and the average is calculated. My problem here is that when I run and enter a value and hit return, say 5, the return character is also used to say "yes continue".

    This program calculates the average of any number of values.
    Enter a value: 5

    Do you want to enter another value? (Y or N):
    Enter a value:

    I can get around this by dealing with the return character.
    scanf("%c", &answer);
    to
    scanf("%c %c", &answer, &something_else);

    I know you have to deal with the carriage return in c++ but I don't remember having to do this in the past with c. Is this a new C99 requirement? I ask because this example is from a 2006 book Apress Beginning C from Novice to Professional (4th Edition Oct 2006). ie, code block is:

    Code:
    int main(void)
    {
      char answer = 'N';      /* user to say yes to no to keep looping */
      double total = 0.0;     /* keep a running total of numbers */
      double value = 0.0;     /* values enter by user */
      int count = 0;          /* keep a running count of total entries */
    
      printf("\nThis program calculates the average of any number of values.");
    
      for( ;; )               /* indefinite loop */
      {
        printf("\nEnter a value: ");
        scanf("%lf", &value);
        total += value;
        ++count;
    
        /* check if user has any more numbers */
        printf("\nDo you want to enter another value? (Y or N): ");
        scanf("%c", &answer);
    
        if(tolower(answer) == 'n')
          break;              /* exit loop if answer is no */
      }
    
      /* output the average to 2 decimal places */
      printf("\nThe average is %.2lf\n", total/count);
      return 0;
    }

  2. #2
    Registered User hamsteroid's Avatar
    Join Date
    Mar 2007
    Location
    Waterford, Ireland
    Posts
    62
    Think I found my bug... if I change

    scanf("%c", &answer);
    to
    scanf(" %c", &answer);
    It handles the carriage return correctly (ie does not use it for the next input).

    Whereas if I leave
    scanf("%c", &answer);

    What happens it uses the carriage return for the next input. Hmmm. How does the trailing space before the scanf %c conversion specifier handle that?

  3. #3
    Lean Mean Coding Machine KONI's Avatar
    Join Date
    Mar 2007
    Location
    Luxembourg, Europe
    Posts
    444
    scanf() only reads a number and stops at the first character not conform to the number format. Imagine the following situation in the in-stream:

    "<a number>\n";

    If you apply scanf("&#37;d") on that stream, you will have the following situation:

    "\n";

    so the next time you'll use scanf("%c"), it will use the remaining "\n" in the stream to immediately read a character. I suggest you read this FAQ entry that'll answer all your questions.

  4. #4
    Registered User hamsteroid's Avatar
    Join Date
    Mar 2007
    Location
    Waterford, Ireland
    Posts
    62
    Thanks Koni - I'll check that out now. Felt spooked there for a sec since I have been using scanf in umpteen examples - but the issue now only showed up since I was in a loop which highlighted the case. Thanks again.

    edit: I had a read and that makes sense - and taking note of the fact that scanf returns the value entered parameters.

    For my simple example above - using " &#37;c" instead of "%c" is working *ok* at a basic level.
    Last edited by hamsteroid; 04-07-2007 at 04:10 AM. Reason: reading the info.

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    8
    You can fix this by placing a fflush(stdin); right befor each scanf statement

  6. #6
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Quote Originally Posted by Chernobyl View Post
    You can fix this by placing a fflush(stdin); right befor each scanf statement
    No. This is NOT guarenteed to work because it is not standard C. Doing this will compile most likely, but the behavior is undefined. On some systems, it will clear the input buffer. Check your compiler's documentation to see if it will support this, but only if you feel you have to do this.

    If you want a more portable way, you should keep reading from stdin char by char until either EOF or '\n' is reached.

  7. #7
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    Quote Originally Posted by Chernobyl View Post
    You can fix this by placing a fflush(stdin); right befor each scanf statement
    ouch... I think we let the void main(void) slide along with a lot of other things, but I sincerely hope that you don't make it a habit of dispensing so much misinformation...
    Why fflush(stdin) is wrong

  8. #8
    Registered User
    Join Date
    Apr 2007
    Posts
    8
    How about the old scanf("&#37;c %*c") trick

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Or even just forget about scanf altogether with all the hacky ways of trying to clean up the input stream and just use fgets() to read a whole line.

    Then use sscanf() (or something else) to scan the line of input from in memory, where it doesn't matter what 'tail' the input has.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User hamsteroid's Avatar
    Join Date
    Mar 2007
    Location
    Waterford, Ireland
    Posts
    62
    Wow! scanf is really the basic tool it says it is.. so many issues with it. For basic purposes as like the program above, I'll stick with the scanf(" %c") with the space. Works fine for learning purposes - when making something more serious... I'll come back and check on it. Interesting topic for such a crucial basic function. Maybe reading it in as a line and dealing with it, as Salem suggests, seems to promise best control over the situation. Interesting!

  11. #11
    Registered User
    Join Date
    Apr 2007
    Posts
    8
    gets(); would be fine to use in this situation id say.

  12. #12
    Lean Mean Coding Machine KONI's Avatar
    Join Date
    Mar 2007
    Location
    Luxembourg, Europe
    Posts
    444
    Only if you are aware of its potential dangers and have read why gets() is bad.

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > gets(); would be fine to use in this situation id say.
    Are your tutorials full of this crap as well?
    http://cboard.cprogramming.com/showthread.php?t=88218

    Because you're 0 for 2 in terms of good advice in this thread.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed