本文最后更新于 34 天前,其中的信息可能已经有所发展或是发生改变。
一、核心语法格式
for (元素类型 变量名 : 容器) {
// 循环体
}
记忆口诀:for (类型 名字 : 容器)
二、三种使用方式对比
| 写法 | 用途 | 能否修改原数据 | 效率 |
|---|---|---|---|
for (char c : s) | 只读遍历,创建副本 | ❌ 不能 | 较低(有拷贝开销) |
for (char& c : s) | 可修改遍历,引用原数据 | ✅ 能 | 高(无拷贝) |
for (const char& c : s) | 只读遍历,引用原数据 | ❌ 不能 | 高(无拷贝) |
三、在蓝桥杯中的经典应用场景
1. 统计字符频率(必会!)
unordered_map<char, int> mp;
string s = "hello";
for (char c : s) {
mp[c]++; // 一行搞定统计
}
2. 遍历并处理字符串
// 转为大写
string s = "hello";
for (char& c : s) { // 要用引用!
c = toupper(c);
}
3. 遍历vector/数组
vector<int> nums = {1, 2, 3, 4, 5};
int sum = 0;
for (int num : nums) {
sum += num;
}
4. 遍历map
unordered_map<string, int> scores = {{"Alice", 90}, {"Bob", 85}};
for (auto& pair : scores) { // pair是键值对
cout << pair.first << ": " << pair.second << endl;
}
四、与普通for循环的对比
场景:遍历字符串统计元音字母
普通for循环(C++98风格):
int count = 0;
for (int i = 0; i < s.length(); i++) {
char c = s[i];
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
count++;
}
}
范围for循环(C++11风格):
int count = 0;
for (char c : s) {
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
count++;
}
}
优点:
- ✅ 代码更简洁
- ✅ 不用处理下标,避免越界
- ✅ 意图更明确(”遍历每个元素”)
缺点:
- ❌ 拿不到当前下标
- ❌ 不能控制遍历步长(如i+=2)
五、蓝桥杯速记模板
模板1:字符串处理
// 只读遍历
for (char c : str) {
// 处理c
}
// 修改遍历
for (char& c : str) {
c = 处理(c);
}
模板2:容器遍历
// vector遍历
for (auto& num : vec) {
// 处理num
}
// map遍历
for (auto& [key, value] : mp) { // C++17结构化绑定
// 处理key和value
}
// 或
for (auto& pair : mp) {
// pair.first是key, pair.second是value
}
模板3:二维数组
vector<vector<int>> matrix;
for (auto& row : matrix) { // row是vector<int>&
for (int& num : row) { // 遍历每行
// 处理num
}
}
六、易错点提醒
❌ 错误写法1:需要下标时用范围for
string s = "hello";
for (char c : s) {
cout << "字符" << c << "的下标是?"; // 拿不到下标!
}
✅ 正确做法:用普通for
for (int i = 0; i < s.length(); i++) {
cout << "下标" << i << "的字符是" << s[i];
}
❌ 错误写法2:遍历时删除元素
vector<int> vec = {1, 2, 3, 4, 5};
for (int num : vec) {
if (num == 3) {
// 不能在范围for循环中删除!
// vec.erase(...) // 错误!
}
}
✅ 正确做法:用迭代器
for (auto it = vec.begin(); it != vec.end(); ) {
if (*it == 3) {
it = vec.erase(it);
} else {
++it;
}
}
七、选择使用哪种循环的建议
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 只需遍历元素,不要下标 | 范围for循环 | 简洁明了 |
| 需要下标 | 普通for循环 | 方便获取i |
| 需要修改元素 | 范围for循环 + 引用 | 简洁且高效 |
| 只读不修改 | 范围for循环 + const引用 | 高效安全 |
| 需要控制步长(如隔一个) | 普通for循环 | 方便控制i+=2 |
| 遍历时可能增删元素 | 迭代器循环 | 安全,不会失效 |
八、实战速查表
// 1. 字符串统计(最常用!)
for (char c : s) { mp[c]++; }
// 2. 修改字符串
for (char& c : s) { c = toupper(c); }
// 3. 只读高效遍历
for (const char& c : s) { /* 只读操作 */ }
// 4. 遍历vector计算
int sum = 0;
for (int num : nums) { sum += num; }
// 5. 遍历map
for (auto& [k, v] : mp) { cout << k << ":" << v; } // C++17
for (auto& p : mp) { cout << p.first << ":" << p.second; } // 通用
九、记忆技巧
一句话总结:
“用引用&才能改,不用&是拷贝,const引用最优选,只读场景效率高”
速记口诀:
范围for真方便,遍历容器很简单
char c : s遍历字符串,auto&遍历更通用
要修改就用引用&,只读就用const&
没下标需求就用它,代码简洁又安全
最终建议
对于蓝桥杯等算法竞赛:
- 优先使用范围for循环,代码更简洁
- 需要下标时用普通for循环
- 默认用
for (auto& x : container),需要时再加const - 记住
mp[c]++这个统计频率的神器组合
掌握了这个语法,你的代码会变得更加简洁优雅!加油!💪