如果索引超出数组末尾有效,为什么我需要指定数组长度?
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)
定义一个有 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)