4

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?

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • What do you mean by *I need to write that void stuff before using flushstdin()*? – R Sahu Jun 05 '15 at 20:21
  • @RSahu this: void flushstdin() { int c; while((c = getchar()) != '\n' && c != EOF); – Rafael Moura Jun 05 '15 at 20:25
  • 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 Jun 05 '15 at 20:40

3 Answers3

8

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.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • So I should not use fflush(stdin)?? – Rafael Moura Jun 05 '15 at 20:16
  • @RafaelMoura It is no longer a portable program. – BLUEPIXY Jun 05 '15 at 20:22
  • @BLUEPIXY what do you mean ? =( – Rafael Moura Jun 05 '15 at 20:23
  • 1
    @RafaelMoura There is no guarantee that the same behavior in others of the environment. – BLUEPIXY Jun 05 '15 at 20:24
  • Even where `fflush(stdin)` works, it "flushes" `stdin` in a different sense than the OP's `flushstdin` function. See my answer. – Keith Thompson Jun 05 '15 at 20:49
  • Note that some systems *do* define a behavior for `fflush( stdin )` that does what most people expect; that is, clear all data from the input stream. Apparently that was easier than convincing N-thousand programmers to *not do that*. However, that behavior should not be relied upon in general, and you should not use `fflush( stdin )` in your code. – John Bode Jun 05 '15 at 20:52
  • @JohnBode; I thought readers will go read the c-faq I linked for suggested reading. Now, added that too in my answer which include your point. – haccks Jun 05 '15 at 21:12
2

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.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • How could one type characters without newline? – haccks Jun 05 '15 at 21:04
  • @haccks: It depends if the terminal is in cooked or raw mode, and if `stdin` is line buffered or not... – chqrlie Jun 05 '15 at 21:11
  • @haccks: By typing some characters and not typing a newline. – Keith Thompson Jun 05 '15 at 21:53
  • @KeithThompson; Lol. Of course but how program will call `fflush(stdin)` without pressing Enter key? – haccks Jun 05 '15 at 21:56
  • @haccks: I think chqrlie's comment is correct. And even if `stdin` is line-buffered, the characters are still *buffered* and should be discarded by `fflush(stdin)` if it behaves as the Linux man page describes it. – Keith Thompson Jun 05 '15 at 21:59
  • 1
    @haccks: Or maybe not. Experiment shows that line-buffered characters are not flushed by `fflush(stdin)` on Linux. In fact I don't see `fflush(stdin)` having any effect at all; perhaps I'm doing something wrong. I have no plans to use it in real code, so perhaps I just won't worry about it. – Keith Thompson Jun 05 '15 at 23:44
  • Thanks for the clarification. I was a bit lost. – haccks Jun 05 '15 at 23:46
1

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;
    ...
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189