I use this function quite a lot. Recently one of my friend told me it is not good to use fflush().
I googled it, and found that it gives some kind of unexpected behaviour. My question is when does this function works improperly and why?

Nowadays I use scanf("[^\n]") to flush input stream. Is this ok?

I've never used it to flush the input stream, but I have used it to flush the output stream. Say you want to produce output like:

Doing something... done!

Then I'd have code like this:

std::cout << "Doing something... ";
fflush( std::cout );

/* Some code that takes some time to do here */

std::cout << "done!" << std::endl;

If you don't have the fflush() part, then the whole message can appear in one go, since the output stream is free to flush when it feels it needs to, not after each call to operator<<. Since this isn't useful for seeing what's going on, I tend to flush the output stream. I think that this is a safe usage.

My question is when does this function works improperly and why?

Technically it works improperly when you call it with an input stream or an update stream in input mode. That is, if you use fopen() with a "w" mode, or a "+" mode and you're currently in the process of reading from the stream, or stdin.

In practice, all of the above situations are okie dokie iff the compiler supports them (and some do, including Borland and Microsoft compilers). In terms of best practice, fflush() on an input stream is frowned upon.

However, note that calling fflush() on an output stream is both well defined and recommended for things such as forcing a user prompt to display, well...promptly. :)

Nowadays I use scanf("[^\n]") to flush input stream. Is this ok?

Close. The correct call for scanf() to read up to a newline would be:

scanf("%*[^\n]");

This isn't complete though, because the newline will still be in the stream. You still need to extract it. One way would be to add an ignored character match in the format string:

scanf("%*[^\n]%*c");

This might not be as flexible though, if you want to do other stuff like count discarded characters. Another way would be to call getchar() after scanf():

scanf("%*[^\n]");
getchar();

Finally, there's the far more common (and faster!) method of calling getchar() in a loop. I'll even give you a function that you can call instead of having to write it ad hoc every time:

#include <stdio.h>

void clear_line(FILE *in)
{
    int ch;

    /* Do nothing if the stream is in an error state */
    if (ferror(in))
        return;

    /* Make sure any end-of-file  state is cleared */
    clearerr(in);

    /* Extract and discard up to a newline or end-of-file */
    do
        ch = getc(in);
    while (ch != '\n' && ch != EOF);

    /*
        Clear an end-of-file state if we stoped on EOF,
        but leave any legitimate error state for the caller
    */
    if (!ferror(in))
        clearerr(in);
}

Note that even this solution is incomplete when compared with what people expect from fflush(stdin) because it blocks for input when the stream is empty. fflush(), when flushing input streams is supported, will return without blocking on an empty stream. Unfortunately, there's no portable way to emulate that behavior, but it's fairly simple to just ensure that the stream is never empty when calling clear_line().

fflush( std::cout );

Yeah, that won't work. fflush() expects a pointer to FILE, not an std::ostream object. std::ostream has its own flush() member for synchronizing with the destination device.

It's also quite silly to flush cout explicitly prior to accepting input through cin because the two are tied together. As soon as you request input from cin, the tied stream (cout) is automatically flushed. Doing it yourself explicitly isn't harmful, but it is redundant.

It's actually a pretty nifty feature of the iostream library. Read more about it starting here.

Yeah, that won't work. fflush() expects a pointer to FILE, not an std::ostream object. std::ostream has its own flush() member for synchronizing with the destination device.

Sorry, I meant to do:

fflush( stdout );

Which does what I wanted it to do :) (I wasn't trying to use std::cin while doing this. I'll have a look a the link though, since I wasn't aware of the coupling you mentioned).

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.