为什么这段代码不会导致段错?

时间:2013-05-07 17:30:56

标签: c segmentation-fault

为什么不是这个段错?

#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上尝试它

3 个答案:

答案 0 :(得分:14)

从技术上讲,这个程序会产生 undefined behavior ,这意味着绝对不能保证这个程序可以做什么。它原则上可以格式化您的硬盘驱动器,向所有朋友发送恶意消息,将您的计算机置于火上,或变得有感情并奴役人类。

在这种情况下,当n = 8时未定义的行为碰巧没有做任何坏事,而当n = 9时未定义的行为导致了段错误。两者都是该程序的完全允许行为,但完全不能保证可移植。

希望这有帮助!

答案 1 :(得分:2)

@templatetypedef是对的;他打败了我的答案。未定义的行为并不一定意味着段错误。

但我想提供一些猜测,为什么它为n = 9但不是8的段错误。通常,int iint 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编译器是在堆还是堆栈中分配静态数组。