For循环在C ++中以字符串长度无限运行

时间:2018-12-15 07:44:04

标签: c++ string for-loop

我对for循环的这种行为感到非常惊讶:

程序1:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s1,s2;
    cin>>s1>>s2;
    for(int i=0;i<(s1.length()-s2.length()+1);i++)
    {
        cout<<"Hello\n";
    }
}

输入后:s1 =“ ab”,s2 =“ abcdef”

程序1的此for循环无限运行并无限次打印“ Hello”。

与此同时,程序2(以下)对于字符串s1和s2的相同输入都可以正常工作。

程序2:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s1,s2;
    cin>>s1>>s2;
    int len = (s1.length()-s2.length()+1);
    for(int i=0;i<len;i++)
    {
        cout<<"Hello\n";
    }
}

有人可以帮我解决这个问题,为什么程序1的for循环无限次运行?

2 个答案:

答案 0 :(得分:4)

在您的示例中,s1.length()被评估为2u(即2,但为unsigned类型),s2.length()被评估为{{1 }},6u最有可能被评估为s1.length() - s2.length()(因为无符号类型中没有4294967292u),而-4被评估为s1.length() - s2.length() + 1

4294967293u在C ++中返回.length(),这是无符号值。从另一个无符号值中减去一个无符号值会产生一个无符号值,例如size_t可能会产生1u - 2u

当混合有符号和无符号值(例如4294967295s.length() - 1)时,有符号值将转换为无符号值,例如i < s.length()通常是-1 > 1u,因为true被转换为-1。如果启用警告,现代编译器会警告您有关这种类型的比较。

了解到这一点,您可能希望循环运行40亿次迭代,但这不一定是正确的,因为4294967295是带符号的i,并且它是32位的(很可能是) ,它不能大于int。当您的程序从2147483647起增加代码时,就会发生有符号溢出,这在C ++中是undefined behavior。因此,您的循环可能会无限运行。

我怀疑您正在做有竞争力的编程。对于竞争性程序设计,我的建议 是无论何时要计算任何内容,都应始终将2147483647强制转换为.length()。您可以创建这样的宏:

int

然后写#define sz(x) ((int)(x).size()) 而不是sz(s)以避免此类错误。

但是,在代码必须生存超过几个小时的任何编程领域中,这种方法还是受到高度重视。例如。在业界还是开源。在这种情况下,每次需要时都使用显式s.length() / static_cast<int>(s.length())。或者,甚至更好的是,在代码审查期间询问有关您的代码的具体建议,还有很多可能的警告,请参见下面的注释以获取一些示例。

答案 1 :(得分:1)

我还没有机会进行测试,因此无法确定,但是我强烈怀疑这与string::length() returns a size_t是无符号类型有关。如果无符号类型变为负数,则它们会绕回最大值,因此2-6 + 1 = -3解释为32位无符号类型时将变为2 ^ 32-3。这导致您的循环迭代数十亿次,因此似乎没有终止。而在第二个程序中,您将显式转换为带符号的int,因此结果为预期的-3。