4

I know that it is use to clean the keyboard buffer, but I don't understand when/why I need to use it or if I really need to.

For example, into this code that I made for my class, it only works if I put fflush(stdin) into the main function right after the while, and I only know this because the professor told me to do so after I had showed him the erro.

Does the problem have something related with the struct and thats why I should use fflush(stdin)?

Here is the code:

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

struct CLIENTES
{
    int ano_nasc, cpf[11];
    float renda_m;
    char nome[50];
}; //Lista de Objetos

int main(void) 
{
    //Declaracao de Variaveis
    int cont=0, num, num_2, client, i, j;
    CLIENTES *vet;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    scanf("%d%*c", &num);
    vet = (CLIENTES*)malloc(num*sizeof(*vet));
    printf("Digite os Dados do Cliente.");

    while (cont != num)
    {  
        fflush(stdin);
        printf("\nNome: ");
        fgets(vet[cont].nome, sizeof(vet[cont].nome), stdin);
        printf("\nAno de Nascimento: ");
        scanf("%d", &vet[cont].ano_nasc);
        printf("\nCPF: ");
        scanf("%d", &vet[cont].cpf);
        printf("\nRenda Mensal: ");
        scanf("%f", &vet[cont].renda_m);
        cont++;
    }

    printf("\nDigite o numero do cliente que voce deseja conferir: ");
    scanf("%d", &num_2);
    for (i=0;i<num;i++)
    {
        if(num_2 == num)
        {
            printf("\nO que deseja saber sobre ele?\n");
            printf("1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n\n\n");
            scanf("%d", &client);
            if (client == 1)
            {
                printf("Nome: %s", vet[(num_2)-1].nome );
            }
            else if(client == 2)
            {
                printf("Ano de Nascimento: %d", vet[num_2].ano_nasc );
            }
            else if(client == 3)
            {
                for(j=0;j<11;j++)
                {
                    printf("CPF: %d", vet[num_2].cpf[j]);
                }
            }
            else if(client == 4)
            {
                printf("Renda Mensal: %f", vet[num_2].renda_m );
            } 
        }
    }

    //Finalizando o Programa
    printf("\n\nFim do Programa!");
    getch();
    return 0;
} 
Gabriel
  • 763
  • 1
  • 10
  • 28
  • 5
    Doing `fflush(stdin)` is illegal in standard C library. The behavior is undefined. – AnT stands with Russia Jul 12 '15 at 22:53
  • 1
    @AnT omg, I really didn't know that, can you explain more about this concept? – Gabriel Jul 12 '15 at 22:56
  • 2
    @AnT: It does have undefined behavior, but it's not illegal. The behavior is [defined by POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/toc.htm). Still, using it here is probably not a good idea. You want to flush input in the sense of reading and discarding some data. – Keith Thompson Jul 12 '15 at 23:07
  • 3
    See [Using `fflush(stdin)`](http://stackoverflow.com/questions/2979209/using-fflushstdin) for a discussion of what it does. Since you're using ``, you are presumably working on Windows where the behaviour of `fflush(stdin)` is defined by Micorsoft. – Jonathan Leffler Jul 12 '15 at 23:16
  • @JonathanLeffler Thank you for the sugestion and the explanation. – Gabriel Jul 12 '15 at 23:23

2 Answers2

4

Actually the professor is wrong if speaking of standard C. According to the standard, calling fflush on an input stream (such as stdin) is undefined behaviour.

However, in many implementations (including Linux†, OS X, various BSDs, etc.) fflush(stdin) discards any input that has been buffered but not yet consumed. This non-standard feature is used in your program to clear the trailing newline left in the input buffer by the previous scanf.

man fflush on Linux is kind enough to mention that this is non-standard (although the wording doesn't quite suggest undefined behaviour):

The standards do not specify the behavior for input streams.

Meanwhile the C11 standard under 7.21.5.2 The fflush function says:

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.

† According to comments this non-standard behaviour may not work on Linux despite man fflush claiming that it should.

Arkku
  • 41,011
  • 10
  • 62
  • 84
  • This is interesting! So the propose of using fflush(stdin) into this program it is not the right thing to do, but it works pretty good to clean input buffer of the scanf, right? Should I use another thing instead of fflush(stdin)? Thank you. – Gabriel Jul 12 '15 at 23:03
  • 1
    @gm_fernandes `fflush(stdin)` is fine if you accept that the program is no longer standard C. You could implement your own function to “flush” the buffer, e.g., consume character by character until you hit something other than whitespace, then `ungetc` the last character. Or you could rethink the input altogether - `fgets` into a buffer and `sscanf` from that buffer is often preferable to using `scanf`, and here you would even do fine with `strtod` and `strtol` instead of `sscanf`. – Arkku Jul 12 '15 at 23:10
  • I really enjoyed your answer, it helped me a lot in terms of understanding the inside of my code and how this function works. Thank you for that! – Gabriel Jul 12 '15 at 23:17
  • 1
    Although `fflush(stdin)` doesn't crash or anything on Linux, it also doesn't clear the input like it does on DOS/Windows... – Dmitri Jul 12 '15 at 23:21
  • @Dmitri Interesting – on Debian jessie `man fflush` claims that `fflush`ing an input stream discards buffered but unconsumed data. – Arkku Jul 12 '15 at 23:22
  • Doesn't work on my current Ubuntu system, or any of the past ones I've tried... and a web search for `fflush(stdin) linux` shows result after result of people looking for alternatives or complaining that it doesn't work.. – Dmitri Jul 12 '15 at 23:24
  • @Dmitri fflush(stdin) doesn't clear the input in g++/Cygwin – M.M Jul 13 '15 at 00:57
0
  1. You should not use fflush(stdin) in a C program. It's not well-defined. It's not portable.

  2. You should not need to use fflush(stdin) in a C program. The only time this need comes up, sadly, is when progammers are learning C and using scanf a lot and getting bin by one of scanf's notoriousl difficulties. Simply put, stop using scanf and the "need" to flush input goes away. Or, insert extra calls to getchar, or loops that read and discard input up to a newline, as described elsewhere.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103