Как мне определить, произошла ли ошибка функции c atoi или это была строка нулей?
Вопрос
При использовании функции atoi
(или strtol
или аналогичные функции, если на то пошло), как вы можете определить, не удалось ли целочисленное преобразование или преобразуемая C-строка была 0
?
За то, что я делаю, 0
является приемлемым значением, и преобразуемая C-строка может содержать любое количество 0
s.Он также может содержать начальный пробел.
Решение
Для C ++ 11 и более поздних версий:
Функция перехода для преобразования строки в целое теперь stoi
, который принимает строку
и возвращает int
, либо выдает исключение при ошибке. р>
Больше нет необходимости в подробном хаке istringstream
, упомянутом в принятом ответе.
(есть также stol
/ stoll
/ stof
/ stod
/ stold
для long
/ long long
/ float
/ double
/ long double
, соответственно .) р>
Другие советы
Правильной функцией (до тех пор, пока вы настаиваете на использовании функций в стиле C) является strtol
и код преобразования может выглядеть следующим образом
const char *number = "10"; /* for example */
char *end;
long value = strtol(number, &end, 10);
if (end == number || *end != '\0' || errno == ERANGE)
/* ERROR, abort */;
/* Success */
/* Add whatever range checks you want to have on the value of `value` */
Некоторые замечания:
strtol
позволяет (имеется в виду:незаметно пропускает) пробел перед фактическим числом.Если вы считаете, что такой начальный пробел является ошибкой, вы должны проверить это самостоятельно.
Проверка на *end != '\0'
следит за тем, чтобы после цифр ничего не было.Если вы хотите разрешить использование других символов после фактического числа (пробел?), эта проверка должна быть изменена соответствующим образом.
P.S.Я добавил следующее end == number
проверьте позже, чтобы перехватить пустые входные последовательности.Входные данные "Все пробелы" и "вообще никакого числа" были бы перехвачены *end != '\0'
проверяйте в одиночку.Однако, возможно, имеет смысл заранее перехватить пустой ввод.В таком случае end == number
проверка будет / может стать ненужной.
Поскольку этот тег помечен c ++ :
template< typename T >
inline T convert(const std::string& str)
{
std::istringstream iss(str);
T obj;
iss >> std::ws >> obj >> std::ws;
if(!iss.eof())
throw "dammit!";
return obj;
}
Со страницы руководства для strtol ():
Если endptr не равен NULL, strtol () сохраняет адрес первого недействительного символ в * endptr. Однако, если цифр не было вообще, strtol () сохраняет исходное значение nptr в * endptr. (Таким образом, если * nptr не
'\ 0'
но ** endptr равен'\ 0'
при возврате, вся строка была действительной.)
Альтернативой strtol
является sscanf
, хотя он немного тяжелый:
const char *numStr = "12345"; // input string
int value;
if(sscanf(numStr, "%d", &value) == 1)
; // parsing succeeded, use value
else
; // error
Однако это позволяет использовать пробел в начале строки (что может или не может быть желательно), и позволяет чему-либо следовать за числом, поэтому " 123abc " будет принят и возвращен 123. Если вы хотите иметь более жесткий контроль, используйте strtol ()
, как AndreyT демонстрирует .
Прошло много времени с тех пор, как я написал C / C ++, но мне кажется, что (слишком) простым решением было бы проверить только строку на наличие "0".
int value = atoi(string_number.c_str());
if ( !value && string_number != "0" ) {
// error
} else {
// great success!
}