2013-04-05 68 views
0

我试过一段代码,它使得数组溢出,但是当我用gcc编译它时发生了意想不到的事情。下面是代码:当我尝试创建一个数组溢出时,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, %X\n", size, &a); 
    a[4] = 6; 
    printf("%d, %X\n", size, &a); 
    a[5] = 78; 
    printf("%d, %X\n", size, &a); 
    a[6] = 65; 
    printf("%d, %X\n", size, &a); 
    for (i = 0; i < size; i++) { 
     printf("%d, ", a[i]); 
    } 
    printf("%d, %d, %d\n", 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 

所以在代码中,我并没有改变大小的值,但是当它跑,它本身没有变化!那么谁能告诉我为什么会发生这种情况?

PS:gcc版本是4.8.0。

根据@NPE的回答,我检查了size的地址,它实际上位于a之后的内存中。

但当我之前

printf("%d, %X\n", size, &a); 

添加一段代码

printf("%X\n", &size); 

结果是

BFC39108 
4, BFC3910C 
4, BFC3910C 
4, BFC3910C 
4, BFC3910C 
0, 2, 4, 7, 4, 78, 65 

在这个时候,size位于内存a之前。


事实上,无论我打印size的地址,它位于正好之前a的地址;如果我不打印size的地址,它就位于a的地址之后。那么它仍然是编译器的未定义行为?

+0

我预计大小的值不应该改变。 – Jude 2013-04-05 14:12:49

+1

你不能再期待一旦你有未定义的行为。 – NPE 2013-04-05 14:14:14

回答

4

由于您写过a的末尾,因此您的程序有undefined behaviour。这意味着它可以以任何方式行事,包括您观察的方式。

发生了什么事的做法是,size恰好位于内存a之后,下面出界外分配:

a[4] = 6; 

覆盖size

注意,代码可以在一些其他的方式失败,如果您使用的是不同的编译器或不同的编译器设置,或对程序看似无关紧要的变化。或者它在整个测试过程中都可以正常工作,然后在客户的脸上炸开。

+0

但是'size'似乎每次运行时都位于'a'后面的memeory中。 – Jude 2013-04-05 14:34:50

+0

@Jude:电脑是在完全可以预测的,如果你给他们同样的指示,他们会做同样的事情。所以你不应该感到惊讶。该行为仍然是不确定的,明天'size'可能不对了''后定位。 – NPE 2013-04-05 14:38:31

+0

我刚刚编辑过这个问题,如果我在任何地方打印size的地址,它就位于'a'的地址之前。那么这仍然是编译器的复活节彩蛋? – Jude 2013-04-07 11:19:26

0

您覆盖了a []数组末尾的内存,因此覆盖了大小的值。

相关问题