Consider the code below. It uses the standard library function strtol() which has several important features for bullet-proof conversion of text strings to numeric values.
The prototype is:
long strtol(const char *s, char **end_ptr, int base);
Here are its features:
If the base argument is 10 the function expects to find a text representation of a number in ordinary decimal format.If the base argument is 0 the function examines the input string the same way the C compiler does when processing your source code. That is if the first two non-blank characters of the string are "0x" or "0X", it treats the rest of the string as hexadecimal and accepts the characters 'a' through 'f' and 'A' through 'F' as the corresponding hex digits. If the first non-blank character of the string is '0' and it is not followed by 'x' or 'X' but by more digits, the rest of the string is treated as octal.
If the base argument is 2, strtol() will process a string of '0' and '1' characters as represent a binary string, which is another common question.
If you specifically want hex or octal input, you can use a base argument of 16 or 8.
At this point, if the end_ptr parameter was not NULL, it sets the char pointer to point to the first character which isn't part of the number.
Testing end_ptr for equality to the original string tells you for sure whether you got a value of 0 because the user entered 0, or because the entered string is not numerical.
Testing errno if you get back LONG_MAX or LONG_MIN tells you whether the number exceeds the range of a signed long int, or whether that exact value was entered.
If the value you are inputting is intended to be placed in an integer type which might be smaller than a long (int, short, or signed char), then you merely test the result against the limits for that type. The tests do nothing if the smaller type happens to have the same size and representation on a particular compiler.
A sample program is below. Note that this sample program does not check to see that there are no non-numeric characters after the valid numeric characters that can be converted into a value. In some cases, this is the type of response that you want. In other cases you might want to do additional checking.
/* file usestrtol.c
*
* 22-Aug-2005
* © 1999-2005 by Jack Klein
* All rights reserved
*
* License granted for free non-commercial use
*
* Description:
*
* this program demonstrates the use of the standard
* library function strtol() prototpyed in <stdlib.h>
* to obtain and validate a signed integer value from the
* standard input stream
*
* C++ notes:
*
* On newer, ANSI/ISO Standard Conforming C++ compilers,
* the function strtol() is prototpyed in <cstdlib> and
* is in the std namespace
*
* The strtol() function operates with an array of constant
* characters as its source which could be read with the
* cin.getline() member function instead of the C library
* fgets() function
*
* It can even be called with the pointer returned by the
* c_str() member function for a std::string
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int main(void)
{
char buff [25];
char *end_ptr;
long long_var;
int int_var;
for ( ; ; )
{
printf("\nEnter an int, return only to quit: ");
fflush(stdout);
end_ptr = fgets(buff, sizeof buff, stdin);
if ((end_ptr == NULL) || (buff [0] == '\n'))
{
break;
}
errno = 0;
long_var = strtol(buff, &end_ptr, 0);
if (ERANGE == errno)
{
printf("Number out of range...\n"
"Too %s for signed long\n",
LONG_MAX == long_var ? "big" : "small");
}
else if (long_var > INT_MAX)
{
printf("%ld too large!\n", long_var);
}
else if (long_var < INT_MIN)
{
printf("%ld too small!\n", long_var);
}
else if (end_ptr == buff)
{
printf("Not valid numeric input\n");
}
/* here is where you might want to add code to */
/* test for extra non-numeric characters at the */
/* end of the input string, if you want that to */
/* be an error */
/* */
/* if you want to generate this error, remove */
/* the two preprocessor lines that start with */
/* #if 0 and #endif */
#if 0
else if (('\n' != *end_ptr) && ('\0' != *end_ptr))
{
printf("Extra characters on input line\n");
}
#endif
else
{
int_var = (int)long_var;
printf("The number %d is OK!\n", int_var);
}
}
return 0;
}