最直白有效的方式是用普通for循环配合下标访问直接赋值,如arr[i] = value;错误写法是范围for循环中修改副本,原数组不变。

用普通 for 循环 + 下标访问直接改
最直白有效的方式就是用 for 配合下标,arr[i] 是左值,能直接赋值。编译器不加干预,改完立刻生效,适用于所有内置类型和可赋值的自定义类型。
常见错误是写成 for (int x : arr) 这种只读遍历,哪怕后面写 x = 5 也只改了副本,原数组完全没变。
- ✅ 正确:
for (int i = 0; i - ❌ 错误:
for (int x : arr) x *= 2;(x是拷贝) - ⚠️ 注意:如果
arr是const或元素类型不可赋值(如std::unique_ptr移动后为空),编译会直接报错
用范围 for 循环必须加引用
想用更简洁的 for (auto& x : arr) 修改,关键在 & —— 缺了它就退化成只读遍历。引用绑定到原元素,所有对 x 的修改都会反映到底层存储。
性能上几乎无额外开销,但要注意引用类型匹配:比如 const int& 能读不能写,int&& 通常用于移动,别乱用。
- ✅ 生效:
for (auto& x : vec) x += 10;(vec是std::vector<int></int>) - ✅ 也生效:
for (int& x : arr) x = 0;(C 风格数组) - ❌ 不生效:
for (auto x : arr)或for (const auto& x : arr)
迭代器遍历改值要解引用
用 begin()/end() 配合迭代器时,必须用 *it 获取可修改的左值。直接对迭代器变量赋值(如 it = 5)毫无意义,那是改迭代器本身,不是改它指向的元素。
对 std::vector 和 std::array 安全;但若在遍历中调用 push_back 或 erase,可能使迭代器失效,导致未定义行为。
- ✅ 安全修改:
for (auto it = v.begin(); it != v.end(); ++it) *it = *it + 1; - ⚠️ 危险操作:
for (auto it = v.begin(); it != v.end(); ++it) { v.push_back(42); *it = 0; }(push_back可能使it失效) - ? 提示:
std::vector::iterator本质是指针,*it就是*(it),和arr[i]底层一致
修改时注意类型和生命周期
真正让修改“生效”的前提是:目标内存可写、对象未被 const 限定、引用/指针没悬空。很多看似语法正确却没效果的情况,其实卡在语义层面。
比如把 std::vector<:string></:string> 的元素改成空字符串,实际是调用 std::string::operator=,涉及内存释放;而改 std::vector<bool></bool> 的某个位,底层是特化代理对象,*it = true 看似正常,但代理对象临时性容易引发意外。
- ✅ 普通情况:
int a[3] = {1,2,3}; for (int& x : a) x *= -1;—— 内存连续、类型平凡、无副作用 - ⚠️ 隐患点:
std::vector<bool> b(3); for (auto& x : b) x = true;</bool>——x是std::vector<bool>::reference</bool>临时对象,某些老编译器优化下可能不触发写入 - ? 绝对无效:
const int arr[] = {1,2,3}; for (auto& x : arr) x = 0;—— 编译失败,const修饰的是元素类型
改数组元素这件事,核心就一条:确保你操作的是原始内存位置的左值。语法糖再方便,绕不开这个前提。很多人卡在“写了却没变”,往往是因为没意识到自己其实在改副本、代理或已失效的引用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











