为何STL array首元素为数组大小,其副本却符合预期?
问题分析与解答
问题描述
我原本想学习如何将一维数组当作二维数组进行旋转,却发现了异常现象:声明包含16个int的std::array,打印时首元素显示为16(数组大小),但复制到同大小的std::array后,副本打印结果符合初始定义值。后续发现复制代码存在数组越界错误,但仍有疑问:为何原数组首元素变为数组大小,副本却无此问题?
相关代码:
// 打印函数 void func(std::array<int, 16> arr){ for(int i = 0; i < 16; ++i){ std::cout << arr[i] << ' '; if((i + 1) % 4 == 0) std::cout << std::endl; } } // 原数组声明 std::array<int, 16> arr{ 1, 2, 3, 4, 0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 0, 1 }; // 复制代码(存在越界) for(int i = 0; i <= 16;++i){ rotd_arr[i] = arr[i]; }
核心原因:数组越界触发的未定义行为
你的问题本质是数组越界访问导致的未定义行为,具体现象和编译器的内存布局直接相关,拆解如下:
越界访问的发生
复制循环的条件是i <= 16,会执行17次循环(i从0到16),但std::array<int,16>的有效索引范围是0~15。当i=16时,arr[16]属于越界读取,rotd_arr[16]属于越界写入——这在C++中是未定义行为,编译器无法保证任何预期结果。原数组首元素变为16的具体原因
在你的编译环境中,rotd_arr和arr的栈内存可能相邻。执行rotd_arr[16] = arr[16]时:arr[16]越界读取到栈上的循环变量i的当前值16;rotd_arr[16]的内存地址恰好覆盖了arr的首元素arr[0]的地址,导致arr[0]被意外修改为16。
副本打印正常的原因
副本rotd_arr的有效元素是索引0~15,越界写入的rotd_arr[16]不在打印函数的遍历范围内,因此有效元素未被破坏,打印结果看起来符合初始值。但实际上rotd_arr的内存已经被非法修改,只是影响的是数组之外的区域。
修复方案
将循环条件改为i < 16,确保只访问有效索引:
for(int i = 0; i < 16; ++i){ rotd_arr[i] = arr[i]; }
或者直接使用std::array的赋值运算符,更简洁安全:
rotd_arr = arr;
内容的提问来源于stack exchange,提问作者Noah M
相关产品推荐
相关产品推荐

