14. 循环结构(下):for循环、循环控制、无限循环与优化技巧
上一章我们聊了 while 和 do-while,今天来把循环剩下的内容一口气讲完。for 循环、break、continue、无限循环,还有我这些年积累的一些优化小窍门。嗯,这些内容在实际项目中几乎天天都要打交道。
14.1 for 循环:最常用的循环结构
说实话,for 循环是我用得最多的循环。为什么?因为它把初始化、条件判断、循环更新都写在一行里,结构清晰,不容易漏东西。
// 标准 for 循环语法
for (初始化表达式; 条件表达式; 更新表达式) {
循环体语句;
}
来看个实际例子。我在做数据采集项目时,经常需要遍历数组:
#include <stdio.h>
int main() {
int sensor_data[5] = {23, 45, 67, 12, 89};
// 遍历数组,找出最大值
int max = sensor_data[0];
for (int i = 1; i < 5; i++) {
if (sensor_data[i] > max) {
max = sensor_data[i];
}
}
printf("最大值是:%d\n", max);
return 0;
}
我个人习惯把循环变量 i 定义在 for 语句内部,这样它的作用域就限制在循环里,不会污染外部命名空间。你想想看,要是整个函数里到处都是 i、j、k,调试起来多头疼。
14.2 循环控制:break 和 continue
这两个关键字,说白了就是给循环装了个「急刹车」和「跳过键」。
14.2.1 break:跳出整个循环
break 用来提前终止循环。我在项目中遇到过这样一个场景:从传感器读取数据,读到异常值就立刻停止处理。
#include <stdio.h>
int main() {
int readings[] = {12, 15, 18, 99, 20, 22};
for (int i = 0; i < 6; i++) {
if (readings[i] > 50) {
printf("检测到异常值 %d,停止读取!\n", readings[i]);
break; // 跳出循环
}
printf("正常读数:%d\n", readings[i]);
}
return 0;
}
输出结果:
正常读数:12
正常读数:15
正常读数:18
检测到异常值 99,停止读取!
14.2.2 continue:跳过本次循环
continue 和 break 不一样。它不跳出循环,只是跳过当前这一次,继续下一次。我曾经在写数据过滤程序时用过它:
#include <stdio.h>
int main() {
int data[] = {3, -1, 5, 0, 7, -2, 9};
printf("过滤后的有效数据:");
for (int i = 0; i < 7; i++) {
if (data[i] <= 0) {
continue; // 跳过非正数
}
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
输出结果:
过滤后的有效数据:3 5 7 9
14.3 无限循环:什么时候用?怎么用?
无限循环,就是条件永远为真的循环。你可能会问:「这不会让程序卡死吗?」其实不会,只要我们在循环体里放一个 break 条件就行。
我常用的两种写法:
// 写法一:for 无限循环
for (;;) {
// 循环体
if (退出条件) {
break;
}
}
// 写法二:while 无限循环(我个人更常用这种)
while (1) {
// 循环体
if (退出条件) {
break;
}
}
为什么需要无限循环?举个真实例子。我在做嵌入式设备时,主程序就是一个无限循环:
#include <stdio.h>
#include <unistd.h> // sleep 函数
int main() {
while (1) {
// 1. 读取传感器数据
int temp = read_temperature();
// 2. 判断是否超温
if (temp > 80) {
printf("温度过高!触发报警!\n");
trigger_alarm();
}
// 3. 等待 1 秒再检测
sleep(1);
}
return 0;
}
你看,设备上电后就要一直运行,直到断电。这种场景用无限循环再合适不过了。
14.4 循环的优化技巧
做嵌入式开发,资源有限,循环优化是基本功。下面这几个技巧,都是我在实际项目中踩过坑之后总结出来的。
14.4.1 减少循环内的函数调用
把不变的表达式提到循环外面:
// ❌ 低效写法
for (int i = 0; i < strlen(str); i++) {
// 每次循环都调用 strlen,O(n²)
}
// ✅ 高效写法
int len = strlen(str);
for (int i = 0; i < len; i++) {
// 只调用一次 strlen,O(n)
}
14.4.2 使用前置递增
在 C++ 里,++i 比 i++ 效率高。C 语言中差别不大,但我习惯用 ++i:
// 推荐写法
for (int i = 0; i < 100; ++i) {
// ...
}
14.4.3 循环展开
对于循环次数固定的简单操作,可以手动展开,减少循环开销:
// 原始循环
for (int i = 0; i < 4; i++) {
a[i] = b[i] + c[i];
}
// 循环展开
a[0] = b[0] + c[0];
a[1] = b[1] + c[1];
a[2] = b[2] + c[2];
a[3] = b[3] + c[3];
14.5 知识体系总览
下面这张图把本章的核心内容串起来了,你可以对照着复习:
14.6 避坑指南
最后,分享几个我踩过的坑:
- 循环变量溢出:我曾经用 unsigned char 做循环变量,结果到 255 后变成 0,死循环了。记得选对数据类型。
- break 只跳一层:嵌套循环里想跳出多层?用 goto 或者加一个标志变量。
- continue 的位置:如果 continue 在循环尾之前,后面的代码会被跳过。我见过有人把资源释放写在 continue 后面,结果内存泄漏了。
好了,for 循环的内容就讲到这里。记住:多写、多练、多调试,循环这块就能拿捏得死死的。
公众号:蓝海资料掘金营,微信 deep3321