为什么不是这个段错?
#include <stdio.h>
int main()
{
int i;
int arr[] = {1, 2, 3, 4};
for(i=0;i<8;i++)
{
arr[i] = i;
printf(" %d", arr[i]);
}
printf("\n");
return 0;
}
但是当我在for循环中将9替换为9时,它确实存在。
注意:我在32位crunchbang linux上尝试它
答案 0 :(得分:14)
从技术上讲,这个程序会产生 undefined behavior ,这意味着绝对不能保证这个程序可以做什么。它原则上可以格式化您的硬盘驱动器,向所有朋友发送恶意消息,将您的计算机置于火上,或变得有感情并奴役人类。
在这种情况下,当n = 8时未定义的行为碰巧没有做任何坏事,而当n = 9时未定义的行为导致了段错误。两者都是该程序的完全允许行为,但完全不能保证可移植。
希望这有帮助!
答案 1 :(得分:2)
@templatetypedef是对的;他打败了我的答案。未定义的行为并不一定意味着段错误。
但我想提供一些猜测,为什么它为n = 9但不是8的段错误。通常,int i
和int arr[]
等变量驻留在stack上,下。因此,i
可能位于地址0x4000
,如果它是4字节int
,那么arr[0]
位于0x4004
,{{1} }在arr[1]
,依此类推。在这种情况下,编译器很可能为0x4008
分配了16个字节,它可能使用arr
以下的地址(0x4014
之后的第一个字节,即{{1}的地址}})。但除了手动声明的变量之外,堆栈上通常还有其他东西。例如,arr
调用的参数可能在堆栈中,并且可能存在其他簿记信息。因此,如果arr[5]
与编译器用于其他内容的堆栈位置一致,则会无意中破坏该信息,这可能导致段错误。
或者,如果printf
位于从操作系统分配的堆栈帧的底部,那么您的操作系统将配置您的处理器,从字面上拒绝执行任何指令来加载或存储重合的地址中的值与arr[9]
。我认为这种情况不太可能,因为堆栈大小通常是4KB左右,对于这么短的程序,你应该远远没有分配堆栈的末尾。
答案 2 :(得分:0)
templatetypedef回答是正确的,这是一个未定义行为的情况(这并不像你想象的那么罕见),但我想补充一点:
9 * sizeof(int)不是2的幂。当编译器分配内存时,它们通常以两个字节的幂分配,以防止heap的碎片化。
您可能想知道为什么它不会分配4 * sizeof(int),因为这正是您所要求的。我不确定,但可能是编译器分配了几个额外的字节,或者它将为数组分配最小的内存量。这取决于编译器和编译代码的选项。
尝试在没有优化的情况下运行代码(在命令行上使用-O0),它可能会为您分配所需的确切内存量,并为i&gt; = 4分配段。
我可能错了,但我不确定C编译器是在堆还是堆栈中分配静态数组。