5

对不起,如果这是一个菜鸟问题:(。

一段C代码。

int array[5];
int cnt;

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

应该报错吧?不!工作正常!但这是为什么呢?似乎 - 在第一行 - 定义了一个大于双倍大小 (11) 的数组。您甚至可以稍后访问数组 [5 到 10]。这让我很困惑。当您定义数组 [4 或更少] 时,它会停止工作...

提前致谢。

4

9 回答 9

24

它可能恰好适用于您的特定编译器和计算机,但您不应该指望它。

根据 C 语言规范,您的代码的行为是未定义的。这意味着它可能会如您所愿,或者可能导致您的计算机崩溃,或者可能导致恶魔飞出您的鼻子

与 Java 和 C# 等高级语言不同,C 信任您并且不对数组的边界执行显式检查。你应该负责,不要踏出阵列的边界。

于 2009-04-27T20:40:21.163 回答
17

如果您对“工作”的定义与“尚未崩溃”同义,则这只“有效”。

于 2009-04-27T20:42:59.253 回答
5

您看到的是未定义的行为,这是由于您使用无效索引访问数组引起的。未定义的行为意味着任何事情都可能发生,包括您的程序似乎可以正常工作。

于 2009-04-27T20:43:25.570 回答
4

“但这是为什么呢?”

因为C就是这样。

运行时不检查数组边界。

这就是“C定律”

于 2009-04-27T20:40:32.253 回答
4

我只想指出,这一切确实是未定义的。您的示例在此特定示例中“有效”,因为这两个变量都位于堆栈上。那就是 cnt 的地址就在数组末尾的下方。当 cnt 达到 cnt==5 时,语句 array[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

循环的最后两次写入会覆盖 a[] 之后的堆栈数据,并且可能会产生非常混乱的错误。在这种情况下,cnt2 被丢弃。

于 2009-04-28T15:57:10.523 回答
2

C 中的数组在运行时不检查。换句话说,您可以“定义”一个大小为 N 的数组,并愉快地访问数组边界的末尾。如果您离开数组的末尾,那么您将在堆栈(或堆)的某个位置丢弃内存。

一旦你在某处垃圾内存,你的程序很可能会崩溃。这些崩溃可能很难追踪,因为它们可能会在远离您实际超出阵列末端的地方崩溃。

通常,当您在 C 中声明数组时,最好使用某种常量或 #define 来标记数组的大小:

#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 的,因此您必须使用小于和不小于或等于进行检查。

于 2009-04-27T20:47:47.183 回答
1

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

于 2009-05-01T03:37:04.413 回答
0

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

于 2009-04-27T20:43:11.203 回答
0

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

于 2009-04-27T20:43:19.020 回答