В чем разница между моими вызовами atoi ()? - PullRequest
1 голос
/ 22 июня 2009

У меня в строке хранится большое число, и я пытаюсь извлечь одну цифру. Но чем отличаются эти звонки?

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

Это даст следующий вывод.

цифра: 7

цифра2: 2147483647

цифра3: 57230

Первый - желаемый результат. Второе мне кажется случайным числом, которого я не могу найти в строке. Третий - это конец строки, но не просто одна цифра, как я ожидал, а от 12-го индекса до конца строки. Может кто-нибудь объяснить мне различные выводы?

РЕДАКТИРОВАТЬ: это будет приемлемым решением?

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

Ответы [ 5 ]

5 голосов
/ 22 июня 2009

Это все более или менее объяснимо.

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

Эта строка копирует один символ '5' в символьную переменную. atoi преобразует это правильно. atoi ожидает, что строковым параметром является допустимая строка с нулем в конце. &tmp является только указателем на символьную переменную - поведение этого вызова не определено, поскольку память, следующая непосредственно за символом в памяти, неизвестна. Точнее, вам нужно будет создать строку с нулевым символом в конце и передать ее. *

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

Эта строка получает указатель на символ в позиции 5 в строке. Это указатель на исходную строку большого числа выше - поэтому строковый параметр atoi выглядит как строка "5720394857230". atoi явно переполнит поток, пытаясь превратить это в целое число, поскольку ни одно 32-битное целое не будет содержать это.

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

Эта строка получает указатель на строку в позиции 12. Параметр atoi является строкой. "57230". Правильно преобразуется в целое число 57230.

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

... } * * Тысяча двадцать-один

Поскольку вы используете C ++, есть более приятные методы для преобразования строк символов в целые числа. Я неравнодушен к библиотеке Boost lexical_cast. Вы бы использовали это так:

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)));

* Строго говоря, atoi будет сканировать числовые символы, пока не будет найден нечисловой. Он явно не определен, когда он найдет его и что он будет делать при чтении из недопустимых областей памяти.

5 голосов
/ 22 июня 2009

Я знаю, почему отображается 2-й номер.

Из справочника Atoi.

Если правильное значение находится вне диапазона представляемых значений, возвращается INT_MAX или INT_MIN.

2147483647 - INT_MAX

3 голосов
/ 22 июня 2009

Функция at дает указатель на символ в строке. Функция atoi преобразует строку в int, а не только в один символ.

3 голосов
/ 22 июня 2009

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

3 голосов
/ 22 июня 2009

bigNumber.at() не возвращает новую строку с одним символом, но адрес символа в строке. Итак, второй вызов на самом деле:

atoi("720394857230")

, что вызывает переполнение внутреннего алгоритма.

Кроме того, первый вызов очень опасен, поскольку он зависит от (случайного) значения в памяти при (&tmp)+1.

Вы должны выделить строку из двух символов, назначить один символ из bigNumber.at() первому и \0 второму, а затем вызвать atoi() с адресом временной строки.

...