3

为什么没有这个段错误?

#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 循环中将 8 替换为 9 时,它确实如此。

注意:我正在 32 位 crunchbang linux 上尝试

4

3 回答 3

14

从技术上讲,这个程序会导致未定义的行为,这意味着绝对不能保证这个程序可以做什么。原则上,它可以格式化你的硬盘,通过电子邮件向你所有的朋友发送讨厌的信息,让你的电脑着火,或者变得有知觉并奴役人类。

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

希望这可以帮助!

于 2013-05-07T17:32:54.817 回答
2

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

但我想提供一些推测,为什么它会出现 n=9 而不是 8 的段错误。通常,变量喜欢int iint arr[]驻留在stack上,它会向下增长。因此,i可能位于 address 0x4000,如果它是 4 byte int,则arr[0]is at 0x4004arr[1]is at 0x4008,依此类推。在这种情况下,编译器很可能已经为 分配了 16 个字节arr,并且它可能使用下面的地址0x4014(之后的第一个字节arr,即 的地址arr[5])。但是除了您手动声明的变量之外,堆栈上通常还有其他东西。例如,printf调用的参数可能在堆栈上,并且可能还有其他簿记信息。因此,如果arr[9]与编译器用于其他用途的堆栈位置相吻合,您将无意中破坏该信息,这可能导致段错误。

或者,如果arr[8]位于从操作系统分配的堆栈帧的底部,那么您的操作系统将配置您的处理器以拒绝执行任何指令以从与arr[9]. 我认为这种情况不太可能发生,因为堆栈大小通常为 4KB 左右,对于这么短的程序,您应该离分配堆栈的末尾很远。

于 2013-05-07T17:55:54.300 回答
0

templatetypedef 的答案是正确的,这是一个未定义行为的情况(这并不像您想象的那么罕见),但我想补充一点:

9*sizeof(int) 不是 2 的幂。当编译器分配内存时,它们通常以两个字节的幂进行分配,以防止碎片。

您可能想知道为什么它不分配 4*sizeof(int) 因为这正是您所要求的。我不确定,但可能是编译器分配了几个额外的字节,或者它具有为数组分配的最小内存量。这取决于编译器和您编译代码时使用的选项。

尝试在没有优化的情况下运行您的代码(命令行上的-O0),它可能会分配您需要的确切内存量,并为 i>=4 分配段错误。

不过我可能错了,我不确定 C 编译器在堆或堆栈中分配静态数组。

于 2013-05-07T17:44:44.483 回答