how to properly flush the input stream (stdin)

jephthah 0 Tallied Votes 6K Views Share

too many new and intermediate users of C attempt to use the command fflush(stdin) to "flush the input buffer". this is patently wrong.

the rule is (and click if you don't believe me) : NEVER "FFLUSH()" ON INPUT SUCH AS "STDIN"

here is one method of properly flushing extra (and unwanted) characters from the stdin input stream. the code is written as a macro, and requires a character array to collect excess (junk) input. the macro will also ensure the newline character is stripped.

the intended use is in conjunction with fgets. for example:

char userInput[8]; // change array size to any arbitrary value

    printf("input a string and hit <enter>.  A maximum of %d characters will be recorded.\n",sizeof(userInput)-1);

    fgets(userInput,sizeof(userInput),stdin);
    FLUSH_STDIN(userInput);    // strip newline, flush extra chars

    printf("the first %d characters are \"%s\", any others have been discarded.\n",strlen(userInput),userInput);
#define FLUSH_STDIN(x) {if(x[strlen(x)-1]!='\n'){do fgets(Junk,16,stdin);while(Junk[strlen(Junk)-1]!='\n');}else x[strlen(x)-1]='\0';}

char Junk[16]; // buffer for discarding excessive user input, 
               // used by "FLUSH_STDIN" macro

Dani AI

Generated

The C standard does not define any effect for fflush on an input stream; portable code must not use fflush(stdin). See the standard library semantics summarized at cppreference: fflush. Some implementations historically add a non-standard behavior (notably MSVC), but Microsoft documents that using fflush on input is not portable and should be avoided (Microsoft: fflush).

Robust programs should not silently discard unread input. As deceptikon noted, the newline that fgets preserves is useful: it tells you whether you consumed an entire line. If you did not, you can read and append more or decide that the line is too long and handle it as an error. A simple, portable approach is to read whole lines and then parse:

#include <stdio.h>
#include <stdlib.h>

char *line = NULL;
size_t cap = 0;
ssize_t n = getline(&line, &cap, stdin);  /* POSIX */
if (n < 0) { /* EOF or error */ }
else {
    if (n && line[n-1] == '\n') line[n-1] = '\0';  /* drop newline */
    /* process line or parse with strtol/strtod, etc. */
}
free(line);

If you cannot use getline, loop with fgets into a growing buffer until you see a newline or EOF. For terminals on POSIX where you truly need to discard pending typed characters at the device level (not stdio), use tcflush() on the file descriptor, not fflush on stdin (man7: tcflush).

jephthah 1,888 Posting Maven

wow, dude, this snippet rocks! A+++ would read again!

William Hemsworth 1,339 Posting Virtuoso

Rofl :]

Adak 419 Nearly a Posting Virtuoso

It's good. ;)

The one I like moves the stream pointer for the keyboard - very elegant, but everybody asks WTF is THAT?

smoothment 0 Newbie Poster

That is a fantastic solution, you are my hero :)))

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

That is a fantastic solution

Eh, I'm not a fan of it. It's tied heavily to fgets, requires a special buffer that can easily cause name conflicts, lacks flexibility in where it can be called, and ignores error handling. It's inefficient in general, and most importantly, neglects that the newline handling of fgets is there for a reason. Instead of calling characters beyond the length of your buffer "junk" and throwing them away, robust code will at best allow them somehow and at worst gracefully refrain from actively deleting data.

David_50 13 Junior Poster in Training

Now, if stdin is a pipe or such, a read() too big will stall, so many apps read() one byte at a time to get earlier access to input.

David_50 13 Junior Poster in Training

For C I/O in a line oriented text milieu, fgets() is fine: returns null on error or EOF, is supported by ferror(), perror(), feof() (not necessary, as if a null return is not an error, it is EOF). The only caveat is that you need a long line detection, which can simply be that if the last byte of your buffer is set to null and the prior byte is not a linefeed, your buffer was too short for the line, and you have just the first part of the line. How you handle that is policy: ignore, error out or realloc() a bigger buffer and fgets() on top of the trailing null byte for additional space plus 1.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.