There are far more ways to incorrectly use scanf
in a loop that proper ones. The primary issue (aside from input or matching failures that are explained in the man page), is failing to empty the input buffer (stdin
when reading from a terminal) after a failed conversion. (There is also the issue that the user must enter something.) When a user enters text and presses [Enter]
a newline
('\n'
) is generated and placed in the input buffer to mark the end of line. When you enter a, 5.4, c
, 'a'
is fine, but 5.4
is not an int
and the processing fails:
If processing of a directive fails, no further input is read, and
scanf() returns.
When scanf
returns, it leaves the remaining characters in stdin
and you loop and attempt to read again. scanf
attempts to read what is left in stdin
, processing again fails, and the loop continues endlessly.
In this situation the only way to prevent the indefinite loop is to manually empty the input buffer after you call to scanf
. Something simple will do:
int c;
...
while (...) {
scanf (...)
while ((c = getchar()) != '\n' && c != EOF) {}
}
This will insure you start with an empty buffer on the next iteration. For example:
#include <stdio.h>
int main (void) {
int num1 ,num2, c;
char str;
while (printf ("\nEnter : ") &&
scanf (" %d, %d, %c%*c", &num1, &num2, &str) != 3) {
printf ("error: invalid input, required: 'int, int, char'\n");
/* empty remaining chars from input buffer */
while ((c = getchar()) != '\n' && c != EOF) {}
}
printf ("\n num1 : %d\n num2 : %d\n str : %c\n\n", num1, num2, str);
return 0;
}
Example Use
$./bin/scanf3
Enter : a
error: invalid input, required: 'int, int, char'
Enter : a, 5.4, c
error: invalid input, required: 'int, int, char'
Enter : 10, 25
error: invalid input, required: 'int, int, char'
Enter : 10, 25, a
num1 : 10
num2 : 25
str : a
note: this does not protect against the user entering nothing (just pressing [Enter]
) and the cursor just sitting there blinking as it waits for input. That is an inherent behavior of scanf
, part of which is the reason that line-oriented input methods (fgets
or getline
) are preferable when taking input.