Как я могу сказать, что функция c atoi завершилась неудачно или это была строка нулей? - PullRequest
35 голосов
/ 29 октября 2009

При использовании функции atoi (или strtol или аналогичных функций в этом отношении), как вы можете определить, не удалось ли преобразовать целое число или была ли преобразованная C-строка 0?

Для того, что я делаю, 0 является приемлемым значением, и преобразуемая С-строка может содержать любое количество 0 с. Он также может иметь пробельные символы.

Ответы [ 6 ]

44 голосов
/ 29 октября 2009

Правильная функция (если вы настаиваете на использовании функций в стиле 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 проверка станет / может стать ненужной.

23 голосов
/ 29 октября 2009

Так как это помечено :

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; 
}
9 голосов
/ 14 февраля 2015

Для C ++ 11 и более поздних версий:

Функция перехода для преобразования строки в целое теперь имеет значение stoi, которое принимает string и возвращает int или создает исключение при ошибке.

Больше нет необходимости в подробном istringstream хаке, упомянутом в принятом ответе.

(Есть также stol / stoll / stof / stod / stold для long / long long / float / double / long double соответственно.)

5 голосов
/ 29 октября 2009

Со страницы руководства для strtol ():

Если endptr не равен NULL, strtol () сохраняет адрес первого недействительного символ в * endptr. Однако, если цифр не было вообще, strtol () сохраняет исходное значение nptr в * endptr. (Таким образом, если * nptr не '\0' но ** endptr равен '\0' при возврате, вся строка была действительной.)

2 голосов
/ 29 октября 2009

Альтернативой 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 демонстрирует .

1 голос
/ 29 октября 2009

Прошло много времени с тех пор, как я написал C / C ++, но мне кажется, что (слишком) простым решением было бы проверить только строку на "0".

int value = atoi(string_number.c_str());

if ( !value && string_number != "0" ) {
  // error
} else {
  // great success!
}
...