C语言数组越界访问未触发Segmentation Fault的原因咨询
我使用gcc编译运行以下C语言代码:
#include <stdio.h> int main() { float box[2][2]; box[3][3] = 1; printf("%f", box[3][3]); return 0; }输出结果为:
1.000000
为何C语言未抛出Segmentation Fault(数组越界错误)?
这是个相当典型的C语言新手困惑点,我来一步步给你拆解原因:
C语言对数组越界的定义是「未定义行为」
C标准里并没有要求编译器必须检测数组越界,也没有规定越界后程序必须抛出段错误。所谓「未定义行为」,意思是程序的行为完全不可预测——它可能正常运行,可能崩溃,可能篡改其他变量的值,甚至可能在不同环境下表现出完全不同的结果。你的代码刚好属于“正常运行”的极端情况,但这绝对不是正确的行为。段错误的触发条件是访问了受保护的内存页
Segmentation Fault是操作系统的内存保护机制在起作用:当你的程序试图访问不属于它的内存区域(比如内核空间、其他进程的内存,或者标记为不可访问的内存页)时,操作系统才会终止程序并抛出这个错误。
在你的代码里,box是一个栈上的二维数组,栈内存是程序自己的内存区域,向下生长。box[3][3]的地址虽然超出了数组的合法范围,但可能依然落在栈的有效内存范围内(还没触及到栈的边界或者受保护的内存页),所以操作系统没有拦截这次访问,程序得以继续执行。为什么输出是1.000000?
你给box[3][3]这个越界的内存位置赋值了1,随后又读取了它。因为这个位置是程序可访问的栈内存,所以赋值和读取操作都能顺利完成,自然就输出了你设置的值。但要注意:如果这个越界位置刚好是其他变量的存储地址,你这行赋值操作就会破坏那个变量的值,引发难以排查的bug。
最后一定要提醒:永远不要依赖这种未定义行为!数组越界是C语言中非常常见的bug根源,编写代码时一定要确保数组索引在合法范围内,比如使用循环时严格控制边界,或者用静态检查工具提前发现问题。
内容的提问来源于stack exchange,提问作者nikhilbalwani

