最简洁安全的方法是用 std::count_if 配合 lambda,如 [](int x) { return x % 2 == 0; },它自动适配容器类型,避免手写循环的边界错误和 sizeof 退化问题,且 x % 2 == 0 对负数和零均正确判定偶数。

用 std::count_if 最简洁安全
直接用 std::count_if 配合 lambda,避免手写循环出错,也自动适配容器类型(std::vector、原生数组、std::array)。
常见错误是传错迭代器范围,比如对原生数组漏写 std::end(arr),或误用 sizeof(arr)/sizeof(arr[0]) 在函数参数里——此时 arr 已退化为指针,sizeof 失效。
- 对原生数组:必须用
std::begin(arr)和std::end(arr),不能靠sizeof - 对
std::vector:直接用v.begin()和v.end() - lambda 判断写成
[&](int x) { return x % 2 == 0; },注意负数取余在 C++ 中符号随被除数,但偶数定义是能被 2 整除,所以x % 2 == 0对负数也成立(如-4 % 2是 0)
int arr[] = {1, 2, 3, 4, -6, 7};
auto count = std::count_if(std::begin(arr), std::end(arr), [](int x) { return x % 2 == 0; });
// 结果是 3
手动遍历要注意 % 运算符的边界行为
手写 for 循环更直观,但容易忽略负数和零的处理。C++ 中 0 % 2 是 0,0 是偶数;负偶数如 -2、-100 的 % 2 也是 0,所以 x % 2 == 0 完全够用,不需要额外加 abs() 或判断符号。
性能上无差别,但可读性略低,且易漏边界(如空数组未初始化计数器)。
- 务必初始化计数变量为 0,否则值不确定
- 循环条件别写成
i 导致越界访问 - 若数组元素是
unsigned int,% 2仍安全,但没必要转成int再算
int count = 0; for (int i = 0; i <h3>用位运算 <code>& 1</code> 替代 <code>% 2</code>?不推荐盲目优化</h3> <p><code>x & 1</code> 确实比 <code>x % 2</code> 快,但现代编译器(GCC/Clang/MSVC)在 <code>-O2</code> 及以上会自动把 <code>% 2</code> 优化成位运算,实际生成的汇编一样。强行用 <code>& 1</code> 只会让代码意图变模糊,还可能引入 bug:对有符号整数,<code>& 1</code> 看的是补码最低位,结果和 <code>% 2 == 0</code> 一致;但若类型是 <code>char</code> 或 <code>short</code>,隐式提升后没问题,可读性仍是负收益。</p>
- 除非 profiling 明确指出这里是瓶颈,否则别改
- 如果真要用,写成
(x & 1) == 0,不是! (x & 1)—— 后者在x是负数时逻辑等价,但易误解 - 对
size_t或其他无符号类型,& 1安全,但同样没必要
统计前先确认数组是否为空或指针是否有效
实际工程中,数组来源可能是函数参数、动态分配内存或全局缓冲区,空指针或零长度导致崩溃很常见。标准库算法(如 std::count_if)对空范围安全,但手动遍历时必须检查。
- 原生数组作为函数参数传入时,长度必须额外传入,无法从形参推导
- 用
std::vector可直接调.empty()和.size() - 如果数组来自 C API(如
malloc),记得判nullptr,再判长度
最易被忽略的是跨平台场景:某些嵌入式平台或旧编译器对 std::begin/std::end 支持不完整,这时退回到显式长度 + 指针偏移更稳妥。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











