为什么这不会产生分段错误

时间:2013-05-07 20:44:35

标签: c++

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

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

3 个答案:

答案 0 :(得分:18)

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

  • 分段错误
  • 完全没有错误
  • 输出不一致
  • 硬盘格式化
  • ......(无论如何)

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

  

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

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

  

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

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

  

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

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

答案 1 :(得分:3)

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

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

所以你正确地意识到你已经超出了数组的界限,并且在最后一次循环迭代中你正在访问你程序的已分配内存之外的东西。事实上,这段内存不是系统内存而且存在,因此它可以让你阅读它。

如果你运行这段代码足够多次,你最终会遇到分段错误,因为它恰好会被放置在系统内存或内存的末尾。

答案 2 :(得分:1)

我认为Andy Prowl已经回答说这是不确定的行为。

但是如果你对它没有崩溃的原因感兴趣,至少在我的编译器上,变量x被分配在紧跟在数组之后的堆栈上的位置。当您将x分配给arr[5]时,您实际上只是将x分配给自己。

显然,从一个编译器到下一个编译器可能会有所不同。您可能有兴趣至少知道一个特定的编译器正在做什么。