This is a seemingly simple question that I have not been able to answer for far too long:
I am trying to read input from a user in a C program using fgets(). However, I am running into the problem that if the user enters more characters than fgets() is set to read, the next call to read a string from the user automatically reads the remaining characters in the stdin buffer, and this is NOT behavior I want.
I have tried many ways to clear the stdin stream, and while I know something like
while(getchar()!='\n');
will work, this requires the user to hit enter an additional time which is not something I want.
The structure of the code looks something like this:
void read_string(char *s, int width){
fgets(s,width,stdin);
clear_stdin();
.
.
}
while (1){
read_string()
.
.
}
But I cannot get a clear_stdin() function that works desirably. How on earth can I clear the stdin, without having the user needlessly need to hit enter twice?
To achieve what you want — reading and ignoring extra characters up to a newline if the buffer you supplied is over-filled — you need to conditionally read up to the newline, only doing so if there isn't a newline already in the input buffer that was read.
void read_string(char *s, int width)
{
if (fgets(s, width, stdin) != 0)
{
size_t length = strlen(s);
if (length > 0 && s[length-1] != '\n')
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
;
}
/* Use the input data */
}
else
/* Handle EOF or error */
}
The other part of the technique is to make sure that you use a big enough buffer that it is unlikely that anyone will overflow it. Think in terms of char buffer[4096]; as an opening bid; you can increase it if you prefer. That makes it unlikely that anyone will (be able to) type enough data on a single line to overflow the buffer you provide, thus avoiding the problem.
Another option is to use POSIX getline(). It reads a line into allocated space, allocating more space until the data fits (or you run out of memory). It has at least one other major advantage over fgets() — it reports the number of characters in the line it read, which means it is not confused by null bytes ('\0', usually typed as Control-@) in the input. By contrast, you can't tell whether there was any data entered after the first null byte with fgets(); you have to assume that the input stopped at the first null byte.
Note that the simple loop shown in the question (while (getchar() != '\n');) becomes infinite if it encounters EOF before reading a newline.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With