Keyboard buffer cleaning after scanf

7

I'm having problems with the scanf(); function. When reading two or more values, subsequent values are not read.

I've already tried:

__fpurge(stdin);

After doing the readings, but in this case, I need to give an enter after each reading, which is a bit uncomfortable for me.

I've already tried it:

fflush(stdin);

But it does not solve (I'm using Debian 7.1, I think fflush(stdin); only works on Windows)

What solved the problem was:

#include <stdio.h>

//Limpa o buffer do teclado
void flush_in(){ 
    int ch;
    while( (ch = fgetc(stdin)) != EOF && ch != '\n' ){} 
}

int main(){
    char c;

    printf("\nEntre com um caractere: ");
    scanf("%c",&c);
    flush_in(); 
    printf("\nO caractere: \"%c\" tem o valor ASCII %d", c ,(int)c);

    printf("\nEntre com um caractere: ");  
    scanf("%c",&c);
    flush_in();  
    //__fpurge ( stdin );
    printf("\nO caractere: \"%c\" tem o valor ASCII %d", c ,(int)c);

    printf("\nPress any key to exit...\n\n"); 
    getchar();
    return 0;
}

But the code for the function flush_in() , I got here , it's obscure for me.

Then ...

  • Why does this problem occur?
  • How to work around this problem so that the same code works in Windows and Linux environments after being compiled?
  • What does the following code snippet do?

    void flush_in(){
        int ch;
        while( (ch = fgetc(stdin)) != EOF && ch != '\n' ){}
    }
    
  • asked by anonymous 15.03.2014 / 18:25

    5 answers

    10

    The problem is that when you type the following:

    A [enter]
    B [enter]

    The following input was inserted into the input buffer:

    A\nB\n
    

    When you run scanf("%c", &c) you read a single character from the buffer. In case it is A .

    \nB\n
    

    Notice that at no time has \n been consumed. In the next scanf("%c", &c) , it will be read. Then c = '\n' and the buffer is:

    B\n
    

    And here lies the error. The expected behavior was to have read A on the first and B on the second.

    The fix for this, however, is quite simple and does not need any additional function. Simply consume the line break! Use scanf("%c\n", &c) .

    As for what the flush_in function does, note:

    void flush_in() {
        int ch;
        do {
            ch = fgetc(stdin)
        } while (ch != EOF && ch != '\n');
    }
    

    It will repeatedly read the input buffer until it encounters a line break or until the buffer is gone. That is, it will consume the entire current line.

        
    15.03.2014 / 18:53
    3

    The best way to read user input is to use only fgets() to get data (do not mix with scanf() , getchar() , or other reading functions).

    Every time you make a fgets() you should check if a full line has been read (the last element of the read string is '\n' ) and if not, continue reading by increasing the buffer size or bypassing the extra characters.

    After the complete line has been retrieved (and the '\n' removed if you want) you should treat this line with sscanf() , strstr() , strtol() , strtod() , direct character access, ...

    #include <stdio.h>
    #include <string.h>
    
    int main(void) {
        char buffer[80];
    
        for (int k = 0; k < 2; k++) {
            printf("Entre com um caractere: ");
            fflush(stdout);
            fgets(buffer, sizeof buffer, stdin);
            if (buffer[strlen(buffer) - 1] != '\n') {
                // linha muito longa, ignorar o resto usando a parte final do buffer
                do {
                    fgets(buffer + 1, sizeof buffer - 1, stdin);
                } while (buffer[strlen(buffer) - 1] != '\n');
            }
            printf("O caractere: \"%c\" tem o valor ASCII %d\n", *buffer, *buffer);
        }
    
        printf("Press ENTER to exit...\n");
        do {
            fgets(buffer, sizeof buffer, stdin);
        } while (buffer[strlen(buffer) - 1] != '\n');
    
        return 0;
    }
    
        
    15.03.2014 / 20:17
    1

    You can use this code here which also works perfect:

    while ((c = getchar()) != '\n' && c != EOF) {}
    
        
    29.11.2017 / 13:11
    0

    As mentioned by Guilherme Bernal, whenever you read a character with scanf("%c", &x); we have this problem. A practical way to solve is to give a getchar() after reading, and:

    scanf("%c", &x);
    getchar();
    

    Still, the safest way to handle this kind of problem is with fgets (), as mentioned by @pmg.

        
    16.03.2014 / 03:03
    0
    #include <stdio.h>
    
    int main()
    {
       char c;
    
       printf("\nEntre com um caracter: ");
       scanf(" %c%*[^\n]",&c);
       printf("\nO caracter: \"%c\" tem o valor ASCII %d", c ,(int)c);
    
       printf("\nEntre com um caracter: ");
       scanf(" %c%*[^\n]",&c);
       printf("\nO caracter: \"%c\" tem o valor ASCII %d", c ,(int)c);
    
       printf("\nPress any key to exit...\n\n");
       getchar(); // consome '\n' deixado plo scanf
       getchar(); // aguarda ENTER do teclado
    }
    

    Explanation of scanf(" %c%*[^\n]",&c); :

  • whitespace (including '', '\ t' and '\' ')
  • reads an X character that is not whitespace
  • jumps all characters until you find a '\ n' (the '\ n' is in the buffer)
  • In the next% w / o of the '\ n' that was left in the buffer it will be consumed in step 1.

        
    12.10.2016 / 18:03