There's additional work you have to do around the scanf
call.
First of all, scanf
will return the number of successful conversions and assignments - in this case, you would expect 1
on success. If there are no successful conversions and assignments, it will return 0
. If there's an error on input, it will return EOF
.
So, as a first pass, you'd do something like this:
if ( scanf( "%d", &n ) != 1 )
// input was not an integer or error on input
else
// successful input, do something with n
By itself, this is not enough.
%d
tells scanf
to skip over leading whitespace, then read up to the first non-digit character. If you enter "abc"
, then there are no valid digit characters, scanf
returns 0
, and n
is unmodified.
However, if you enter a string like "12c"
, then "12"
will be read and converted, n
will be assigned the value 12
, scanf
will return 1
, and 'c'
will be left in the input stream to foul up the next read. Ideally, you should reject that whole input.
There are a couple of ways around this. You can peek at the character immediately following your input - if it's whitespace, then the input was valid:
char dummy;
int items_read = scanf( "%d%c", &n, &dummy );
If items_read
is 2, that means scanf
read at least one decimal digit character followed by a non decimal digit character. If dummy
contains a whitespace character, that means the input was a valid integer. If dummy
contains a non-whitespace character, then the user fatfingered a nondigit character on input (meaning the value in n
shouldn't be trusted). Either way, we need to push that dummy character back onto the input stream before continuing.
If items_read
is 1, that means we read at least one decimal digit character followed by hitting EOF, so that means our input has to be a valid integer as well.
So, the test would look something like this:
if ( items_read == 2 && isspace( dummy ) || items_read == 1 )
{
// do something with n
if ( items_read == 2 )
ungetc( dummy, stdin );
}
else
{
// input was not an integer, or error on input
}
Alternately, you can read your input as a string, then use strtol
to do the conversion:
char input[MAX_INPUT_LENGTH+1];
if ( fgets( input, sizeof input, stdin ) ) // using fgets instead of scanf for this
{
char *chk; // stores address of first character *not* converted
long tmp = strtol( input, &chk, 0 ); // convert into a temporary
if ( isspace( *chk ) || *chk == 0 )
{
// input is good, assign tmp to n
if ( tmp <= INT_MAX && tmp >= INT_MIN )
n = tmp;
else
// input was within range for long but not int
}
else
// trailing non-digit character
}