C++:使用 "strtol" 检查字符串是否为有效整数

C++: check if string is a valid integer using "strtol"

本文关键字:是否 有效 整数 字符串 检查 使用 strtol C++      更新时间:2023-10-16

我听说我应该使用strtol而不是atoi,因为它可以更好地处理错误。我想通过查看是否可以使用此代码来检查字符串是否为整数来测试strtol

#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;
}

我用5替换了ANYTHING,它工作得很好:

testString = 5
errno = 0
Success.
testInt = 5

当我使用2147483648执行此操作时,最大可能的int+ 1 (2147483648),它返回以下内容:

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

很公平。但是,当我尝试使用Hello world!时,它错误地认为它是一个有效的int并返回0

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

笔记:

  • 我正在使用 Code::Blocks with GNU GCC Compiler on Windows
  • "让 g++ 遵循 C++11 ISO C++ 语言标准 [-std=c++11]"在"编译器标志"中选中。

根据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 == '';
}

在 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并且代码得到了简化。

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";

不要使用 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())); 
}