-1

这是 c++ 中的 for 循环。我不明白为什么它在执行时没有给出分段错误。

int main() 
{
   int arr[5];
   for (int x = 0; x <= 5; x++)
       {
           arr[x] = x;
       }
   return 0; 
}
4

3 回答 3

18

这是未定义的行为。未定义的行为意味着任何事情都可能发生,包括:

  • 分段故障
  • 完全没有错误
  • 输出不一致
  • 硬盘格式化
  • ... (任何)

为了更正式一点,这是 C++11 标准定义未定义行为的方式:

本国际标准对其没有要求的行为 [:当本国际标准省略任何明确的行为定义或程序使用错误构造或错误数据时,可能会出现未定义的行为。允许的未定义行为的范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),到终止翻译或执行(发出的诊断消息)。许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来。——尾注]

关于doingx[5]确实是未定义行为的原因,那是因为x[5]相当于*(x + 5)(参见第8.3.4/6段),关于一元运算符的第5.3.1/1段*指定:

一元 * 运算符执行间接:应用它的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是一个左值,指向表达式指向的对象或函数。如果表达式的类型是“指向 T 的指针”,则结果的类型是“T”。[...]

但是由于x + 5不指向任何对象,并且上面的段落没有指定解引用这样的指针的结果应该是什么,所以前面引用的句子适用:

[...] 当本国际标准省略任何明确的行为定义时,可能会出现未定义的行为 [...]

这意味着这x[5]是未定义的行为。

于 2013-05-07T20:45:30.743 回答
3

当用户程序尝试执行以下操作之一时,会发生分段错误:

  • 访问不允许访问的内存的一部分,例如系统内存
  • 访问不存在的内存部分(也就是越界)

因此,您正确地意识到您超出了数组的范围,并且在最后一次循环迭代中,您正在访问程序分配内存之外的内容。碰巧这块内存不是系统内存并且它存在,所以它可以让你读取它。

如果您将这段代码运行足够多次,您最终应该会遇到分段错误,因为它恰好位于系统内存或内存末尾。

于 2013-05-07T20:51:31.203 回答
1

我认为 Andy Prowl 已经回答得最好,说这是未定义的行为。

但是,如果您对为什么它不会崩溃的细节感兴趣,至少在我的编译器上,变量x被分配在紧跟数组的堆栈上的位置。当您分配x给 时arr[5],您实际上只是分配x回自身。

显然,这可能因一种编译器而异。只是想你可能有兴趣至少知道一个特定的编译器在做什么。

于 2013-05-07T20:53:04.853 回答