When using the function atoi
(or strtol
or similar functions for that matter), how can you tell if the integer conversion failed or if the C-string
From the man page for strtol():
If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, however, strtol() stores the original value of nptr in *endptr. (Thus, if *nptr is not
'\0'
but **endptr is'\0'
on return, the entire string was valid.)
Since this is tagged c++:
template< typename T >
inline T convert(const std::string& str)
{
std::istringstream iss(str);
T obj;
iss >> std::ws >> obj >> std::ws;
if(!iss.eof())
throw "dammit!";
return obj;
}
The proper function (as long as you are insisting on using C-style functions) is strtol
and the conversion code might look as follows
const char *number = "10"; /* for example */
char *end;
long value = strtol(number, &end, 10);
if (end == number || *end != '\0' || errno == ERANGE)
/* ERROR, abort */;
/* Success */
/* Add whatever range checks you want to have on the value of `value` */
Some remarks:
strtol
allows (meaning: quietly skips) whitespace in front of the actual number. If you what to treat such leading whitespace as an error, you have to check for it yourself.
The check for *end != '\0'
makes sure that there's nothing after the digits. If you want to permit other characters after the actual number (whitespace?), this check has to be modified accordingly.
P.S. I added the end == number
check later to catch empty input sequences. "All whitespace" and "no number at all" inputs would have been caught by *end != '\0'
check alone. It might make sense to catch empty input in advance though. In that case end == number
check will/might become unnecessary.
It's been a while since I've done and C/C++, but it would appear to me that the (overly) simple solution would be to check just the string for "0".
int value = atoi(string_number.c_str());
if ( !value && string_number != "0" ) {
// error
} else {
// great success!
}
The go-to function for string-to-integer conversion is now stoi, which takes a string
and returns an int
, or throws an exception on error.
No need for the verbose istringstream
hack mentioned in the accepted answer anymore.
(There's also stol
/stoll
/stof
/stod
/stold
for long
/long long
/float
/double
/long double
conversions, respectively.)
An alternative to strtol
is sscanf
, although it's a little heavy-weight:
const char *numStr = "12345"; // input string
int value;
if(sscanf(numStr, "%d", &value) == 1)
; // parsing succeeded, use value
else
; // error
However, this allows leading whitespace in your string (which may or may not be desirable), and it allows anything to trail the number, so "123abc" would be accepted and return 123. If you want to have tighter control, go with strtol()
, as AndreyT demonstrates.