I'm using a function called checkType to check whether the user has entered a valid input of integer type. For example, if the user enters 15 it will print valid and 15c will print not valid. However, if the user enters a string input only like ccccc, it results in an infinite loop and the program crashes. I have added some screenshots below to show the outputs.
int checkType(int input, char *c) {
if (input == 2 and *c == '\n') {
return 1;
} else {
return 0;
};
}
int main(void) {
int faces = 0;
char c;
int valid = 0;
int input;
while (valid == 0) {
printf("Enter number of faces: ");
input = scanf("%d%c", &faces, &c);
valid = checkType(input, &c);
printf(valid == 0 ? "not valid\n" : "valid\n");
}
}
Infinite Loop:
The reason is scanf reads directly from the standard input and which blocks and waits for user input after it has processed the line. What you need to do is read the line and process that line in your while loop. I've modified your code below.
The problem with scanf () is that when the conversion fails it will not consume the content of the input buffer... For example... ? ... will go into an infinite loop if you type the letter A and hit enter. Frankly I see this as a terrible flaw in C's input functions, they should ALWAYS wait, no matter what... others will have varying opinions.
If the user enters several letters, the getchar () will remove only one char, per loop, but the program will not crash. So when I see scanf ()'s used in a loop, without such guards in place, and the program is looping until it crashes - it's the first thing that crosses my mind.
If you use scanf (), it will always leave a newline char behind, in the input stream. Scanf () can ignore it, if the input is the wrong size, but sometimes it will goof up, and accept the newline, as your entry. Especially if the scanf () is for a type char - then it will always seem to "skip" the entry, and go on. ?
The scanf()
family of functions is not really made for input of questionable syntax.
The usual approach to solve your problem is to read in all the input in a way which is sure to succeed, e.g. by reading a complete line (instead of a number, word-like string, or anything else with expected format) with fgets()
.
Then you can try to parse that line-representing string as by expected format. (You can use sscanf()
for the parsing attempt.) If that fails you ignore it and read the next line, or try parsing according to an alternative allowed format for the same input.
The relevant difference is that reading a whole line will succeed and remove it from the input stream. In contrast to that, your code, in case of syntax failure, leaves in the input stream whatever did not match the expected syntax. As such it will, of course, fail the next iteration of the reading loop again. That is what causes your endless loop.
In detail:
fgets()
and the option to restrict the number of characters to the size of the bufferscanf()
sscanf()
and with a check of the return valuesscanf()
again,However, if the user enters a string input only like ccccc,
it results in an infinite loop and the program crashes
Reason : scanf
returns the number of valid read values from stdin
. If we give cccc
as input, scanf
cannot read the value, because the input and variable faces
are of different data type. This makes input = 0
. So the function checkType
returns 0, which in turn makes valid = 0
. This makes while(valid == 0)
always true and hence the endless loop.
Scanf will read form stdin, and not clean the stdin buffer if not match. So it will read wrong data again in your case, you can just add a clean function with stdin after scanf, like: __fpurge(stdin)
You can refer to the following two links:
https://man7.org/linux/man-pages/man3/scanf.3.html
http://c-faq.com/stdio/stdinflush2.html
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