为什么下面的代码没有给出分段错误?

时间:2011-09-10 01:56:05

标签: c arrays segmentation-fault

在下面的程序中,第二个循环中的代码不应该给出分段错误吗? 有人可以解释为什么以下代码没有给出分段错误并按预期工作?

输出: 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1

#include <stdio.h>
#define N 20

int main(){
    int a[N];
    int i;

    for(i=0;i<N;i++){
        a[i]=20-i;
        printf("%3d ",a[i]);
    }

    printf("\n\n");

    for(i=0;i<N;i++){
        a[i]=a[a[i]];
        printf("%3d ",a[i]);
    }

    printf("\n\n");

    return 0;
}

3 个答案:

答案 0 :(得分:10)

您的阵列在堆栈中。运行结束通常意味着您正在访问垃圾(因此调用未定义的行为),但它不一定会触发seg-fault。

在您的情况下,第一个a[i]=20-i将第一个元素设置为值20.因此,第一个a[i]=a[a[i]]会触发对a[20]的访问,该访问不在最后。但实际上它很有可能访问变量i - 假设编译器将其紧接在数组之后 - 并且i当前为零,因此nett效应为a[0] = 0。由于a[i]=a[a[i]]a[i] < 20的每次后续调用都保证完全在范围内。

答案 1 :(得分:2)

马塞洛的评论似乎很直观但实际上并不是正在发生的事情。堆栈从高到低增长。所以[19]将位于较高地址,[0]将位于较低地址。由于i是在数组之后定义的,因此它在堆栈中甚至更低。所以[20]并没有指向我。正如其他人所提到的那样,只是垃圾价值。 a [-1]或[-2](某些编译器允许使用负号进行索引,这意味着它会降低)实际上将指向i。 (-2因为某些编译器在分配数组后可以放置一个保护字节(或4个字节)以避免缓冲区溢出攻击)。

答案 2 :(得分:1)

非常确定操作系统是否存在故障,而不是编译器。您的里程可能因系统和为堆栈分配的内存而异。我猜想只要您在预先分配的堆栈空间中,它就不会崩溃。这就是特别麻烦 - 它可以很好地运行而不是告诉你有问题,除非你很幸运它会产生错误的结果。

如果你试图访问,比如说a[10000] - 操作系统知道的东西不在你的程序空间中 - 超出了为堆栈分配的空间,那就会出错。