Question

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 that was being converted was a 0?

For what I'm doing, 0 is an acceptable value and the C-string being converted may contain any number of 0s. It may also have leading whitespace.

Was it helpful?

Solution

For C++11 and later:

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.)

OTHER TIPS

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.

Since this is tagged :

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; 
}

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.)

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.

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!
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top