遍历std::array二维数组时下标顺序应为i行j列,即arri,避免因惯性将j误作行索引导致越界或逻辑错误。

用 for 循环遍历 std::array<:array>, 4></:array> 时下标别写反
二维数组本质是“数组的数组”,arr[i][j] 中 i 是外层数组索引(行),j 是内层数组索引(列)。很多人习惯先写“x 坐标再写 y 坐标”,结果把 j 当成行、i 当成列,访问越界或逻辑错乱。
- 确认维度顺序:声明为
std::array<:array cols>, ROWS></:array>,则循环应是for (size_t i = 0; i 套 <code>for (size_t j = 0; j - 用范围 for 更安全:对
std::array<:array>, 4></:array>,可写for (const auto& row : arr) { for (int x : row) { /* use x */ } },完全避开下标错误 - 如果用 C 风格数组
int arr[4][3],sizeof(arr)/sizeof(arr[0])得行数,sizeof(arr[0])/sizeof(arr[0][0])得列数——别直接硬编码 4 和 3,否则改大小就崩
遍历 std::vector<:vector>></:vector> 要提防空行和不规则形状
std::vector<:vector>></:vector> 不是真正意义上的二维数组,每行长度可以不同。直接套用固定列数的双重 for 循环会崩溃或漏数据。
- 安全写法:外层循环用
for (size_t i = 0; i ,内层必须用 <code>for (size_t j = 0; j ,不能假设所有 <code>vec[i].size()相同 - 避免重复调用
.size():在内层循环前缓存const size_t row_len = vec[i].size();,尤其在 debug 模式下.size()可能非 O(1) - 若确定是规则矩阵且性能敏感,改用一维
std::vector<int></int>手动映射:索引row * cols + col,比嵌套 vector 快且内存连续
std::for_each 配合 lambda 处理二维容器时注意引用捕获
想用 STL 算法遍历二维结构,容易忽略 lambda 捕获方式导致拷贝开销或悬垂引用。
- 对
std::vector<:vector>>& mat</:vector>,用[&mat]捕获可读写;但若只读且元素是基本类型,[&]或[&mat]都行,别用[=]——会深拷贝整个二维结构 - 对
std::array<:array n>, M></:array>,值语义没问题,[=]安全,但没必要;更推荐直接范围 for,语义清晰无歧义 - 若在 lambda 里修改元素,确保传入的是非常量引用:比如
std::for_each(mat.begin(), mat.end(), [&](auto& row) { std::for_each(row.begin(), row.end(), [](int& x) { x *= 2; }); });
用 std::span(C++20)切片二维数据时别忽略 stride
std::span 本身不支持二维,但常被用来包装一维内存并模拟二维访问。这时候行列计算依赖正确的 stride(步长),错一个数就全偏移。
立即学习“C++免费学习笔记(深入)”;
- 假设有连续内存
std::vector<int> data(ROWS * COLS)</int>,想按行优先访问第r行第c列:索引是r * COLS + c,不是r + c * ROWS - 封装成行视图:用
std::span<int>{data.data() + r * COLS, COLS}</int>,别漏掉+ r * COLS偏移 - 跨平台或对接 C API 时,确认对方是否用列优先(如 Fortran、某些 BLAS 实现),此时 stride 应为
ROWS,不是COLS
实际写的时候,最麻烦的从来不是“怎么写循环”,而是搞清数据在内存里到底怎么排的——尤其是混用 vector、array、裸指针、C 接口时,维度和 stride 一错,调试半天才发现是访问了隔壁变量。











