2

I'm trying to convert a string variable, which contains alphabetic and numeric values, into an int variable.

string argument = "100km";
int i = atoi(argument.c_str());
cout<<i<<endl;

I've confirmed that i has an int of 100 and km is omitted. However, if I enter 2147483648km, which is over that range of int, i will have -2147483648.

According to this page, int is supposed to be able to have

–2,147,483,648 to 2,147,483,647

So, I thought that this error came from the range of int, but the same error happens even when atoi is replaced by atol and int is replaced by unsigned long, which can have a much larger value. In other words, replacing int with long doesn't fix this error.

Chances are that I need to come up with an alternative way to convert this kind of string (i.e. string of "______km" into an int variable).

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
Hiroki
  • 3,893
  • 13
  • 51
  • 90
  • 1
    According to the page that you linked, `long` also has the range `–2,147,483,648 to 2,147,483,647` (on that platform)... – eerorika Jun 09 '15 at 08:41
  • data type limits aside, I would use sscanf for this type of string parsing not atoi/atol. It's much more versatile. – Pandrei Jun 09 '15 at 08:44
  • Thank you all very much. Using `atoll` and `long long` seems to be the most suitable choice for my case, but other opinions are highly appreciated and informative too. – Hiroki Jun 09 '15 at 08:53

5 Answers5

4

In some compilers int is not "much less" than long, and indeed they're equal.

The only guarantee the standard gives you is that a long is never smaller than an int.

A simple solution would be to use atof instead that uses doubles that on most platforms is a 64-bit IEE754 double-precision number that is able to represent all integers exactly up to a magnitude of 253 that is 9,007,199,254,740,992.

6502
  • 112,025
  • 15
  • 165
  • 265
2

The size and range of the basic integer types depends on the compiler. On 32-bit platforms just about all compilers only have 32-bit int and long types. On 64-bit platforms the Visual Studio compiler still have 32-bit int and long while e.g. GCC have 32-bit int and 64-bit long.

If you want a larger type then you need long long which currently is 64 bits on all platforms and compilers (though it don't have to be).

Also, you should switch to stoi, stol and stoll (or their unsigned variants) instead of atoi.


If you want to know the actual limits, sizes and ranges of a type, you should use std::numeric_limits.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

The data type ranges from Microsoft's site can show you what Visual C++ compilers use.
This may vary, see 6502's answer covering that.

Moreover, atol returns a long, so if you give it a unsigned long you're going to get a long in return.

Since C++11, you are able to use atoll which returns a long long, otherwise see the other answers using stoi, stol, stoll.

Andreas DM
  • 10,685
  • 6
  • 35
  • 62
0

By using strtol you can achieve what you are looking for:

    string argument = "2147483648km";
    char *end;
    std::cout<<strtol(static_cast<const char *> (argument.c_str()),&end,10);

Depends on the size , you can prefer stol,stoll or stoi. More details are available here : http://en.cppreference.com/w/cpp/string/byte/strtol

Steephen
  • 14,645
  • 7
  • 40
  • 47
0

Use std::stringstream.

#include <sstream>
#include <iostream>
#include <string>
using namespace std;

int main()
{
        std::stringstream ss { "2147483648km" };
        int n;
        string s;

        if (!(ss >> n ))
        {
                std::cout << "cannot convert \n";
        }
        else
        {
                ss >> s ;
                std::cout << n << " " << s << "\n";
        }
}

And you can even abstract the whole thing

struct Distance
{
    string unit; 
    int distance;

    friend istream& operator>>(istream& in, Distance &d)
    {
         return in >> distance >> unit;
    }

};

std::stringstream ss { "331104km" };
Distance dst;
ss >> dst;
edmz
  • 8,220
  • 2
  • 26
  • 45