How to convert a command-line argument to int?

169,027

Solution 1

Since this answer was somehow accepted and thus will appear at the top, although it's not the best, I've improved it based on the other answers and the comments.

The C way; simplest, but will treat any invalid number as 0:

#include <cstdlib>

int x = atoi(argv[1]);

The C way with input checking:

#include <cstdlib>

errno = 0;
char *endptr;
long int x = strtol(argv[1], &endptr, 10);
if (endptr == argv[1]) {
  std::cerr << "Invalid number: " << argv[1] << '\n';
} else if (*endptr) {
  std::cerr << "Trailing characters after number: " << argv[1] << '\n';
} else if (errno == ERANGE) {
  std::cerr << "Number out of range: " << argv[1] << '\n';
}

The C++ iostreams way with input checking:

#include <sstream>

std::istringstream ss(argv[1]);
int x;
if (!(ss >> x)) {
  std::cerr << "Invalid number: " << argv[1] << '\n';
} else if (!ss.eof()) {
  std::cerr << "Trailing characters after number: " << argv[1] << '\n';
}

Alternative C++ way since C++11:

#include <stdexcept>
#include <string>

std::string arg = argv[1];
try {
  std::size_t pos;
  int x = std::stoi(arg, &pos);
  if (pos < arg.size()) {
    std::cerr << "Trailing characters after number: " << arg << '\n';
  }
} catch (std::invalid_argument const &ex) {
  std::cerr << "Invalid number: " << arg << '\n';
} catch (std::out_of_range const &ex) {
  std::cerr << "Number out of range: " << arg << '\n';
}

All four variants assume that argc >= 2. All accept leading whitespace; check isspace(argv[1][0]) if you don't want that. All except atoi reject trailing whitespace.

Solution 2

Note that your main arguments are not correct. The standard form should be:

int main(int argc, char *argv[])

or equivalently:

int main(int argc, char **argv)

There are many ways to achieve the conversion. This is one approach:

#include <sstream>

int main(int argc, char *argv[])
{
    if (argc >= 2)
    {
        std::istringstream iss( argv[1] );
        int val;

        if (iss >> val)
        {
            // Conversion successful
        }
    }

    return 0;
}

Solution 3

std::stoi from string could also be used.

    #include <string>

    using namespace std;

    int main (int argc, char** argv)
    {
         if (argc >= 2)
         {
             int val = stoi(argv[1]);
             // ...    
         }
         return 0;
    }

Solution 4

As WhirlWind has pointed out, the recommendations to use atoi aren't really very good. atoi has no way to indicate an error, so you get the same return from atoi("0"); as you do from atoi("abc");. The first is clearly meaningful, but the second is a clear error.

He also recommended strtol, which is perfectly fine, if a little bit clumsy. Another possibility would be to use sscanf, something like:

if (1==sscanf(argv[1], "%d", &temp))
    // successful conversion
else
    // couldn't convert input

note that strtol does give slightly more detailed results though -- in particular, if you got an argument like 123abc, the sscanf call would simply say it had converted a number (123), whereas strtol would not only tel you it had converted the number, but also a pointer to the a (i.e., the beginning of the part it could not convert to a number).

Since you're using C++, you could also consider using boost::lexical_cast. This is almost as simple to use as atoi, but also provides (roughly) the same level of detail in reporting errors as strtol. The biggest expense is that it can throw exceptions, so to use it your code has to be exception-safe. If you're writing C++, you should do that anyway, but it kind of forces the issue.

Solution 5

The approach with istringstream can be improved in order to check that no other characters have been inserted after the expected argument:

#include <sstream>

int main(int argc, char *argv[])
{
    if (argc >= 2)
    {
        std::istringstream iss( argv[1] );
        int val;

        if ((iss >> val) && iss.eof()) // Check eofbit
        {
            // Conversion successful
        }
    }

    return 0;
}
Share:
169,027
nosedive25
Author by

nosedive25

I work mostly with Cocoa and Objective-C. For the past 7 years, between school work and other things I've managed to learn a few programming languages. I've also done some work in Java for the Ludum Dare game jam competition. As for the web I'm fairly good with PHP and HTML5.

Updated on July 05, 2022

Comments

  • nosedive25
    nosedive25 about 2 years

    I need to get an argument and convert it to an int. Here is my code so far:

    #include <iostream>
    
    
    using namespace std;
    int main(int argc,int argvx[]) {
        int i=1;
        int answer = 23;
        int temp;
    
        // decode arguments
        if(argc < 2) {
            printf("You must provide at least one argument\n");
            exit(0);
        }
    
        // Convert it to an int here
    
    }
    
  • WhirlWind
    WhirlWind about 14 years
    I'd recommend against atoi: "The atoi() function has been deprecated by strtol() and should not be used in new code."
  • CB Bailey
    CB Bailey about 14 years
    How about the fact that it's impossible to tell whether a conversion actually took place with atoi? This would seem a pretty good reason to avoid atoi to me.
  • Admin
    Admin about 14 years
    @WhirlWind Deprecated by whom?
  • WhirlWind
    WhirlWind about 14 years
    @Neil I don't see where... maybe it's just my particular standard library that deprecates it.
  • nosedive25
    nosedive25 about 14 years
    Oh opps that was my mistake. I originally had it that way but then started trying different things and forgot to change it back.
  • michelson
    michelson about 14 years
    @WhirlWind: I wouldn't go so far as to call it deprecated Many people still use it when there is no need to check inputs. As for failure checking, the answer isn't checking for failures either.
  • jaques-sam
    jaques-sam about 7 years
    You forgot std:: in front of istreamstream
  • Keyur Padalia
    Keyur Padalia about 7 years
    @DrumM OP has using namespace std; in the question.
  • jaques-sam
    jaques-sam about 7 years
    Correct (even it is a bad habit) ;-)
  • NathanOliver
    NathanOliver almost 6 years
    Would you mind adding a stoi solution now that we have that? That would make this answer more complete.
  • Keyur Padalia
    Keyur Padalia almost 6 years
    @NathanOliver Done, but untested. Feel free to edit!
  • NathanOliver
    NathanOliver almost 6 years
    @Thomas Thanks.
  • Alan Birtles
    Alan Birtles almost 6 years
    @Thomas you need to check pos from std::stoi it only throws if none of the string can be parsed as a number, e.g. std::stoi("1zz") doesn't throw and returns 1 which is probably not what you want when parsing command line arguments.
  • Keyur Padalia
    Keyur Padalia almost 6 years
    @AlanBirtles Done (and the same for the istringstream approach).