对不起,如果这是一个菜鸟问题:(。
一段C代码。
int array[5];
int cnt;
for(cnt = 0; cnt <= 10; cnt+=1)
{
array[cnt] = cnt;
}
应该报错吧?不!工作正常!但这是为什么呢?似乎 - 在第一行 - 定义了一个大于双倍大小 (11) 的数组。您甚至可以稍后访问数组 [5 到 10]。这让我很困惑。当您定义数组 [4 或更少] 时,它会停止工作...
提前致谢。
它可能恰好适用于您的特定编译器和计算机,但您不应该指望它。
根据 C 语言规范,您的代码的行为是未定义的。这意味着它可能会如您所愿,或者可能导致您的计算机崩溃,或者可能导致恶魔飞出您的鼻子。
与 Java 和 C# 等高级语言不同,C 信任您并且不对数组的边界执行显式检查。你应该负责,不要踏出阵列的边界。
如果您对“工作”的定义与“尚未崩溃”同义,则这只“有效”。
您看到的是未定义的行为,这是由于您使用无效索引访问数组引起的。未定义的行为意味着任何事情都可能发生,包括您的程序似乎可以正常工作。
“但这是为什么呢?”
因为C就是这样。
运行时不检查数组边界。
这就是“C定律”
我只想指出,这一切确实是未定义的。您的示例在此特定示例中“有效”,因为这两个变量都位于堆栈上。那就是 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 被丢弃。
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 的,因此您必须使用小于和不小于或等于进行检查。
C 中的数组边界不一定在运行时检查。该标准让实现者可以自由选择或不选择这样做 - 这是undefined的一部分。在使用胖指针的实现中,样本确实可能会导致某种错误。
一旦你跑出数组的末尾,你就会覆盖软件不期望的内存并破坏堆。您的软件可能会继续运行,但会非常不稳定!
取决于堆栈内存的打包方式。此外,它会很高兴地覆盖这些值甚至读取它们,但很可能您正在破坏堆栈。