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

时间:2016-06-22 00:00:21

标签: c++ windows c++11 error-handling strtol

我听说我应该使用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

我打算在这做什么?请不要给我一些简单的东西,比如验证字符串是int。

使用:GNU GCC编译器,Code :: Blocks,Windows
“g ++遵循C ++ 11 ISO C ++语言标准[-std = c ++ 11]”已经在“编译器标志”中进行了检查。

3 个答案:

答案 0 :(得分:3)

strtol在第一个非数字

上停止

但如果您阅读了手册页http://man7.org/linux/man-pages/man3/strtol.3.html,则可以看到

  

如果endptr不为NULL,则strtol()存储第一个地址          * endptr中的无效字符。如果根本没有数字,          strtol()将nptr的原始值存储在* endptr中(并返回          0)。 特别是,如果* nptr不是&#39; \ 0&#39;但是** endptr是&#39; \ 0&#39;上          返回,整个字符串有效

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

答案 1 :(得分:2)

根据the man page of 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 :(得分:0)

不要使用带有异常的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 reference),其中包含空字符串。

编辑: 如果必须处理溢出,请使用上面的异常版本。只有您不能使用例外时才使用:

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