8

I have a difficulty understanding getchar(). In the following program getchar works as expected:

#include <stdio.h>


int main()
{
    printf("Type Enter to continue...");
    getchar();
    return 0; 
} 

However, in the following program, getchar does not create a delay and the program ends:

#include <stdio.h>

int main()
{
    char command[100];
    scanf("%s", command );
    printf("Type Enter to continue...");
    getchar();
    return 0; 
} 

I have the following weired workaround, which works, but I don't understand why:

#include <stdio.h>

int main()
{
    char command[100];
    int i;
    scanf("%s", command );
    printf("Type Enter to continue...");
    while ( getchar() != '\n') {
      i=0; 
    }
    getchar();
    return 0;    
}

So my questions are:
1. What is scanf doing? Why does scanf do this ?
2. Why is my work around working?
3. What is a good way to emulate the following Python code:

raw_input("Type Enter to continue")
oz123
  • 27,559
  • 27
  • 125
  • 187

5 Answers5

13

The input is only sent to the program after you typed a newline, but

scanf("%s", command );

leaves the newline in the input buffer, since the %s(1) format stops when the first whitespace character is encountered after some non-whitespace, getchar() then returns that newline immediately and doesn't need to wait for further input.

Your workaround works because it clears the newline from the input buffer before calling getchar() once more.

To emulate the behaviour, clear the input buffer before printing the message,

scanf("%s", command);
int c;
do {
    c = getchar();
}while(c != '\n' && c != EOF);
if (c == EOF) {
    // input stream ended, do something about it, exit perhaps
} else {
    printf("Type Enter to continue\n");
    getchar();
}

(1) Note that using %s in scanf is very unsafe, you should restrict the input to what your buffer can hold with a field-width, scanf("%99s", command) will read at most 99 (sizeof(command) - 1)) characters into command, leaving space for the 0-terminator.

Clifford
  • 88,407
  • 13
  • 85
  • 165
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
3

Whitespace is a delimiter for 5y3 %s format specifier, and newline is regarded as whitespace, so it remains buffered. Console input is normally line oriented, so a subsequent call to getchar() will return immediately because a 'line' remains buffered.

scanf("%s", command );
while( getchar() != '\n' ){ /* flush to end of input line */ }

Equally if you use getchar() or %c to get a single character you normally need to flush the line, but in this case the character entered may itself be a newline so you need a slightly different solution:

scanf("%c", ch );
while( ch != '\n' && getchar() != '\n' ){ /* flush to end of input line */ }

similarly for getchar():

ch = getchar();
while( ch != '\n' && getchar() != '\n' ){ /* flush to end of input line */ }

The sensible thing to do of course is to wrap these solutions into stand-alone specialised input functions that you can reuse and also use as a place to put common input validation and error checking code (as in Daniel Fischer's answer which sensibly checks for EOF - you would normally want to avoid having to duplicate those checks and error handling everywhere).

Clifford
  • 88,407
  • 13
  • 85
  • 165
2

I'd rather first use fgets and then use sscanf to parse the input. I have been doing this stuff like this for a long time and the behaviour has been more predictable than using plain scanf.

Pablo
  • 13,271
  • 4
  • 39
  • 59
-2

Well, I have something easier: add another getchar() ... problem solved!!

Pokechu22
  • 4,984
  • 9
  • 37
  • 62
  • that doesn't necessarily solve the problem, you still may have more than one byte in the buffer and `getchar()` will then return immediately. – Pablo Sep 25 '14 at 15:20
-4

after taking command input flush the stdin.

fflush(stdin);

but flushing a input stream results in undefined behavior (though Microsoft's C library defines the behaviour as an extension).

pmg
  • 106,608
  • 13
  • 126
  • 198
Debobroto Das
  • 834
  • 6
  • 16
  • 2
    fflush() is undefined for input streams. – Clifford Sep 29 '12 at 15:24
  • 1
    -1: applying `fflush()` to an input stream (or an input/output stream for which the last operation was input) is one of the few specific examples of Undefined Behavior specified by the [C Standard](http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1570.pdf). – pmg Sep 29 '12 at 15:25
  • Note that while this works with Microsoft's C library, it certainly does not with the GNU C library. Avoid. – Clifford Sep 29 '12 at 15:39
  • I have mentioned about the undefined behavior. – Debobroto Das Sep 29 '12 at 16:05
  • @DebobrotoDas: you *ninja-edited* your answer and the downvotes (at least mine) couldn't be revoked. I'll edit your answer and revoke my downvote in a second. – pmg Sep 29 '12 at 16:09
  • It was I who downvoted your answer. I did that before the answer had the information about Undefined Behavior. When I noticed you had changed it I couldn't revoke the downvote, but revoked it right after I edited your answer. Sorry for the confusion. – pmg Sep 29 '12 at 16:28
  • 1
    It remains bad advice IMO - "undefined" includes not actually doing anything at all. It may or may not deserve a down vote, but certainly not an up vote. – Clifford Sep 29 '12 at 17:55
  • `fflush(stdin);` is undefined and not a good habit. I recomend to first use `fgets` and then `sscanf`. It's much safer and predictable. – Pablo Sep 29 '12 at 19:07