If you are using the function strtoul
for converting the string input to an integer, then you don't need to determine yourself whether the input is larger than ULONG_MAX
. The function strtoul
will report this, by setting the value of errno
accordingly. However, depending on the platform, an unsigned long
may be able to represent more numbers than an unsigned int
. Therefore, after the function strtoul
reports that the input range is ok, you should additionally verify that the number is not larger than UINT_MAX
.
Another problem with using the function strtoul
is that it will accept negative numbers as valid. We must therefore check ourselves whether the first non-whitespace character is a minus sign.
Here is an example program which uses a function get_unsigned_int_from_user
which will continue prompting the user for input, until the input is valid and in the range of an unsigned int
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
unsigned int get_unsigned_int_from_user( const char *prompt )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p, *q;
unsigned long ul;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//make "p" point to first non-whitespace character
for ( p = buffer; isspace( (unsigned char)*p ); p++ )
;
//since the function "strtoul" accepts negative
//input as valid input, which we don't want, we must
//first check ourselves whether the input starts
//with a minus sign
if ( *p == '-' )
{
printf( "number must not be negative!\n" );
continue;
}
//attempt to convert string to number
errno = 0;
ul = strtoul( p, &q, 10 );
if ( q == p )
{
printf( "error converting string to number\n" );
continue;
}
//make sure that number is representable as an "unsigned int"
if ( errno == ERANGE || ul > UINT_MAX )
{
printf( "number out of range error\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfh4q" gets rejected
for ( ; *q != '\0'; q++ )
{
if ( !isspace( (unsigned char)*q ) )
{
printf( "unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return ul;
continue_outer_loop:
continue;
}
}
int main( void )
{
unsigned int num;
num = get_unsigned_int_from_user( "Please enter a number: " );
printf( "Input is valid, you entered: %u\n", num );
}
This program has the following behavior:
Please enter a number: -1
number must not be negative!
Please enter a number: -5000000000
number must not be negative!
Please enter a number: 5000000000
number out of range error
Please enter a number: 4000000000
Input is valid, you entered: 4000000000
The program behaves this way because UINT_MAX
has the value 4294967295
on most common platforms.
The function get_unsigned_int_from_user
is a modified version of my function get_int_from_user
from this answer of mine. See that answer for further information on how that function works.