<p>最直接标准做法是用 for 循环配合 i += 2,起始索引和边界条件须匹配数组长度,避免越界;常见错误是写成 i < arr.length - 1 或起始值设错导致漏访或越界。</p>

用 for 循环配合 i += 2 最直接
标准做法就是写一个普通 for 循环,但步长不写 i++,改用 i += 2。注意起始索引和边界条件必须匹配数组长度,否则越界。
常见错误是写成 i 或漏判奇数长度数组的最后一个有效索引。
- 起始索引通常为
0(取偶数位),也可从1开始(取奇数位) - 终止条件必须是
i ,其中 <code>n是数组大小,不能写成i 这类易错形式 - 对
std::vector,用vec.size();对 C 风格数组,得提前知道长度,比如sizeof(arr)/sizeof(arr[0])
int arr[] = {10, 20, 30, 40, 50};
size_t n = sizeof(arr) / sizeof(arr[0]);
for (size_t i = 0; i < n; i += 2) {
std::cout << arr[i] << " "; // 输出: 10 30 50
}用迭代器时别用 std::next 做步进
std::next(it, 2) 看似方便,但每次调用都重新计算地址,效率低;更重要的是,它不检查是否越界,容易引发未定义行为。
正确方式是手动推进迭代器,并在每次推进前检查是否到达 end()。
立即学习“C++免费学习笔记(深入)”;
- 不要写
it = std::next(it, 2)—— 它可能越过end() - 推荐用
std::advance(it, 2),但它也不自动校验边界,仍需你手动判断 - 最稳妥的是每次只
+= 2后立刻比较:if (it != vec.end()) { ... }
避免用 std::ranges::views::stride(C++23)踩兼容性坑
std::ranges::views::stride(2) 确实语义清晰,但它是 C++23 特性,GCC 12/Clang 15 才开始支持,且需显式开启 -std=c++23。很多项目还卡在 C++17/C++20。
更隐蔽的问题是:它返回的是一个 lazy view,底层不复制数据,但如果原容器生命周期结束,view 就悬空。
- 仅当确定编译器版本、标准支持、且容器生命周期可控时才考虑
- 调试时无法直接打印 view 内容,得转成
std::vector或循环展开,增加排查成本 - 对小数组或简单遍历,纯属杀鸡用牛刀
指针算术要小心对齐和类型大小
用指针遍历(如 int* p = arr; p )本质和 <code>for 循环等价,但容易误以为“p += 2 跳过两个字节”——其实跳过的是两个 int 单元,即 2 * sizeof(int) 字节。
这点在处理 char 数组或自定义结构体时尤其关键:步长含义完全取决于指针类型。
-
char*指针加 2 真的是跳 2 字节;int*加 2 是跳 8 字节(假设int为 4 字节) - 如果数组元素不是 POD 类型,指针算术可能不合法,优先用索引或迭代器
- 用
std::span(C++20)可兼顾类型安全与指针风格,但需确认标准支持情况
实际写的时候,90% 的场景用第一个 for 循环就够了。真正容易出问题的不是语法,而是边界判断——尤其是当数组长度为 0 或 1 时,i += 2 后是否还满足 i < n,这个细节一疏忽就段错误。


















