Gareth Lam
Gareth Lam

Reputation: 145

About the mechanism of using fgets() and stdin together

I would like to have a better understanding of using fgets() and stdin. The following is my code:

int main()
{
    char inputBuff[6];
    while(fgets(inputBuff, 6, stdin))
    {
        printf("%s", inputBuff);
    }
    return 0;
}

Let's say my input is aaaabbbb and I press Enter. By using a loopcount, I understand that actually the loop will run twice (including the one I input aaaabbbb) before my next input.

Loop 1: After I have typed in the characters, aaaabbbb\n will be stored in the buffer of stdin file stream. And fgets() is going to retrieve a specific number of data from the file stream and put them in inputBuff. In this case, it will retrieve 5 (6 - 1) characters at a time. So that when fgets() has already run once, inputBuff will store aaaab, and then be printed.

Loop 2: Then, since bbb\n are left in the file stream, fgets() will execute for the second time so that inputBuff contains bbb\n, and then be printed.

Loop 3: The program will ask for my input (the 2nd time) as the file stream has reached the end (EOF).

Question: It seems that fgets() will only ask for my keyboard input after stdin stream has no data left in buffer (EOF). I am just wondering why couldn't I use keyboard to input anything in loop 2, and fgets() just keep on retrieving 5 characters from stdin stream and left the excess data in the file stream for next time retrieval. Do I have any misunderstanding about stdin or fgets()? Thank you for your time!

Upvotes: 4

Views: 6808

Answers (3)

zebck
zebck

Reputation: 334

fgets() does only read until either '\n' or EOF. Everything after that will be left in stdin and therefore be read when you call fgets() again. You can however remove the excess chars from stdin by for example using getc() until you reach '\0'. You might want to look at the manpages for that.

Upvotes: 1

chqrlie
chqrlie

Reputation: 144740

The behavior of your program is somewhat more subtle than you expect:

fgets(inputBuff, 6, stdin) reads at most 5 bytes from stdin and stops reading when it gets a newline character, which is stored into the destination array.

Hence as you correctly diagnose, the first call reads the 5 bytes aaab and prints them and the second call reads 4 bytes bbb\n and prints them, then the third call gets an empty input stream and waits for user input.

The tricky part is how stdin gets input from the user, also known as console input.

Both console input and stdin are usually line buffered by default, so you can type a complete line of input regardless of the size of the buffer passed to fgets(). Yet if you can set stdin as unbuffered and console input as uncooked, the first fgets() would indeed read the first 5 bytes as soon as you type them.

Console input is an intricate subject. Here is an in depth article about its inner workings: https://www.linusakesson.net/programming/tty/

Upvotes: 1

Achal
Achal

Reputation: 11921

Everything is there in manual page of fgets() whatever you are asking. Just need to read it properly, It says

char *fgets(char *s, int size, FILE *stream);

fgets() reads in at most one less than sizecharacters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.

If input is aaaabbbb and in fgets() second argument you specified size as 6 i.e it will read one less 5 character and terminating \0 will be added so first time inputBuff holds aaaab and since still EOF or \n didn't occur so next time inputBuff holds bbb\n as new line also get stored at last.

Also you should check the return type of fgets() and check if \n occurs then break the loop. For e.g

char *ptr = NULL;

while( (ptr = fgets(inputBuff, 6, stdin))!= NULL){
          if(*ptr == '\n')
                   break;
          printf("%s", inputBuff);
}

Upvotes: 1

Related Questions