yad0
yad0

Reputation: 67

Clearing the buffer not working as expected?

I have the following code.

           int x1, x2;
           char check[3];
           do{
                //input should be (x1,x2)
                successfully_inputed = scanf("(%d,%d%2s", &x1, &x2, check);
                if(successfully_inputed == EOF)
                        break;
                if(check[1] || successfully_inputed != 3 || check[0] != ')'){
                        fprintf(stderr, "Invalid line");
                        
                        char ch;
                        while((ch = getchar()) != EOF && ch != '\n');

                        continue;
                }
                getchar(); // remove the new line character from buffer
          }while(1);

It does work for every input i give other than a particular one. When i give anything and then followed by the EOF, for example "asdEOF" then it consumes "asd" and when it reaches EOF it asks me for input, not the scanf() but the getchar(). Why is this happening and how can i solve it?

Upvotes: 1

Views: 106

Answers (1)

user9706
user9706

Reputation:

When the input is "asd<ctr-d>" scanf() fails so you need to swap the order of conditions to you check it first:

        if(successfully_inputed != 3 || check[1] || check[0] != ')'){

In either case we are correctly getting an "Invalid line". Then we try to flush the input stream (ensuring ch is int):

int ch;
while((ch = getchar()) != EOF && ch != '\n');

This result in getchar() reading the 'a' and 's' and 'd' then hanging waiting for input. This is because, on Linux, the ctrl-d only cause the terminal buffer to be flushed, and you need a 2nd ctrl-d on an empty stream to close it. This will then trigger EOF being returned by getchar().

Even if you switch to reading input with fgets() it will not return till you press ctrl-d twice on non-empty input buffer:

#include <stdio.h>
#define LINE_LEN 100
#define CHECK_LEN 3

int main() {
    for(;;) {
        char line[LINE_LEN];
        if(!fgets(line, LINE_LEN, stdin)) {
            if(feof(stdin)) break;
            // handle error
            return 1;
        }
        int x1;
        int x2;
        char check[CHECK_LEN];
        int rv = sscanf(line, "(%d,%d%2s", &x1, &x2, check);
        if(rv != 3 || check[1] || check[0] != ')') {
            fprintf(stderr, "\nInvalid line\n");
        }
    }
}

and example session:

$ ./a.out
asd<ctrl-d><ctrl-d>
Invalid line
$
$ ./a.out
<ctrl-d>
$

Upvotes: 2

Related Questions