windows — C ++: проверить, является ли строка допустимым целым числом, используя & quot; strtol & quot;

Я слышал, что я должен использовать strtol вместо atoi из-за его лучшей обработки ошибок. Я хотел посмотреть, смогу ли я использовать этот код, чтобы проверить, является ли строка целым числом:

#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{
string testString = "ANYTHING";
cout << "testString = " << testString << endl;
int testInt = strtol(testString.c_str(),NULL,0);
cout << "errno = " << errno << endl;
if (errno > 0)
{
cout << "There was an error." << endl;
cout << "testInt = " << testInt << endl;
}
else
{
cout << "Success." << endl;
cout << "testInt = " << testInt << endl;
}
return 0;
}

Я заменил ANYTHING с 5 и это сработало отлично:

testString = 5
errno = 0
Success.
testInt = 5

И когда я делаю это с 2147483648, самое большое возможное int + 1, это возвращает это:

testString = 2147483648
errno = 34
There was an error.
testInt = 2147483647

Справедливо. Но когда я попробую это с Hello world!, это подходит:

testString = Hello world!
errno = 0
Success.
testInt = 0

Что мне здесь делать? И, пожалуйста, не давайте мне ничего сложного для чего-то такого простого, как проверка, что строка является целым числом.

Использование: GNU GCC Compiler, Code :: Blocks, Windows
«Пусть g ++ следует стандарту языка C ++ 11 ISO C ++ [-std = c ++ 11]», было проверено в «Флагах компилятора».

1

Решение

В соответствии с справочная страница strtol. Вы должны определить свою функцию, такую ​​как:

bool isNumeric(const std::string& str) {
char *end;
long val = std::strtol(str.c_str(), &end, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
//  if the converted value would fall out of the range of the result type.
return false;
}
if (end == str) {
// No digits were found.
return false;
}
// check if the string was fully processed.
return *end == '\0';
}

В C ++ 11 я предпочитаю использовать std::stol вместо std::strtol, такие как:

bool isNumeric(const std::string& str) {
try {
size_t sz;
std::stol(str, &sz);
return sz == str.size();
} catch (const std::invalid_argument&) {
// if no conversion could be performed.
return false;
} catch (const std::out_of_range&) {
//  if the converted value would fall out of the range of the result type.
return false;
}
}

std::stol звонки std::strtol, но вы работаете напрямую с std::string и код упрощен.

2

Другие решения

strtol останавливается на первой не цифре

но если вы читаете страницу руководства http://man7.org/linux/man-pages/man3/strtol.3.html ты можешь видеть

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

т.е.

string testString = "ANYTHING";
cout << "testString = " << testString << endl;
char *endptr;
int testInt = strtol(testString.c_str(),&endptr,0);
if(**endptr)
cout << "bad input";
3

Не используйте решение C ++ 11 с исключениями, потому что оно медленнее. Вот быстрая версия C ++ 11:

#include <algorithm>
bool is_decimal(const std::string& s)
{
return !s.empty() && std::find_if(s.begin(), s.end(), [](char c){ return !std::isdigit(c); }) == s.end();
}

Если вы уверены, что ваши строки в основном не пусты, вы можете удалить !s.empty (). Если нет, сохраните это, потому что !s.empty () (!(S.length () == 0)) дешевле, чем если бы вы позвонили find_if (ссылка) с пустой строкой.

Редактировать:
Если вам нужно справиться с переполнением, используйте версию исключения выше. Только если вы не можете использовать исключения, используйте это:

#include <string>
#include <sstream>
#include <limits>

template <class T>
bool is_decimal_and_fit(const std::string& s)
{
long double decimal = 0;
return (!(std::istringstream(s) >> decimal).fail() && (decimal >= std::numeric_limits<T>::lowest()) && (decimal <= std::numeric_limits<T>::max()));
}
0
По вопросам рекламы [email protected]