4
votes

What is the difference between using fflush(stdin) and flushstdin()? The only difference I know is that I need to write that void stuff before using flushstdin(), but I don't know why.

void flushstdin()
{
    int c;
    while((c = getchar()) != '\n' && c != EOF); 
}
int main () {
    float a, b, c;
    float s=0, ar1=0, ar2=0;
    printf("Inform value of side A");
    while(scanf("%f",&a) != 1 || a <= 0){ 
        printf("Invalid value.\n");
        flushstdin();
    }
}

and

int main(){
    float a,b,c,s=0;
    printf("Inform value of side A.");
    while(scanf("%f",&a) != 1 || a<=0){
        printf("Invalid value.\n");
        fflush(stdin);
    }
}

I'm a beginner! Which code is the best? Or they are equal?

3
What do you mean by I need to write that void stuff before using flushstdin()?R Sahu
@RSahu this: void flushstdin() { int c; while((c = getchar()) != '\n' && c != EOF);Rafael Moura
Ask the person who told you to "write that void stuff". You also should tell her that this "void stuff" is a function and that one does not "write" it (in context of files "to write something" has certain semantics), but define (and here also declare) and lateron call. He really should get the terms right, so others will actually understand what you're talking about.too honest for this site

3 Answers

1
votes

Both versions have problems.

As was already extensively documented, fflush(stdin) has undefined behaviour per the C Standard. The alternative using the flushstdin() function is not much better. I suggest reading standard input one line at a time and parsing that with sscanf(), all in a utility function that you can use as needed:

int readfloat(const char *prompt, float *val) {
    char buf[128];
    for (;;) {
        if (prompt) 
            fputs(prompt, stdout);
        if (!fgets(buf, sizeof(buf), stdin)) {
            printf("Premature end of file\n");
            return 1;
        }
        if (sscanf(buf, "%f", val) == 1 && *val > 0)
            return 0;
        printf("Invalid value.\n");
    }
}

int main(void) {
    float a, b, c, s = 0;
    if (readfloat("Enter value of side A: ", &a))
        return 1;
    ...
}
8
votes

Difference is that flushstdin is user defined and the only way in standard C to flush stdin.
fflush is a standard library function. fflush(stdin); will invoke undefined behavior.

c- faq: 12.26a:

fflush is defined only for output streams. Since its definition of "flush" is to complete the writing of buffered characters (not to discard them), discarding unread input would not be an analogous meaning for fflush on input streams.

c-faq: 12.26b:

There is no standard way to discard unread characters from a stdio input stream. Some vendors do implement fflush so that fflush(stdin) discards unread characters, although portable programs cannot depend on this. (Some versions of the stdio library implement fpurge or fabort calls which do the same thing, but these aren't standard, either.) Note, too, that flushing stdio input buffers is not necessarily sufficient: unread characters can also accumulate in other, OS-level input buffers. If you're trying to actively discard input (perhaps in anticipation of issuing an unexpected prompt to confirm a destructive action, for which an accidentally-typed "y" could be disastrous), you'll have to use a system-specific technique to detect the presence of typed-ahead input; see questions 19.1 and 19.2. Keep in mind that users can become frustrated if you discard input that happened to be typed too quickly.

2
votes

They are quite different. They can both "flush" input, but in different senses of that word.

fflush is a standard C function. Its behavior on input streams such as stdin is undefined -- meaning that the C standard does not define its behavior.

Some systems do define the behavior of fflush on an input stream. For example 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.

You can rely on fflush(stdin) to behave in accordance with this description if your program runs on a Linux-based system, or on another system that documents the same behavior. Your program's behavior will not be portable; on other systems, it might behave in arbitrarily bad ways. (Most likely if fflush(stdin) doesn't work, it will do nothing other than returning an error indication, but that's not guaranteed.)

Your own flushstdin function does something different from the Linux behavior of fflush(stdin). It reads and discards all input functions up to the first newline or until EOF (which is triggered either by end-of-file or by an error). It does this regardless of whether that input is buffered or not.

For example, suppose you type the chacters hello (without a newline), then your program calls fflush(stdin), and then you enter a newline.

fflush(stdin), given the Linux documented behavior, will discard the hello and return immediately, leaving the newline to be read by a later call. It "flushes" stdin in the sense that it discards all pending input, regardless of what it is.

Your flushstdin() function will read and discard the hello and then wait until you type Enter (or Ctrl-D), and then read and discard that. It reads and discards all input up to a newline or EOF, regardless of whether it was pending at the time of the call.

And again, the behavior of fflush(stdin) is not defined by the C standard, so using it makes your program non-portable (and your compiler will not necessarily warn you about that).

Incidentally, "that void stuff" is the definition of the flushstdin function. It's not needed for fflush because that's a standard C library function that's already defined for you.