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.