В чем разница между моими вызовами atoi()?
Вопрос
У меня есть большое число, хранящееся в строке, и я пытаюсь извлечь одну цифру.Но в чем разница между этими вызовами?
#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-й номер.
Если правильное значение выходит за пределы диапазона представимых значений, возвращается
INT_MAX
или INT_MIN.
2147483647 - INT_MAX
bigNumber.at ()
не возвращает новую строку с одним символом, но адрес символа в строке. Итак, второй вызов на самом деле:
atoi("720394857230")
который вызывает переполнение внутреннего алгоритма.
Кроме того, первый вызов очень опасен, поскольку он зависит от (случайного) значения в памяти в (& amp; tmp) +1
.
Вы должны выделить строку из двух символов, назначить один символ из bigNumber.at ()
первому и \ 0
второму, а затем вызвать < code> atoi () с адресом временной строки.
Аргументом для atoi
должна быть строка с нулевым символом в конце.
Функция at
дает указатель на символ в строке. Функция atoi
преобразует строку в int, а не только в один символ.