If all you care about is validating that an arbitrarily long sequence of characters contains only decimal digits, then chux's answer is the right one.
However, based on your code, it looks like you don't just want to validate the string, you want to convert it to the corresponding integer value and save it. If that's the case, 50 digits is way beyond what you can store in any of the standard integer types1; you'd have to use a multi-precision library like GMP. The best you can do with native types is unsigned long long
, which on my platform can support values with up to 20 decimal digits (ULLONG_MAX == 18446744073709551615
).
Instead of using atoi
, you can use something from the strto*
family of functions. The neat thing about these functions is you can pass a pointer argument that will point to the first character in the string that wasn't converted - if that character isn't whitespace or the 0 terminator, then you know the input string isn't valid.
In this case we'll use strtoll
, which converts strings to long long
:
#define LLONG_DIGITS 19 // set this for whatever your platform supports;
// mine supports up to 19 for long long
char buf[LLONG_DIGITS+3] = {0}; // digits plus sign, newline, and terminator
long long val = 0;
if ( fgets( buf, sizeof buf, stdin ) )
{
/**
* Step 1. Check for a newline character. If one isn't present,
* then the input was too long for the buffer. Reject
* the input and clear out the input stream.
*/
char *newline = strchr( buf, '\n' );
if ( !newline )
{
fputs( "Input too long, rejecting\n", stderr );
while ( getchar() != '\n' )
; // empty loop
}
else
{
/**
* Step 2. Replace newline with terminator
*/
*newline = 0;
char *check;
/**
* Step 3. Use strtoll to convert the string to a long long.
* check will point to the first character in the string
* that was *not* converted - if this character isn't
* whitespace or the string terminator, then the input
* was not a valid integer string
*/
long long tmp = strtoll( buf, &check, 10 );
if ( check > buf && !isspace( *check ) && *check != 0 )
fputs( "Input value is empty or contains non-numeric characters!\n", stderr );
else
val = tmp;
}
}
else
{
fputs( "Error on input\n", stderr );
}
Now, when I say a type can support decimal values up to N digits, that doesn't mean it can support all N-digit values. An 8 bit byte can represent 256 distinct values, so it can represent some 3-digit decimals, but it can't represent things like 999
. LLONG_MAX
is 9223372036854775807
, so if you input a value higher than that you will have signed integer overflow, which invokes undefined behavior.
- 50 decimal digits corresponds to at least 160 bits; I'm not aware of any system with a native integer type that large. An
int
is only guaranteed to store values in the range [-32767..32767]
, which is at most 5 digits. Most platforms use 32-bit int
which can store values in the range [-2147483648..2147483647]
which is 10 digits. A 64-bit `unsigned long long` can store a value up to 18446744073709551615
which is 21 digits. No native type, not even long double
, is going to be able to handle 50 digits.