为什么在环路条件中使用'<='而不是'<'会产生分段错误 [SIGSEGV]?

why does using '<=' instead of '<' in the loop condition gives a segmentation fault [SIGSEGV]?

本文关键字:lt 分段 SIGSEGV 错误 条件 环路 为什么      更新时间:2023-10-16

我在 12 月的比赛中解决了 codechef 的问题 - https://www.codechef.com/DEC19B/problems/BINADD .在代码中的某个地方,我放了这个循环:

for(i=0;i<=(pos.size()-2);i++)
{
if(pos[i]<0) 
continue;
else if(len<(pos[i]-pos[i+1])) 
len=pos[i]-abs(pos[i+1]);
} 

这里 pos 是一个向量,声明为:vector<int> pos;

对于这些值,代码显示一个 SIGSEGV :

POS 的大小 = 1 , pos[0]=0 , len=0

但是如果我在循环中用i<(pos.size()-1)替换i<=(pos.size()-2),则不会发生SIGSEGV 。有人有解释吗

注意:1( 完整代码 :

#include <bits/stdc++.h>
using namespace std;
void func()
{   
int i=0,len=0,index=0;
string a,b;
cin>>a>>b;
if(b=="0") {std::cout << 0 << std::endl;return;}
else if(a=="0") {std::cout << 1 << std::endl;return;}
int n1,n2;
n1=a.length();
n2=b.length();
if(n1<n2)
{ 
i=n2-n1;
while(i--)
a="0"+a;
}
else 
{   
i=n1-n2; 
while(i--) 
b="0"+b;
}
std::vector<int> pos;
i=a.length();
while(i--)
{
if(a[i]=='0'&&b[i]=='0')
pos.push_back(-i);
if(a[i]=='1'&&b[i]=='1')
pos.push_back(i);
}
for(i=0;i<=(pos.size()-2);i++)
{
if(pos[i]<0) 
continue;
else if(len<(pos[i]-pos[i+1])) 
len=pos[i]-abs(pos[i+1]);
}
if(pos[i]>=0)
if(len<(pos[i]+1))
len=pos[i]+1;
std::cout << (len+1) << std::endl;
}
int main() {
int t,n;
std::cin >> t;
while(t--)
func();
return 0;
}

2(对于测试用例:

1

1 1

上面的代码显示了SIGSEGV

正如其他人所提到的,size()属于无符号的size_t类型,因此size() - n所有非零n都可能下溢。

由于这种下溢,循环将至少执行一次。

i等于零且pos.size()等于 1 时,pos[i+1]的索引是未定义的行为,可能会出现段错误:

else if(len<(pos[i]-pos[i+1])) 
len=pos[i]-abs(pos[i+1]);

pos是向量,所以分配的大小会比大小多,所以在i增长到等于向量的初始分配大小之前,它可能不会出现段错误;当这种情况发生时,pos[i+1]的索引将脱离为向量分配的内存的末尾。

也有可能它甚至没有段错误,但在下一页边界 - 一旦你有未定义的行为,那么很难准确地判断程序何时崩溃而不调试它或添加跟踪输出,而且它真的没有那么重要,因为你应该纠正代码。

如果pos的大小为1pos.size()-2不等于-1,它是size_t(无符号类型(可以在系统上保持的最大值。所以循环运行到i是一个非常非常大的数字。

最大数量有一个定义:SIZE_MAX。它通常在现代 64 位系统上18446744073709551615.

for(i=0;i<=(pos.size()-2);i++)对于pos.size()==1是一个无限循环,对于i == SIZE_MAX,条件是SIZE_MAX<=SIZE_MAX,这是真的,然后i绕到0,就这样继续下去。

您通过越界访问vector来调用未定义的行为。编译器可能对此进行了优化,因此您只需一次又一次地计数SIZE_MAX

size()返回一个无符号的size_t。当大小为 1 时,大小 -2 是一个负数,它四舍五入为一个大的 posisibe 数。因此,您的 for 循环会在不应该执行时执行。