scanf() isn't all that easy to use properly and recover from invalid input.
I use a combination of fgets() and sscanf() to do a bulletproof scan of a single number for a single prompt. Something like this:
int GetInt(char *prompt, int *result)
{
... char ans[64];
... int len, nconverted, value;
... char extra;
... fputs(prompt, stdout);
... if (fgets(ans, sizeof ans, stdin) == NULL)
... ... return 0;
... len = strlen(ans);
... if (len == (sizeof ans - 1) && ans[len-1] != '\n')
... ... return 0;
... nconverted = sscanf(ans, " %d %c", &value, &extra);
... if (nconverted != 1)
... ... return 0;
... *result = value;
... return 1;
}
The arguments are a prompt string and a pointer to where to store the result.
The return value is a logical true (nonzero) if the number parsed correctly, or false (0) if there was any error. On an error return, no change was made to the (*result) value.
That was typed from memory, so there may be errors. The idea is to get the whole response line into a buffer, using fgets() -- NEVER use gets() ever ever ever -- to guard against too much input. If the buffer is full and doesn't end with a \n newline, then an error is returned. (You may have to increase the buffer size if you run on a 256-bit computer. :^)
Next, sscanf is used to scan from that response string. The format " %d %c" has four elements. The first space skips 0 or more spaces and/or tabs, the %d attempts to parse and convert an integer, the second space skips 0 or more spaces/tabs again, and finally--if there are any characters left--%c stores the first such character into (extra). That store into extra should never happen, and the return value from sscanf() tells how many fields were stored. If the return value is 1, then only the integer was stored. Any other value indicates an error. (0 values stored means that no number was found, 2 values stored means that a number was found, but it was followed by unwanted garbage.
Finally, only if all went well does the function actually store the parsed value into *result.
You can see why I make this a function. I don't want to be coding this at every input.
A really simple calling sequence might be:
while (!GetInt("Tell me your age: ", &age) || age < 1 )
{
... printf("That's not a good age!\n");
}
Put the GetInt function before main(), and you won't need a prototype. Otherwise, you'll need to add:
int GetInt(char *prompt, int *result);
...at the top of your file. You'll need #includes for
and up there, no matter what.
Edit: At least two errors. I coded "null" instead of "NULL" for the fgets() error test. Too much Java or not enough mocha java, I guess. Also, I misspelled "value" as "val" in two spots. This version should at least compile...