如果索引超过数组末尾有效,为什么我需要指定数组长度
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!
您的代码之所以"有效"0xFFFD
是因为内存存在有两个原因:1:堆栈向下增长,操作系统会自动保留,因此您不会出现段错误(Windows 上的"访问冲突"),以及 2:您没有接近堆栈溢出错误情况。
但是,如果您要向函数添加更多局部变量,那么您会看到a[2]
将覆盖这些值,您还冒着覆盖当前堆栈帧的返回地址的风险,从而损坏堆栈并使程序处于不确定状态,应立即终止)。
考虑:
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)
相关文章:
- 数组长度,为什么从命令行获取时不能使用它?
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- 为什么我不能将 rand() 与数组的大小一起使用?
- 在C++中传递给函数时,为什么要指定数组大小作为参数
- 为什么我的排序算法会更改数组值
- 为什么std::vector比数组慢
- 为什么调用堆栈数组会导致内存泄漏
- 为什么用结构初始化数组需要指定结构名称
- 为什么我需要C++中不同的排序格式来对这个USACO代码上的数组和优先级队列进行排序
- 为什么可以修改数组 b?
- 为什么我们将单个或多维数组的大小声明为常量值?
- 为什么我的数组双精度函数不起作用?
- 为什么 2 个相同数组的元素彼此相等
- 为什么 &a 和 c++ 中的静态数组相同?
- 初始化不可移动对象数组:为什么这样的代码无法在 GCC 上编译?
- C++ 结构数组 - 为什么它必须是指针
- 在C++中添加两个 2D 数组 - 为什么这个程序崩溃
- 动态分配缓冲空间为二维数组 - 为什么失败
- 非恒定大小的数组:为什么这甚至可以工作
- C++字符数组——为什么是垃圾