在下面的程序中,第二个循环中的代码不应该给出分段错误吗? 有人可以解释为什么以下代码没有给出分段错误并按预期工作?
输出:
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;
}
答案 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]
- 操作系统知道的东西不在你的程序空间中 - 超出了为堆栈分配的空间,那就会出错。