如果索引超出数组末尾有效,为什么我需要指定数组长度?

Why do I need to specify array length if indexing past the end of the array works?

定义一个有 2 个元素的数组

char a[2];

然后赋值并打印第 4 个元素。

a[0]='a';
a[1]='b';
a[2]='c';
a[3]='d';
cout<<a[3]<<endl;

为什么我能得到答案 'd' 而不是 运行 时间错误?声明数组a时,[]里面的值2代表什么?如果 2 在这里没有意义,为什么我不能把它写成:

char a[];

C和C++中的索引运算符a[b]可以认为定义为*(&a + sizeof(TA) * b),(有趣的是,a[b]b[a] 也是等价的,但这是另一种解释)。

让我们看一下代码:

char a[2]; // statically-allocates 2 bytes on the stack, e.g. at `0xFFFF`, and `0xFFFE` (as the stack grows downwards)
a[0] = 'a'; // sets `0xFFFF`
a[1] = 'b'; // sets `0xFFFE`
a[2] = 'c'; // sets `0xFFFD` <-- danger!

这里存在危险:C/C++ 不强制数组代码进行边界检查,因此您的代码可以被认为等同于此:

char a0; // 0xFFFF
char a1; // 0xFFFE
*0xFFFF = 'a';
*0xFFFE = 'b';
*0xFFFD = 'c'; <-- danger! writing to unallocated memory
*0xFFFC = 'd'; <-- uncharted territory! here be dragons!

你的代码"works"因为0xFFFD将是内存,存在的原因有两个:1:堆栈向下增长,将由OS自动保留,所以你不会段错误("access violation" on Windows),以及 2:你没有接近堆栈溢出错误条件。

但是,如果您要向函数中添加更多局部变量,那么您会发现 a[2] 将覆盖这些值,您还 运行 有覆盖当前堆栈框架 return 地址从而破坏您的堆栈并使您的程序处于不确定状态,应立即终止)。

考虑:

char[2] a;
int     b = 0;
int     c = 0;

a[2] = 'a';

assert( b == 0 ); // this assertion will fail (at least on systems that don't word-align locals)