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
What Is the Fastest Way to Change a Key of an Element Inside Std::Map
Using Bitwise Operators for Booleans in C++
Std::Shared_Ptr Initialization: Make_Shared<Foo>() VS Shared_Ptr<T>(New Foo)
Best Method for Storing This Pointer for Use in Wndproc
How to Generate Assembly Code with Clang in Intel Syntax
Converting Data from Glreadpixels() to Opencv::Mat
What Is the Meaning of Clang's -Wweak-Vtables
Handling Header Files Dependencies with Cmake
Can Openssl on Windows Use the System Certificate Store
Can't Overload Operator<< as Member Function
Move or Named Return Value Optimization (Nrvo)
Restrict C++ Template Parameter to Subclass
How Often Should I Call Srand() in a C++ Application