@steelhouse , you should always check the value returned by each scanf()
(see man 3 scanf
, but in your case, it’s okay 1) and correctly program error handling.
UPD
@steelhouse , as promised about scanf
.
This function tries to enter the ordered number of arguments (in accordance with the format) and returns the number of successfully read arguments or EOF (in the case of the end of the input stream (file)).
When reading a number, scanf
first skips delimiters (space, tabulation, new line character, etc.), and then converts the string of digits into a decimal number (of course, the + or - sign is allowed). As soon as a non-digit scanf
is encountered, it proceeds to read the next argument, but this “non-numeric” remains in the stream !!! .
That’s why your program loops. You read the numbers and if a letter is encountered (or another, unsuitable character in the format), it remains. The next scanf
tries to read it and leaves it in the stream, etc.
The solution is to analyze the number returned by scanf
. If it is less than expected (and not EOF (by EOF, you probably need to complete all input)), then you need to skip all the characters to a new line .
Here is a small example.
#include <stdio.h> #include <stdlib.h> // прочтем все символы до новой строки // вернем (для любопытных) их количество // или EOF (для анализа конца файла (это уже не пустое любопытство)) static int skip() { int c, n = 0; if (!feof(stdin)) // убедимся, что нужно читать while ((c = getchar()) != EOF) { n++; if (c == '\n') return n; } return EOF; } int main () { int a, b, i = 0, rc; while (rc != EOF) { printf ("Enter a,b: "); fflush(stdout); rc = scanf("%d%d",&a,&b); printf ("rc = %da = %db = %d\n", rc,a,b); #if ERRDEMO if (rc == 2) i = 0; else if (++i > 5) break; #else if (rc != EOF) if (rc != 2) { printf ("Input error rc = %d\n",rc); printf ("skip %d characters\nTry again ",rc = skip()); } #endif } exit (0); }
#if ERRDEMO
#else ...
#endif
it is (if you do not know yet) conditional compilation directives. Those. if you compile
gcc ac
then the code will be compiled between #else and #endif, and if
gcc -DERRDEMO ac
then the code is between #if and #else. Naturally, the code outside #if .... #endif is always compiled.
Now look at the results (and you can also collect it under Windows (gcc checked) and try different options)
avp@avp-xub11:~/hashcode$ gcc ac -DERRDEMO avp@avp-xub11:~/hashcode$ ./a.out Enter a,b: 1 2 rc = 2 a = 1 b = 2 Enter a,b: 3 a rc = 1 a = 3 b = 2 Enter a,b: rc = 0 a = 3 b = 2 Enter a,b: rc = 0 a = 3 b = 2 Enter a,b: rc = 0 a = 3 b = 2 Enter a,b: rc = 0 a = 3 b = 2 Enter a,b: rc = 0 a = 3 b = 2 avp@avp-xub11:~/hashcode$ gcc ac avp@avp-xub11:~/hashcode$ ./a.out Enter a,b: 1 2 rc = 2 a = 1 b = 2 Enter a,b: 3 a rc = 1 a = 3 b = 2 Input error rc = 1 skip 2 characters Try again Enter a,b: 3 4 rc = 2 a = 3 b = 4 Enter a,b: 5 6f rc = 2 a = 5 b = 6 Enter a,b: rc = 0 a = 5 b = 6 Input error rc = 0 skip 2 characters Try again Enter a,b: 5 6 rc = 2 a = 5 b = 6 Enter a,b: rc = -1 a = 5 b = 6 avp@avp-xub11:~/hashcode$
rc = -1 at the end, this is a seal for EOF (^ D in * nix, ^ Z in Windows).
Successes.
UPD 2
Slightly corrected skip()
to work more correctly when typing from the keyboard.