“12345678987654321” is generally too large for an int
, and atoi
does not provide error detection.
You can use the strto…
functions to convert a numeral in a string to an integer type. Below is an example using strtoimax
, for the widest signed integer type a C implementation supports. There are also versions for other types, such as strtoll
for long long
.
The strto…
functions provide error checking, so you can detect when a number is too large and report it to the user or otherwise handle it.
#include <ctype.h> // For isdigit and isspace.
#include <errno.h> // For errno.
#include <inttypes.h> // For stroimax and PRIdMAX.
#include <stdint.h> // For intmax_t.
#include <stdio.h> // For printf, fprintf, getchar, and ungetc.
#include <stdlib.h> // For exit.
int main(void)
{
// Read string.
char string[20];
int n = 0; // Number of characters read so far.
while (1)
{
int c = getchar();
// When we see the end of the input stream, leave the loop.
if (c == EOF)
break;
/* When we see a white-space character (including new-line), put it
back into the stream and leave the loop.
*/
if (isspace(c))
{
ungetc(c, stdin);
break;
}
/* If we see character that is not a space or a digit, complain, unless
it is the first character and is a sign, "+" or "-".
*/
if (!isdigit(c) && !(n == 0 && (c == '+' || c == '-')))
{
fprintf(stderr, "Error, non-digit seen: \"%c\".\n", c);
exit(EXIT_FAILURE);
}
// Record the digit.
string[n++] = c;
if (sizeof string / sizeof *string <= n)
{
fprintf(stderr, "Error, too many digits, can handle only %zu.\n",
sizeof string / sizeof *string - 1);
/* ("sizeof *string" is one for ordinary "char" arrays, but
using it allows changing to wide character types if
desired.)
*/
exit(EXIT_FAILURE);
}
};
// Finish string with a null character.
string[n] = '\0';
// Attempt to convert string to an intmax_t.
char *end;
errno = 0; // Initialize error indicator.
intmax_t number = strtoimax(string, &end, 0);
/* Test whether the string failed to match the form for a numeral, because
it was empty or was just a sign with no digits.
*/
if (end == string)
{
fprintf(stderr, "Error, numeral has no digits.\n");
exit(EXIT_FAILURE);
}
// Check for error.
if (errno != 0)
{
fprintf(stderr, "Error, number is too large for intmax_t.\n");
exit(EXIT_FAILURE);
}
/* Test whether the whole string was used in the conversion. It should have
been, considering we ensured each character was a digit, but a check
like this can be useful in other situations, where we are parsing a
numeral from a more general string.
*/
if (*end != 0)
{
fprintf(stderr, "Error, unexpected character in numeral, \"%c\".\n",
*end);
exit(EXIT_FAILURE);
}
// Print the number.
printf("The number is %" PRIdMAX ".\n", number);
}