How to Tell If the C Function Atoi Failed or If It Was a String of Zeros

How do I tell if the c function atoi failed or if it was a string of zeros?

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

atoi — how to identify the difference between zero and error?

That's one of the reasons atoi is sometimes considered unsafe. Use strtol / strtoul instead. And if you have it use strtonum.

The function atoi is more dangerous than you might think. The POSIX standard says:

If the value cannot be represented, the behavior is undefined.

The C99 standard says this also:

7.20.1

The functions atof, atoi, atol, and atoll need not affect the value of
the integer expression errno on an error. If the value of the result
cannot be represented, the behavior is undefined.

Use of atoi when string represents zero?

It's very simple, atoi returns the number converted which in your case is exactly 0 (as expected).

There is no standard method of checking whether the conversion actually succeeded or not when using atoi.

Since you are writing c++ you could get the same result with better error checking by using a std::istringstream, std::stoi (C++11) or strtol (which is a better interface when dealing with arbitrary numbers).


std::istringstream example

#include <sstream>

...

std::istringstream iss (argv[1]);
int res;

if (!(iss >> res))
std::cerr << "error";

std::strtol example

#include <cstdlib>
#include <cstring>

...

char * end_ptr;

std::strtol (argv[1], &end_ptr, 10);

if ((end_ptr - argv[1]) != std::strlen (argv[1]))
std::cerr << "error";

std::stoi (C++11)

#include <string>

...

int res;

try {
res = std::stoi (argv[1]);

} catch (std::exception& e) {
std::cerr << "error";
}

C++ - error while using atoi

That is why atoi is unsafe to use. It doesn't detect and inform the program if the input is invalid.

C++11 has introduced std:stoi which is safe, as it throws exception if input is invalid in some way. There are also two other variants : std::stol and std:stoll. See the online documentation for detail:

  • std::stoi, std::stol, std::stoll

Your code would become this:

try {
string s = "ssss";
int i = std::stoi(s); //don't call c_str()
//if (i == 0) no need to check!
std::cout << i << endl;
}
catch(std::exception const & e)
{
cout<<"error : " << e.what() <<endl;
}

Note that the runtime type of e could be either std::invalid_argument or std::out_of_range depending on the cause of the throw. You could just write two catch blocks if you want them to handle differently.

atoi ignores a letter in the string to convert

that's because atoi is an unsafe and obsolete function to parse integers.

  • It parses & stops when a non-digit is encountered, even if the text is globally not a number.
  • If the first encountered char is not a space or a digit (or a plus/minus sign), it just returns 0

Good luck figuring out if user input is valid with those (at least scanf-type functions are able to return 0 or 1 whether the string cannot be parsed at all as an integer, even if they have the same behaviour with strings starting with integers) ...

It's safer to use functions such as strtol which checks that the whole string is a number, and are even able to tell you from which character it is invalid when parsing with the proper options set.

Example of usage:

  const char *string_as_number = "01e";
char *temp;
long value = strtol(string_as_number,&temp,10); // using base 10
if (temp != string_as_number && *temp == '\0')
{
// okay, string is not empty (or not only spaces) & properly parsed till the end as an integer number: we can trust "value"
}
else
{
printf("Cannot parse string: junk chars found at %s\n",temp);
}

Atoi of a long string error

atoi interprets its input as a decimal number, not a binary number. Your longer string is causing the value to overflow, in which case the return value of atoi is undefined (although returning INT_MAX is common, which is equal to the value you're seeing).

To interpret the input as a binary number you can use strtol like this:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>

int main()
{
char line[256];

while (printf("\nInput: "),
fgets(line, sizeof line, stdin))
{
// skip initial whitespace and break if input is nothing but whitespace
char *p = line;
while (isspace(*p)) ++p;
if (*p == '\0') break;

// interpret input as a binary number
long n = strtol(line, &p, 2);

if (p == line)
printf("** Can't convert any characters. **\n");
else if (n == LONG_MAX || n == LONG_MIN)
printf("** Range error **\n");
else
printf("Value: %ld\n", n); // prints value in decimal

while (isspace(*p)) ++p; // skip whitespace after the value
if (*p != '\0')
printf("** Excess characters in input **\n");
}

return 0;
}

atoi() not converting whole string because of special character

It's not clear what you actually want, but maybe something like:

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
char *time = argc > 1 ? argv[1] : "10:20";
int d;
char *e;

d = strtol(time, &e, 10);
if( *e == ':' ){
d *= 100;
d += strtol(e + 1, &e, 10);
}
if( *e != '\0' ){
fprintf(stderr, "invalid input\n");
return 1;
}

printf("string val = %s, int value = %d\n", time, d);
return 0;
}

This will produce d = 1020 for the string "10:20". It's not at all clear to me what integer you want to produce, but that seems to be what you're looking for.



Related Topics



Leave a reply



Submit