4
votes

I was writing some code and used fgets to get user input. And then i wrote a loop over my code to keep asking for user input until the user prints quit. But the second time it asked, it wrote "Please enter your input" 2 times instead of 1 , and didn't wait for my input the first time. So, i googled it and found that the stdin buffer was filled and it had to be cleared. I found this solution :

void dump_line(FILE * fp) {
    int ch;
    while ((ch = fgetc(fp)) != EOF && ch != '\n') {
        /* null body */;
    }
}

and then calling from the main function :

dump_line(stdin);

I have a very hard time understanding it. As i understand it, it simply assigns "ch" the value of fgetc(stdin) .. I simply cant understand how would assigning fgetc(stdin) to "ch" clear the buffer . Thank you very much for your help!

7
The buffer isn't filled. It just contains a line terminator that you hadn't read, and that the loop you posted reads.user207421

7 Answers

6
votes

Here is an old snippet I am using for user input if I really need to do it in pure C:

int get_line(char *buffer, int bsize)
{
    int ch, len;

    fgets(buffer, bsize, stdin);

    /* remove unwanted characters from the buffer */
    buffer[strcspn(buffer, "\r\n")] = '\0';

    len = strlen(buffer);

    /* clean input buffer if needed */
    if(len == bsize - 1)
        while ((ch = getchar()) != '\n' && ch != EOF);

    return len;
}

It retrieves bsize amount of letters from stdin and stores them into given buffer. stuff left in stdin input buffer will be cleaned automatically. It also removes newlines (\r and \n) from the input data.

Function returns the amount of characters sucessfully read.

2
votes

it simply assigns "ch" the value of fgetc(stdin)

Calling fgetc has the side effect that a character is read and removed from that file stream.

2
votes

Assigning fgetc(stdin) to ch is not what clears the buffer. It's the actual calling of fgetc(stdin) that does it. Each call (and thus, each iteration of the loop) eats a char from stdin.

How it works:

  1. Call fgetc(stdin), and assign the result to ch.
  2. If ch is not equal to either EOF or '\n', go to 1.

When the loop stops, one of two things will be true: Either you've just eaten the char that marks the end of the current line (read: you're at the next line now), or stdin is empty and you won't get any more input. (The latter is semi unusual in an interactive app, but common when people pipe stuff into your app from elsewhere. Be ready for it.)

0
votes

fgetc() gets a character from the buffer. This code reads characters from the buffer until the end-of-file or a new-line is reached.

0
votes

This is the same loop, but written differently, perhaps this will explain it:

void dump_line(FILE * fp) { /* dump a line from fp */
    int ch; /* temporary storage for character */

    while (1) {
        ch = fgetc(fp); /* read char from fp, this removes it from the stream */

        if (ch == EOF)  /* break if we reached END-OF-FILE */
            break;

        if (ch == '\n') /* break if we reached a newline, because */
            break;      /* we have succesfully read a line */
    }
}
0
votes

Another example for clearing the buffer:

char ch[1];
while(1){
    ch[0] = fgetc(stdin);
    if(ch[0] == '\n' || ch[0] == EOF) break;
}
-1
votes

Here's a two line solution I came up with, hope this helps someone.

char ch;
while ((ch = fgetc(stdin)) == EOF || ch == '\n');

The fgetc both reads and removes from the STDIN buffer. It will continue to do so until it reaches the EOF or newline, meaning STDIN is now empty.