By wrongusername


2010-06-05 04:50:23 8 Comments

So a quick Google search for fflush(stdin) for clearing the input buffer reveals numerous websites warning against using it. And yet that's exactly how my CS professor taught the class to do it.

How bad is using fflush(stdin)? Should I really abstain from using it, even though my professor is using it and it seems to work flawlessly?

4 comments

@tiftik 2010-06-05 05:10:38

According to the standard, fflush can only be used with output buffers, and obviously stdin isn't one. However, some standard C libraries provide the use of fflush(stdin) as an extension. In that case you can use it, but it will affect portability, so you will no longer be able to use any standards-compliant standard C library on earth and expect the same results.

@Ryan Chen 2018-05-18 03:08:36

Quote from POSIX:

For a stream open for reading, if the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be set to the file position of the stream, and any characters pushed back onto the stream by ungetc() or ungetwc() that have not subsequently been read from the stream shall be dis- carded (without further changing the file offset).

Note that terminal is not capable of seeking.

@Jonathan Leffler 2015-12-13 01:26:08

Converting comments into an answer — and extending them since the issue reappears periodically.

Standard C and POSIX leave fflush(stdin) as undefined behaviour

The POSIX, C and C++ standards for fflush() explicitly state that the behaviour is undefined, but none of them prevent a system from defining it.

ISO/IEC 9899:2011 — the C11 Standard — says:

§7.21.5.2 The fflush function

¶2 If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.

POSIX mostly defers to the C standard but it does mark this text as a C extension.

[CX] For a stream open for reading, if the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be set to the file position of the stream, and any characters pushed back onto the stream by ungetc() or ungetwc() that have not subsequently been read from the stream shall be discarded (without further changing the file offset).

Note that terminals are not capable of seeking; neither are pipes or sockets.

Microsoft defines the behaviour of fflush(stdin)

Microsoft and the Visual Studio runtime defines the define the behaviour of fflush() on an input stream.

If the stream is open for input, fflush clears the contents of the buffer.

M.M notes:

Cygwin is an example of a fairly common platform on which fflush(stdin) does not clear the input.

This is why this answer version of my comment notes 'Microsoft and the Visual Studio runtime' — if you use a non-Microsoft C runtime library, the behaviour you see depends on that library.

Linux documentation and practice seem to contradict each other

Surprisingly, Linux nominally documents the behaviour of fflush(stdin) too, and even defines it the same way (miracle of miracles).

For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application.

I remain a bit puzzled and surprised at the Linux documentation saying that fflush(stdin) will work. Despite that suggestion, it most usually does not work on Linux. I just checked the documentation on Ubuntu 14.04 LTS; it says what is quoted above, but empirically, it does not work — at least when the input stream is a non-seekable device such as a terminal.

demo-fflush.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c; enter some new data\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

Example output

$ ./demo-fflush
Alliteration
Got A; enter some new data
Got l
$

This output was obtained on both Ubuntu 14.04 LTS and Mac OS X 10.11.2. To my understanding, it contradicts what the Linux manual says. If the fflush(stdin) operation worked, I would have to type a new line of text to get information for the second getchar() to read.

Given what the POSIX standard says, maybe a better demonstration is needed, and the Linux documentation should be clarified.

demo-fflush2.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c\n", c);
        ungetc('B', stdin);
        ungetc('Z', stdin);
        if ((c = getchar()) == EOF)
        {
            fprintf(stderr, "Huh?!\n");
            return 1;
        }
        printf("Got %c after ungetc()\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

Example output

Note that /etc/passwd is a seekable file. On Ubuntu, the first line looks like:

root:x:0:0:root:/root:/bin/bash

On Mac OS X, the first 4 lines look like:

##
# User Database
# 
# Note that this file is consulted directly only when the system is running

In other words, there is commentary at the top of the Mac OS X /etc/passwd file. The non-comment lines conform to the normal layout, so the root entry is:

root:*:0:0:System Administrator:/var/root:/bin/sh

Ubuntu 14.04 LTS:

$ ./demo-fflush2 < /etc/passwd
Got r
Got Z after ungetc()
Got o
$ ./demo-fflush2
Allotrope
Got A
Got Z after ungetc()
Got B
$

Mac OS X 10.11.2:

$ ./demo-fflush2 < /etc/passwd
Got #
Got Z after ungetc()
Got B
$

The Mac OS X behaviour ignores (or at least seems to ignore) the fflush(stdin) (thus not following POSIX on this issue). The Linux behaviour corresponds to the documented POSIX behaviour, but the POSIX specification is far more careful in what it says — it specifies a file capable of seeking, but terminals, of course, do not support seeking. It is also much less useful than the Microsoft specification.

Summary

Microsoft documents the behaviour of fflush(stdin). Apparently, it works as documented on the Windows platform, using the native Windows compiler and C runtime support libraries.

Despite documentation to the contrary, it does not work on Linux when the standard input is a terminal, but it seems to follow the POSIX specification which is far more carefully worded. According to the C standard, the behaviour of fflush(stdin) is undefined. POSIX adds the qualifier 'unless the input file is seekable', which a terminal is not. The behaviour is not the same as Microsoft's.

Consequently, portable code does not use fflush(stdin). Code that is tied to Microsoft's platform may use it and it will work, but beware the portability issues.

POSIX way to discard unread terminal input from a file descriptor

The POSIX standard way to discard unread information from a terminal file descriptor (as opposed to a file stream like stdin) is illustrated at How can I flush unread data from a tty input queue on a Unix system. However, that is operating below the standard I/O library level.

@Eli Bendersky 2010-06-05 04:53:39

Simple: this is undefined behavior, since fflush is meant to be called on an output stream. This is an excerpt from the C standard:

int fflush(FILE *ostream);

ostream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.

So it's not a question of "how bad" this is. fflush(stdin) is plainly wrong, and you mustn't use it, ever.

@wrongusername 2010-06-05 04:56:36

Thank you! I wonder why the prof is using it then...

@BlueRaja - Danny Pflughoeft 2010-06-05 05:00:19

In his defense, knowing what is and isn't "undefined behavior" basically means having the whole C specification memorized... fflush(stdin) is actually a very common mistake.

@Eli Bendersky 2010-06-05 05:04:14

@BlueRaja: there's defense for a newbie mistake here, but no defense for a teacher propagating wrong knowledge! Any reference of fflush makes clear it's meant for output streams right in the first paragraph, you don't have to memorize the C standard for that!

@BlueRaja - Danny Pflughoeft 2010-06-05 05:06:17

@Eli: No one can know everything. The processor will never know his mistake until someone tells him... I used fflush(stdin) for years until I discovered it's UB (by accident)

@Anders 2010-06-05 05:07:01

I guess university professors are also human :-)

@Alex Budovski 2010-06-05 05:28:50

Err, shouldn't one normally consult the documentation for a function before they use it? Especially a professor?

@saadtaame 2012-09-16 16:00:27

@EliBendersky So it's safe to use it with output streams?!

@Eli Bendersky 2012-10-10 15:36:12

@saadtaame: yes

@Daniel Fischer 2012-10-29 20:23:39

Another point of defense would be the following part of the man page (various glibc versions on Linux): "For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application. The open status of the stream is unaffected." Although it's UB, some implementations seem to make guarantees without mentioning its status with respect to the standard.

@Victor Zamanian 2013-02-23 00:57:08

@DanielFischer: Under the "CONFORMING TO" section of the glibc man page: "The standards do not specify the behavior for input streams." That's a good section to read sometimes. :) So even glibc mentions that it's not standard behavior, and even that it is undefined. So it shouldn't be used in order to be standard-compliant/portable/what-have-you.

@Jonathan Leffler 2014-02-17 15:29:41

@VictorZamanian: it depends on what you mean by 'undefined behaviour'. On Linux, the manual defines the behaviour; using fflush(stdin) is defined behaviour on Linux. It is not defined according to the standards (so it does not conform to any standard-mandated behaviour in this instance), but it is defined by Linux (or, more accurately, by glibc).

@Victor Zamanian 2014-02-17 20:27:43

@JonathanLeffler I am of course referring to the standard, not implementation-defined behavior as Linux's and glibc's behaviors are.

@Rafael Lerm 2015-01-17 23:14:23

There's another aspect that I seldom see mentioned: fflush(stdin) is much worse than just implementation-defined behavior. Even if it did work as most people intend to, it would terrible. Imagine if stdin is not someone dumbly typing input, but came from another program or shell redirection: it would read the beginning of the file and then just erase the rest. It is really dumb to think that stdin is always something so slow as a human operator.

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] Best practices with STDIN in Ruby?

  • 2008-11-07 19:14:51
  • griflet
  • 180515 View
  • 297 Score
  • 9 Answer
  • Tags:   ruby stdin

21 Answered Questions

[SOLVED] How do you read from stdin?

  • 2009-09-20 05:48:07
  • tehryan
  • 1413735 View
  • 1341 Score
  • 21 Answer
  • Tags:   python stdin

2 Answered Questions

[SOLVED] fflush(stdin) ANSI C

  • 2012-07-22 22:43:05
  • Mahmoud Emam
  • 18713 View
  • 2 Score
  • 2 Answer
  • Tags:   c fflush

4 Answered Questions

[SOLVED] C| how to check if my input buffer(stdin) is empty?

  • 2016-04-05 13:41:06
  • G Eldar
  • 6687 View
  • 1 Score
  • 4 Answer
  • Tags:   c input buffer stdin

3 Answered Questions

[SOLVED] fflush(stdin) function does not work

  • 2012-02-03 01:29:14
  • Karen Langres Bague
  • 7061 View
  • 4 Score
  • 3 Answer
  • Tags:   c stdin fflush

3 Answered Questions

[SOLVED] Difference between fflush(stdin) and flushstdin()

  • 2015-06-05 20:13:25
  • Rafael Moura
  • 1505 View
  • 4 Score
  • 3 Answer
  • Tags:   c stdin fflush

2 Answered Questions

[SOLVED] c language scanf - fflush(stdin) - doesnt work

3 Answered Questions

[SOLVED] Illegal to use fflush() in stdin? What to do instead?

  • 2015-03-10 03:19:03
  • Xisso2
  • 328 View
  • 0 Score
  • 3 Answer
  • Tags:   c stdin fflush

1 Answered Questions

[SOLVED] fflush() function not working with stdin

  • 2014-10-19 01:23:10
  • harianja
  • 240 View
  • 1 Score
  • 1 Answer
  • Tags:   c stdin fflush

2 Answered Questions

[SOLVED] read() stdin in c?

  • 2012-03-07 22:21:36
  • Nick
  • 12881 View
  • 0 Score
  • 2 Answer
  • Tags:   c input stdin

Sponsored Content