В чем разница между моими вызовами atoi()?

StackOverflow https://stackoverflow.com/questions/1026190

  •  06-07-2019
  •  | 
  •  

Вопрос

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

#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;
Это было полезно?

Решение

Все более-менее объяснимо.

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 будет сканировать числовые символы, пока не будет найден нечисловой.Совершенно неясно, когда он его найдет и что он будет делать при чтении недопустимых ячеек памяти.

Другие советы

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

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

  

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

2147483647 - INT_MAX

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

atoi("720394857230")

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top