Search code examples
cwhile-loopgetchar

why the getchar() function does not loop?


I have read so many questions about getchar() and its behaviour, but still I don't understand this simple code..

    while (scanf("%d", &z) != 1)
  {
    while (getchar() != '\n');
    printf ("Try again: ");}

This code is to validate for characters.. From what I infer from this code is that if I input

Stackoverflow

Then the whole line is pushed to the buffer with the newline '\n' also.. Then the getchar() reads each character from the buffer and returns an integer, cleaning the buffer.. In this case the while loop should loop 12 times (number of characters in Stackoverflow) until it reaches the '\n' character.. but actually it just loops once and the output is

Try again:

means its out of loop and asking for scanf again.. It goes against my understanding of looping.. Maybe I misunderstood looping.. One additional question,, if getchar() returns integers then how it could be compared to characters like '\n'?


Solution

  • Reformatting the code to assist with my explanation:

    while (scanf("%d", &z) < 1) {
      int c; // for getchar()'s return value
      while ((c = getchar()) != EOF && c != '\n')
        ;
      printf ("Try again: ");
    }
    

    Note that scanf returns the number of items it read successfully. (I changed the outer while condition.)

    Edit: It is very important that getchar() be checked for EOF. The loop could spin forever otherwise.

    The inner while is followed by a semicolon. This means it does not have a loop body, i.e. does nothing except evaluate its condition until said condition is false.

    But what does the code do?

    Say I type in Stackoverflow. scanf sees %d in its format string, looks for an integer (any number of digits, optionally prefixed by a sign), finds nothing of the sort, and returns failure (i.e. 0) without changing z.

    Execution enters the loop, where getchar is called repeatedly until it finds a newline; this reads and discards all erroneous input. The program prints Try again: (no newline), and the outer loop then evaluates its condition again, trying to read an integer.

    Rinse and repeat until an integer is entered, at which point scanf stuffs it in z and the loop finishes.

    And what about comparing getchar() (int) to '\n' (char int)?

    In C, char is just a smaller int. C does not have a concept of characters separate from a concept of the integers that represent them. '\n' is an int, not a char, so no problems here. (It's for historical reasons - something to do with K&R C.)