我尝试了一段使数组溢出的代码,但是当我用gcc编译它时发生了意想不到的事情。下面是代码:
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a[] = {0,2,4,7};
int size = sizeof(a)/sizeof(int);
int i;
printf("%d, %Xn", size, &a);
a[4] = 6;
printf("%d, %Xn", size, &a);
a[5] = 78;
printf("%d, %Xn", size, &a);
a[6] = 65;
printf("%d, %Xn", size, &a);
for (i = 0; i < size; i++) {
printf("%d, ", a[i]);
}
printf("%d, %d, %dn", a[size], a[size+1], a[size+2]);
printf("n");
return 0;
}
,结果是:
4, BFC4DDF8
6, BFC4DDF8
6, BFC4DDF8
6, BFC4DDF8
0, 2, 4, 7, 6, 5, 65, 0, 0
所以在代码中,我没有改变size的值,但是当它运行时,它确实自己改变了!有人能告诉我为什么会这样吗?
PS: gcc版本是4.8.0.
根据@NPE的答案,我检查了size
的地址,它实际上位于a
之后的内存中。
但是当我添加一段代码
printf("%Xn", &size);
之前printf("%d, %Xn", size, &a);
结果是
BFC39108
4, BFC3910C
4, BFC3910C
4, BFC3910C
4, BFC3910C
0, 2, 4, 7, 4, 78, 65
此时, size
位于a
之前的内存中。
事实上,无论我在哪里打印size
的地址,它都恰好位于a
的地址之前;如果我不打印size
的地址,它就在a
的地址后面。那么它仍然是编译器的未定义行为吗?
由于您写了a
的末尾,因此您的程序具有未定义的行为。这意味着它可以以任何它喜欢的方式行动,包括你观察的方式。
实际情况是,size
恰好位于a
之后的内存中,以及以下越界赋值:
a[4] = 6;
覆盖size
.
请注意,如果使用不同的编译器或不同的编译器设置,或者对程序进行看似无关紧要的更改,代码可能会以其他方式失败。或者它可以在整个测试过程中工作得很好,然后在您的客户面前爆炸。
您覆盖了a[]数组结束后的内存,因此覆盖了size的值。