Search code examples
c++atoi

What is difference between my atoi() calls?


I have a big number stored in a string and try to extract a single digit. But what are the differences between those calls?

#include <iostream>
#include <string>

int main(){
    std::string bigNumber = "93485720394857230";
    char tmp = bigNumber.at(5);
    int digit = atoi(&tmp);
    int digit2 = atoi(&bigNumber.at(5))
    int digit3 = atoi(&bigNumber.at(12));
    std::cout << "digit: " << digit << std::endl;
    std::cout << "digit2: " << digit2 << std::endl;
    std::cout << "digit3: " << digit3 << std::endl;
}

This will produce the following output.

digit: 7

digit2: 2147483647

digit3: 57230

The first one is the desired result. The second one seems to me to be a random number, which I cannot find in the string. The third one is the end of the string, but not just a single digit as I expected, but up from the 12th index to the end of the string. Can somebody explain the different outputs to me?

EDIT: Would this be an acceptable solution?

char tmp[2] = {bigNumber.at(5), '\0'};
int digit = atoi(tmp);
std::cout << "digit: " << digit << std::endl;

Solution

  • It is all more or less explicable.

    int main(){
        std::string bigNumber = "93485720394857230";
    

    This line copies the single character '5' into the character variable. atoi will convert this correctly. atoi expects that the string parameter is a valid 0 terminated string. &tmp is only a pointer to the character variable - the behaviour of this call is undefined since the memory immediately following the character in memory is unknown. To be exact, you would have to create a null terminated string and pass that in.*

        char tmp = bigNumber.at(5);
        int digit = atoi(&tmp);
    

    This line gets a pointer to the character in position 5 in the string. This happens to be a pointer into the original big number string above - so the string parameter to atoi looks like the string "5720394857230". atoi will clearly oveflow trying to turn this into an integer since no 32 bit integer will hold this.

        int digit2 = atoi(&bigNumber.at(5))
    

    This line gets a pointer into the string at position 12. The parameter to atoi is the string "57230". This is converted into the integer 57230 correctly.

        int digit3 = atoi(&bigNumber.at(12));
    

    ... }

    Since you are using C++, there are nicer methods to convert strings of characters into integers. One that I am partial to is the Boost lexical_cast library. You would use it like this:

    char tmp = bigNumber.at(5);
    // convert the character to a string then to an integer
    int digit = boost::lexical_cast<int>(std::string(tmp));
    
    // this copies the whole target string at position 5 and then attempts conversion
    // if the conversion fails, then a bad_lexical_cast is thrown
    int digit2=boost::lexical_cast<int>(std::string(bigNumber.at(5)));
    

    * Strictly, atoi will scan through the numeric characters until a non-numeric one is found. It is clearly undefined when it would find one and what it will do when reading over invalid memory locations.