Does fgets function skip user input?

When I use the fgets function, the program skips user input by executing the rest of the program. An example program with this effect:

 #include <stdio.h> int main() { char firstDigit[2]; char secondDigit[2]; printf("Enter your first digit: "); fgets(firstDigit, 1, stdin); printf("\nEnter your second digit: "); fgets(secondDigit, 1, stdin); printf("\n\nYour first digit is %s and your second digit is %s.\n", firstDigit, secondDigit); } 

Then I thought that maybe the problem is that fgets might write a new line, so I changed the code for the account for this:

 #include <stdio.h> int main() { char firstDigit[3]; char secondDigit[3]; printf("Enter your first digit: "); fgets(firstDigit, 2, stdin); printf("\nEnter your second digit: "); fgets(secondDigit, 2, stdin); printf("\n\nYour first digit is %c and your second digit is %c.\n", firstDigit[0], secondDigit[0]); } 

This time, the first input is working correctly, but the second input is skipped.

What am I doing wrong?

+5
source share
3 answers

char firstDigit[2] and char secondDigit[2] not large enough to contain a digit, a newline, and a null terminator:

 char firstDigit[3]; char secondDigit[3]; 

Then fgets() calls should indicate the size of the buffer arrays:

 fgets(firstDigit, sizeof firstDigit, stdin); /* ... */ fgets(secondDigit, sizeof secondDigit, stdin); 

If fgets(firstDigit, 2, stdin); used instead fgets(firstDigit, 2, stdin); , fgets() stores a maximum of two characters, including the \0 character, in firstDigit[] . This means that the \n character is still in the input stream, and this interferes with the second call to fgets() .

In response to an OP comment How do I remove unread characters from an input stream? A good start would be to use more generous selections for firstDigit[] and secondDigit[] . For example, char firstDigit[100] or even char firstDigit[1000] will be large enough for any expected input to be received using fgets() without leaving characters in the input stream. To be more sure that the input stream is empty, the portable solution should use an idiomatic loop:

 int c; while ((c = getchar()) != '\n' && c != EOF) { continue; } 

Note that you need to check for EOF , since getchar() can return this value if the user signals the end of the file from the keyboard or if stdin was redirected or in the unlikely event of an input error. But also note that this loop should only be used if there is at least the \n character in the input stream. Before attempting to clear the input stream using this method, the input buffer must be checked for a new line; if it is present in the buffer, the input stream is empty and the loop should not be executed. In the code below, strchr() used to check for a newline character. This function returns a null pointer if the character to be found is not found in the input string.

 #include <stdio.h> #include <string.h> // for strchr() int main(void) { char firstDigit[3]; // more generous allocations would also be good char secondDigit[3]; // eg, char firstDigit[1000]; printf("Enter your first digit: "); fgets(firstDigit, sizeof firstDigit, stdin); /* Clear input stream if not empty */ if (strchr(firstDigit, '\n') == NULL) { int c; while ((c = getchar()) != '\n' && c != EOF) { continue; } } putchar('\n'); printf("Enter your second digit: "); fgets(secondDigit, sizeof secondDigit, stdin); /* Clear input stream if not empty */ if (strchr(secondDigit, '\n') == NULL) { int c; while ((c = getchar()) != '\n' && c != EOF) { continue; } } puts("\n"); printf("Your first digit is %c and your second digit is %c.\n", firstDigit[0], secondDigit[0]); return 0; } 

Even better, use a single buffer[] to hold input lines, and then to store individual characters in char s. You can also write a function to clear the input stream, instead of rewriting the same loop every time you need it:

 #include <stdio.h> #include <string.h> // for strchr() void clear_stdin(void); int main(void) { char buffer[1000]; char firstDigit; char secondDigit; printf("Enter your first digit: "); fgets(buffer, sizeof buffer, stdin); firstDigit = buffer[0]; /* Clear input stream if not empty */ if (strchr(buffer, '\n') == NULL) { clear_stdin(); } putchar('\n'); printf("Enter your second digit: "); fgets(buffer, sizeof buffer, stdin); secondDigit = buffer[0]; /* Clear input stream if not empty */ if (strchr(buffer, '\n') == NULL) { clear_stdin(); } puts("\n"); printf("Your first digit is %c and your second digit is %c.\n", firstDigit, secondDigit); return 0; } void clear_stdin(void) { int c; while ((c = getchar()) != '\n' && c != EOF) { continue; } } 
+3
source

In the first case, fgets(firstDigit, 1, stdin); cannot read anything from the input, because the buffer is only 1 byte in size, and fgets() must store a null terminator at the destination.

In the second case: fgets(firstDigit, 2, stdin); reads 1 byte from stdin , the digit you typed, and cannot read the new line, because the target array is already full, which allows you to use a null terminator. The second fgets() reads the pending new line from the first record and returns immediately for the same reason, not allowing you to enter a second input.

You must allow fgets() to read at least 2 bytes, specifying a buffer size of at least 3:

 #include <stdio.h> int main(void) { char firstDigit[3]; char secondDigit[3]; printf("Enter your first digit: "); if (!fgets(firstDigit, sizeof firstDigit, stdin)) return 1; printf("\nEnter your second digit: "); if (!fgets(secondDigit, sizeof secondDigit, stdin)) return 1; printf("\n\nYour first digit is %s and your second digit is %s.\n", firstDigit, secondDigit); return 0; } 

Please note that if you enter more than one character before the enter key, the program will still behave in an unpredictable way.

+2
source

This is a buffer problem. When you press enter, you don’t know why it is stored in the stdin buffer. After executing fgets(...) you should enter fflush(stdin); under all circumstances.

Something like that:

 printf("Enter your first digit: "); fgets(firstDigit, 1, stdin); fflush(stdin); 
0
source

Source: https://habr.com/ru/post/1270803/


All Articles