简体   繁体   中英

c++ weird problem converting a char to int

I'm a total newbie to C++ and I was trying to do one of the problems from Project Euler when I had a very weird problem. I reduced the error to the following.

Consider the following simple code:

#include <iostream>

using namespace std;

int main() {
    int numdigits;
    cout << "digits: ";
    cin >> numdigits;

    char tmpchar;
    cin >> tmpchar;
    cout << atoi(&tmpchar) << endl;
    return 0;
}

Basically if the first input (numdigits) is below 48 everything works fine but if the input is 48 or greater if have a very weird behaviour:

air:programming santi$ ./lol
digits: 30
3
3                            <--- OK
air:programming santi$ ./lol
digits: 48
3
30                           <--- Not OK
air:programming santi$ ./lol
digits: 49
3
31                           <--- Not OK
air:programming santi$ ./lol
digits: 50
3
32                           <--- Not OK

What is going on? I got mad trying to find the error in the algorithm until I found out that the error was in that part of the code where I didn't bother to look at first.

Thanks in advance!

The problem is here:

char tmpchar;
cin >> tmpchar;
cout << atoi(&tmpchar) << endl;

atoi expects a NUL-terminated string , which isn't what you're giving it (there's no NUL character except that you may be sometimes getting one by chance).

A possible (ugly) fix is:

char tmpchar[2] = {0};
cin >> tmpchar[0];
cout << atoi(tmpchar) << endl;

If you're dealing with multiple-character strings, then using std::string would be the way to go:

std::string str;
cin >> str;
cout << atoi(str.c_str()) << endl;
atoi(&tmpchar)

I think this would simply invoke undefined behaviour. Because the type of &tmpchar is char* which is correct c-string type, but its not null-teminated string.

Why don't you simply do this:

int i = tmpchar - '0';
cout << i << endl; //prints whatever single-digit you enter for tmpchar

Or if you want to print the ASCII value of tmpchar , then do this:

int i = tmpchar;
cout << i << endl; //prints the ASCII value of tmpchar

Or even simpler:

cout << (int) tmpchar << endl; //prints the ASCII value of tmpchar

The argument to atoi must be a null-terminated array of characters, not just a pointer to one character.

char tmpchar[2] = {0};
cin >> tmpchar[0];
cout << atoi(&tmpchar) << endl;

Here {0} sets all array elements to 0, cin reads the first one, the second character remains null, so &tmpchar makes a pointer to a character array that is terminated with null character.

atoi() takes a NUL ('\\0') terminated character pointer. You're pointing it at the first character, but there is no guarantee that the second character is NUL. Try the following.

#include <iostream>

using namespace std;

int main() {
    int numdigits;
    cout << "digits: ";
    cin >> numdigits;

    char tmpchar[2];
    cin >> tmpchar[0];
    tmpchar[1] = '\0';
    cout << atoi(tmpchar) << endl;
    return 0;
}

atoi takes a null-terminated string as an argument. That is an array of characters with a null character ('\\0') at the end.

+---+---+---+
|'1'|'0'|\0 | = "10"
+---+---+---+

You are passing the address of a single character. But there is no terminating null character!

+---+---+---+
|'3'| ? | ? | = ?
+---+---+---+

This is undefined behaviour, and that's why you get weird results.

You can obtain a number from a single digit character in a safe manner like this:

int number = digit - '0';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM