2009-04-27 71 views
5

很抱歉,如果这是一个noob问题:(数组中的元素太多! 。?!

片的C代码

int array[5]; 
int cnt; 

for(cnt = 0; cnt <= 10; cnt+=1) 
{ 
     array[cnt] = cnt; 
} 

应该给一个错误,没有正确工作正常 但是,为什么是它似乎!? - 在第一行中定义了一个超过双倍大小的数组(11),你甚至可以稍后访问数组[5到10],这让我感到困惑,当你定义数组[4或更小]时它会停止工作, ...

提前致谢。

回答

23

它可能会与您的特定编译器和计算机一起工作,但您不应该依赖它。

根据C语言规范,您的代码的行为是undefined。这意味着它可能做你想做的事,或者它可能会导致你的电脑崩溃,或者可能导致demons to fly out your nose

与高级语言(如Java和C#)不同,C相信您并不会对数组边界执行显式检查。你应该是负责任的,而不是在阵列的边界之外。

+3

用于鼻子恶魔守卫的+1! – RBerteig 2009-04-27 20:48:34

+2

@Rerteig:我不认为“断层”(defenstration不是一个词)意味着你认为它的意思。在英语中,这将是通过窗口投掷某人/某物的行为。 http://en.wikipedia.org/wiki/Defenestration – 2009-04-27 21:55:16

+0

确实是一个错字,但这个词的选择是故意的。我正在寻找一些与“恶魔”合作的东西,这种东西具有适当的意外驱逐感。这是一个延伸,可能超过了比喻的突破点;-) – RBerteig 2009-04-27 23:30:30

4

“但是为什么呢?”

因为这就是C的方式。

在运行时不检查数组边界。

这就是

16

这只是“的C法”,“作品”,如果你的“作品”的定义是“还没有崩溃”的代名词。

0

一旦运行数组的末尾,就会覆盖软件不期望的内存并破坏堆。你的软件可能会继续运行,但它会非常不稳定!

0

取决于堆栈内存的打包方式。此外,它会高兴地覆盖这些值,甚至读取它们,但很可能你正在破坏堆栈。

5

你所看到的是未定义的行为,由您访问具有无效索引的数组引起的。未定义的行为意味着任何事情都可能发生,包括您的程序看起来正常工作。

2

C中的数组在运行时不会被检查。换句话说,你可以“定义”一个大小为N的数组,并且愉快地访问数组边界的末尾。如果你离开数组的末尾,那么你会在栈(或堆)上的某个地方垃圾。

一旦你在某处丢弃了内存,你的程序可能会崩溃。这些崩溃可能很难追查到,因为它们可能会远离实际上超出数组末尾的地方。

通常当你声明在C数组,最好使用某种恒定或#定义标记数组的大小:

#define MAX_ELEMENTS 10 
int array[MAX_ELEMENTS]; 
int cnt; 
for(cnt = 0; cnt < MAX_ELEMENTS; cnt+=1) { 
    array[cnt] = cnt; 
} 

如果经过MAX_ELEMENTS在数组赋值,你可能覆盖cnt的值。您可能会覆盖其他一些变量。全部取决于编译器和代码结构。还要注意在for循环中使用<符号。 C数组基于0,因此您必须使用小于或小于或等于检查。

4

我只想指出,所有这些确实没有定义。 您的示例在本示例中“有效”,因为这两个变量都位于堆栈中。那就是cnt的地址就在数组的末尾。当cnt达到cnt == 5 时语句数组[cnt] = cnt;不会写入专用于该阵列的内存中,而是在其之后,cnt的地址所在的内存中写入。它只是运气,它不会改变你的柜台。 当cnt> 5时没有内存垃圾,它只会写入“stack void”(不知道正确的单词)。

另一个例子来说明这一点:

int main(int ac,char **av) 
{ 
    int a[5]; 
    int cnt; 
    int cnt2=3; 

    for(cnt=0;cnt<7;cnt++) { 
     a[cnt]=cnt; 
     printf("%d %d %d\n", a[cnt], cnt, cnt2); 
    } 
} 

输出:

0 0 3 
1 1 3 
2 2 3 
3 3 3 
4 4 3 
5 5 5 
6 6 5 

循环的最后两个写操作之后的[]重写栈数据,并且可以产生非常混乱误差。在这种情况下,cnt2被丢弃。

1

C中的数组边界是不一定是在运行时检查。该标准让执行者可以自由选择或不选择 - 这是undefined的一部分。在使用胖指针的实现中,示例可能确实会导致某种错误。