问题
I want to implement a simple code to print the error message when the type of input is not an integer.
Below is a sample code.
int num;
while (1) {
printf("Input the value of integer: ");
int result = scanf(" %d", &num);
if (result == 0) {
printf("ERROR-Not an integer.\n");
}
else if (num < 0) {
printf("ERROR- Not positive.\n");
}else{
break;
}
}
In this code, if the value is not the integer, "scanf" will ask the number.
However, this function did not break when the input is not the integer.
Maybe the problem is the value on the buffer. "fflush" would be solution,but I don't want to use it.
回答1:
The problem is you fail to empty-stdin
on the matching failure case. You are looking for integer input. If the user enters anything other than an integer, a matching failure occurs. When the matching failure occurs, character extraction from stdin
stops and the characters causing the matching failure are left in the input buffer (stdin
here) unread -- just waiting to bite you again if you attempt to read again without clearing stdin
first... If you are taking input in a loop -- well, you know what happens...
(honey... I tried to read an int
and it failed, and I kept trying and it kept failing - help??)
How to fix it?
Very simply, you must empty stdin
after a matching failure. You are doing much better than most -- you are checking the return, but you have one piece of the puzzle to add -- a simple function to empty_stdin()
when a matching failure occurs. A very portable and very simple way is to simply extract all characters until a newline or EOF
is encountered, e.g.:
void empty_stdin(void) {
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
Putting all the pieces together in your example, you could do:
#include <stdio.h>
void empty_stdin(void) {
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
int num;
while (1) {
printf("Input the value of integer: ");
int result = scanf(" %d", &num);
if (result == EOF) { /* handle ctrl+d (ctrl+z on win) */
printf (" user canceled input (manual EOF)\n");
break;
}
else if (result == 0) { /* matching failure */
printf("ERROR-Not an integer.\n");
empty_stdin(); /* remove offending characters */
}
else if (num < 0) {
printf ("ERROR- Not positive.\n");
}
else /* positive number enetered */
break;
}
return 0;
}
(@David Bowling has already explained in the comments that the leading space
in " %d"
is unnecessary as all numeric conversions consume leading whitespace)
Example Use/Output
$ ./bin/scanf_empty
Input the value of integer: foo
ERROR-Not an integer.
Input the value of integer: -1
ERROR- Not positive.
Input the value of integer: bar
ERROR-Not an integer.
Input the value of integer: 1
Testing manual EOF
case (user presses Ctrl+d (or Ctrl+z windows)
$ ./bin/scanf_empty
Input the value of integer: user canceled input (manual EOF)
Look things over and let me know if you have further questions.
回答2:
#include <stdio.h>
int main()
{
int num;
int result;
while (printf("Please input an unsigned integer: "),
(result = scanf(" %d", &num)) != 1 || num < 0 )
{ // ║ ╚══ was successful but negative
if (result != 1) // <════════════╝ 1 conversion was requested
fputs("ERROR: Not an integer.\n", stderr); // write error messages
else fputs("ERROR: Not positive.\n", stderr); // to stderr
int ch; // the following loop *) reads garbage that might be left in stdin
while ((ch = getchar()) != '\n' && ch != EOF); // so the next scanf() won't
} // fail because of it.
printf("You entered: %d\n", num);
}
*) Plan-B:
scanf("%*[^\n]"); // this scanset matches all characters except newline
getchar(); // remove the newline
*) Plan-C:
scanf("%*[^\n]"); // this scanset matches all characters except newline
scanf("%*c"); // remove the newline
Sample Dialog:
Please input an unsigned integer: foo
ERROR: Not an integer.
Please input an unsigned integer: bar
ERROR: Not an integer.
Please input an unsigned integer: -75
ERROR: Not positive.
Please input an unsigned integer: 42
You entered: 42
回答3:
You need to clear stdin before/after every scanf. I personally prefer before.
fseek(stdin, 0, SEEK_END);
int num;
while (1) {
fseek(stdin, 0, SEEK_END);
printf("Input the value of integer: ");
int result = scanf_s(" %d", &num);
if (result == 0) {
printf("ERROR-Not an integer.\n");
}
else if (num < 0) {
printf("ERROR- Not positive.\n");
}
else {
break;
}
}
来源:https://stackoverflow.com/questions/53474700/c-scanf-did-not-stop-in-infinite-while-loop