为什么这不会产生分段错误
Why does this not produce a segmentation fault
这是c++中的for循环。我不明白为什么在执行时没有给出分段错误。
int main()
{
int arr[5];
for (int x = 0; x <= 5; x++)
{
arr[x] = x;
}
return 0;
}
这是未定义行为。未定义的行为意味着任何都可能发生,包括:
- 段错误
- 没有错误
- 输出不一致
- 硬盘格式化
- …(无论)
更正式一点,c++ 11标准是这样定义未定义行为的:
本国际标准对行为没有要求[注:当本国际标准省略了对…的明确定义时,可能会出现未定义的行为行为或当程序使用错误的结构或错误的数据时。允许的未定义行为从完全忽视导致不可预测结果的情况,到在翻译或翻译过程中的行为以环境特征的记录方式执行程序(有或没有发出(诊断消息),到终止翻译或执行(发出诊断消息)。许多错误的程序构造不会产生未定义的行为;他们需要被诊断出来。-end note]
之所以做x[5]
确实是未定义行为,是因为x[5]
等价于*(x + 5)
(见第8.3.4/6段),而关于*
一元算子的第5.3.1/1段规定:
一元*操作符是间接执行的:它所作用的表达式必须是指向对象的指针对象类型或指向函数类型的指针,而的结果是指向对象或函数的左值表达式指向的。如果表达式的类型是"指向T的指针",则结果的类型是"T。"[…]
但是由于x + 5
没有指向任何对象,并且上面的段落没有指定这样的指针解引用的结果应该是什么,因此前面引用的句子适用:
[…当本国际标准省略了对行为的任何明确定义时,可能会出现未定义的行为[…]
表示x[5]
为未定义行为
当用户程序试图执行下列操作之一时,会发生分段错误:
- 访问不允许访问的部分内存,如系统内存
- 访问不存在的部分内存(即超出边界)
所以你意识到你在数组中超出了界限是正确的,在最后一次循环迭代中,你正在访问程序分配的内存之外的东西。它只是碰巧那块内存不是系统内存,它存在,所以它允许你读取它。
如果你运行这段代码的次数足够多,你最终会得到一个分段错误,因为它会恰好被放置在系统内存或内存的末尾。
我认为Andy Prowl已经回答得最好了,他说这是未定义的行为。
但是如果你对为什么它不会崩溃的细节感兴趣,至少在我的编译器上,变量x
被分配在紧跟在数组后面的堆栈位置。当你将x
赋值给arr[5]
时,你实际上只是将x
赋值给它自己。
显然,这在不同的编译器之间可能是不同的。我想你可能有兴趣知道至少一个特定的编译器在做什么。
- 在某些循环内使用vector.push_back时出现分段错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 当我的阵列太大时出现分段错误
- 分段错误当我试图运行程序时出错
- 在c++中初始化矩阵时出现分段错误(核心转储)
- 尝试使用集合函数时出现分段错误
- 我无法缩小此分段错误的原因
- g++的分段错误(在NaN上使用to_string两次时)
- 我是如何在这段代码中出现分段错误的
- 创建结构的数组时遇到分段错误
- 在c++中键入向量中的所有值后,得到分段错误(核心转储)
- 在 c++ 中实现 Trie 时出现分段错误
- 为什么 fstream 在打开带有格式的文件时会导致分段错误?
- 为什么我遇到分段错误?
- 动态类的分段错误(家庭作业问题)
- 分段错误 - 读取初始化指针的数组
- 如何摆脱C ++中的分段错误错误?
- 使用 CTYPE 时出现分段错误
- 为什么代码给出分段错误?