首页 > 解决方案 > 使用 string::size_type vs int 遍历字符串

问题描述

这是我在使用 C++14 标准(32 位/Windows 10)的 TDM-GCC 上使用的代码:

class var
{
private:
    vector<int> num;
public: 
    var(string x)
    {
        for(int i = x.size()-1; i >= 0; i--) // Notice use of INT
            num.push_back(x[i]-'0');
    }
};

int main()
{
    var num1("232");
    return 0;
}

工作得很好,但最佳实践(和几个 SO 答案)说我应该使用string::size_type而不是int因为字符串可能比int可以容纳的更长。

现在,当我替换int为 时string::size_type,会发生一些奇怪的事情;以下代码可以编译,但是当我执行它时,它什么也不做。而是弹出窗口,显示“thisProgram.exe 已停止工作...”对话框,终端突然关闭。(带有任意大的返回码)

class var
{
private:
    vector<int> num;
public: 
    var(string x)
    {
        // Everything is same except the following line has string::size_type instead of int
        for(string::size_type i = x.size()-1; i >= 0; i--) 
            num.push_back(x[i]-'0');
    }
};

int main()
{
    var num1("232");
    return 0;
}

那么,使用有什么问题string::size_type呢?这个编译器是特定的吗?我真的很困惑,因为没有错误消息。

标签: c++stringiteration

解决方案


string::size_type是无符号类型,这意味着它永远不会是负数。这意味着这种情况:

i >= 0

永远不会是假的。事实上,当i低于时0,它会回绕,并成为 的最大可能string::size_type值。然后,当您 index 时x[i],您会调用未定义的行为。

我建议这样写循环:

for(int i = static_cast<int>(x.size()) - 1; i >= 0; i--)
  // ...

注意static_cast 减 1 之前(否则你会遇到空字符串的问题)。

除非您有非常大的字符串,否则长度应该在int可以处理的范围内。如果确实需要string::size_type索引,也可以执行此循环:

auto i = x.size();
while (i-- > 0)
  // ...

unsigned请注意,这对类型是健壮的。比较0发生减量之前i(因此是减量后运算符)。所以你很好地得到了索引size-1, size-2, ..., 1,0。当iis0时,比较将失败,然后i变成一个大正数的事实并不重要。


推荐阅读