C++中一个将字符转换为整数的奇怪问题

4

我是一个C++的新手,尝试解决Project Euler中的一个问题时,遇到了一个非常奇怪的问题。我将错误缩小到以下代码。

考虑以下简单的代码:

#include <iostream>

using namespace std;

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

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

基本上,如果第一个输入(numdigits)小于48,一切正常,但如果输入大于或等于48,则会出现非常奇怪的行为:

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

发生了什么?我因为试图找出算法中的错误而发疯,直到我发现错误在代码的那一部分,我一开始没有去看。

提前感谢!


你想要做什么?为什么输出结果是 NOT OK?预期的输出结果是什么?atoi() 函数需要一个以 NULL 结尾的 c 风格字符串作为参数,这可能是问题所在。tmpchar 直接后面的内存没有初始化,可能是任何值。 - Chad
作为注意事项,表现出这种行为的数字应该是48-57,但有时也包括9-13、43、45、46。(否则它们可能会导致程序崩溃) - Mooing Duck
5个回答

7
问题在这里:
char tmpchar;
cin >> tmpchar;
cout << atoi(&tmpchar) << endl;

atoi函数期望一个以空字符结尾的字符串作为参数,但你提供的不是(除非偶尔会碰巧出现空字符)。

一种可能的(丑陋的)解决方法是:

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

如果您正在处理多个字符的字符串,那么使用std::string将是正确的选择:
std::string str;
cin >> str;
cout << atoi(str.c_str()) << endl;

5
atoi(&tmpchar)

我认为这会产生未定义的行为。因为&tmpchar的类型是char*,这是正确的C字符串类型,但它不是以空字符结尾的字符串。
为什么不直接这样做:
int i = tmpchar - '0';
cout << i << endl; //prints whatever single-digit you enter for tmpchar

如果您想打印tmpchar的ASCII值,则可以执行以下操作:

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

甚至更简单:
cout << (int) tmpchar << endl; //prints the ASCII value of tmpchar

2

atoi()函数接受以NUL('\0')结尾的字符指针。你指向了第一个字符,但不能保证第二个字符是NUL。请尝试以下方法。

#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;
}

2

atoi函数以一个以空字符('\0')结尾的字符串作为参数。这是一个由字符组成的数组,在末尾有一个空字符。

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

您正在传递单个字符的地址。但是没有终止的空字符!
+---+---+---+
|'3'| ? | ? | = ?
+---+---+---+

这是未定义行为,这就是为什么你会得到奇怪的结果。

你可以像这样安全地从单个数字字符中获取一个数字:

int number = digit - '0';

2
atoi的参数必须是以空字符结尾的字符数组,而不仅仅是指向一个字符的指针。
char tmpchar[2] = {0};
cin >> tmpchar[0];
cout << atoi(&tmpchar) << endl;

这里{0}将所有数组元素设置为0,cin读取第一个元素,第二个字符保持为空,所以&tmpchar创建了一个指向以null字符结尾的字符数组的指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接