我对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循环无限次运行?
答案 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
。
当混合有符号和无符号值(例如4294967295
或s.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。