c ++ странная проблема преобразования символа в int - PullRequest
4 голосов
/ 01 сентября 2011

Я абсолютный новичок в 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;
}

В основном, если первый вход (цифры) ниже 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

Что происходит?Я разозлился, пытаясь найти ошибку в алгоритме, пока не обнаружил, что ошибка была в той части кода, где я не удосужился сначала посмотреть.

Заранее спасибо!

Ответы [ 5 ]

7 голосов
/ 01 сентября 2011

Проблема здесь:

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

atoi ожидает NUL-оканчивающуюся строку , что не то, что вы ей даете (нет символа NUL, за исключением того, чтоиногда вы можете получить его случайно).

Возможное (безобразное) исправление:

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 голосов
/ 01 сентября 2011
atoi(&tmpchar)

Я думаю, что это просто вызовет неопределенное поведение.Потому что тип &tmpchar - это char*, который является правильным типом c-строки, но не является строкой с нулевым значением.

Почему бы вам просто не сделать это:

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

Или, если вы хотите напечатать значение ASCII tmpchar, сделайте это:

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

Или даже проще:

cout << (int) tmpchar << endl; //prints the ASCII value of tmpchar
2 голосов
/ 01 сентября 2011

atoi принимает в качестве аргумента строку с нулевым символом в конце.Это массив символов с нулевым символом ('\ 0') в конце.

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

Вы передаете адрес одного символа.Но нет завершающего нулевого символа!

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

Это неопределенное поведение, и поэтому вы получаете странные результаты.

Вы можете получить число из однозначного символа безопасным способомкак это:

int number = digit - '0';
2 голосов
/ 01 сентября 2011

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 голосов
/ 01 сентября 2011

Аргументом atoi должен быть массив символов с нулевым символом в конце, а не просто указатель на один символ.

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

Здесь {0} устанавливает все элементы массива на 0, cin читает первый, второй символ остается нулевым, поэтому &tmpchar делает указатель на массив символов, который заканчивается нулевым символом.

...