流程控制:程序的“交通指挥员”
大家好,我是你们的老朋友。今天我们来聊聊C++和Qt里的流程控制。说白了,就是教程序“什么时候该做什么事”。
我刚开始学编程时,觉得这玩意儿特简单。不就是if-else嘛,谁不会啊?结果后来写了个复杂的业务逻辑,嵌套了七八层if,自己都看晕了。嗯,从那以后我才明白——流程控制写得好不好,直接决定代码是“艺术品”还是“垃圾堆”。
核心思想:程序默认是顺序执行的——从上往下,一行一行跑。流程控制就是打破这种顺序,让程序能“思考”、能“循环”、能“跳转”。
1. if/else:最常用的“岔路口”
if/else 就像你走到一个岔路口。条件成立走左边,不成立走右边。你想想看,生活中到处都是这种选择。
int score = 85;
if (score >= 60) {
cout << "及格了,不错!" << endl;
} else {
cout << "不及格,继续努力!" << endl;
}
我个人习惯把 if 后面的花括号直接写在同行,这样代码更紧凑。当然也有人喜欢换行,这个看团队规范。
小技巧:如果只有一条语句,可以省略花括号。但我建议永远不要省——我踩过这个坑,后来加代码时忘了加括号,结果逻辑全乱了。
多分支时用 else if:
if (score >= 90) {
cout << "优秀" << endl;
} else if (score >= 80) {
cout << "良好" << endl;
} else if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
注意:else 总是匹配最近的 if。我曾经见过一个bug,就是因为else匹配错了,排查了一下午。建议多用花括号明确范围。
2. switch:多路选择的“高速公路”
当你有多个固定值要判断时,switch 比 if-else 更清晰。它就像高速公路上的出口指示牌——根据你的出口号直接拐出去。
int day = 3;
switch (day) {
case 1:
cout << "周一" << endl;
break;
case 2:
cout << "周二" << endl;
break;
case 3:
cout << "周三" << endl;
break;
default:
cout << "其他" << endl;
break;
}
这里有个关键点——break 不能忘。忘了 break 就会“穿透”到下一个 case。有时候我们故意利用这个特性,比如多个 case 共享同一段代码:
switch (grade) {
case 'A':
case 'B':
cout << "通过" << endl;
break;
case 'C':
case 'D':
cout << "补考" << endl;
break;
}
我的经验:switch 只适合判断整型、字符型、枚举型。别拿它判断字符串——那是 if-else 的活。
3. while 和 do-while:循环的两种“姿势”
while 循环:先判断,再执行。条件不满足,一次都不跑。
int i = 0;
while (i < 5) {
cout << i << " ";
i++;
}
// 输出:0 1 2 3 4
do-while 循环:先执行一次,再判断。至少跑一次。
int i = 0;
do {
cout << i << " ";
i++;
} while (i < 5);
// 输出:0 1 2 3 4
有什么区别?你想想看——如果条件一开始就不成立,while 直接跳过,do-while 至少执行一次。我在项目中用 do-while 的场景不多,但处理用户输入验证时特别好用:
int choice;
do {
cout << "请输入1-3之间的数字:";
cin >> choice;
} while (choice < 1 || choice > 3);
避坑指南:我曾经写过一个 while 循环,忘了更新循环变量,结果死循环了。程序卡死,CPU 飙到100%。嗯,从那以后我每次写循环都先检查“退出条件会不会变”。
4. for 循环:最常用的“计数循环”
for 循环是 C++ 里最灵活的循环。它把初始化、条件判断、变量更新都写在一行:
for (int i = 0; i < 10; i++) {
cout << i << " ";
}
// 输出:0 1 2 3 4 5 6 7 8 9
三个部分都可以省略,但分号不能省:
int i = 0;
for (; i < 10; ) {
cout << i << " ";
i++;
}
我个人习惯用 for 循环遍历数组或容器:
int arr[] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
C++11 之后有了范围 for 循环,更简洁:
for (int x : arr) {
cout << x << " ";
}
核心区别:for 循环适合“知道要循环多少次”的场景,while 适合“不知道次数,只知道条件”的场景。
5. break 和 continue:循环里的“刹车”和“跳过”
break:立即跳出整个循环。continue:跳过本次循环的剩余部分,进入下一次。
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 到5就停,输出:0 1 2 3 4
}
cout << i << " ";
}
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数,输出:1 3 5 7 9
}
cout << i << " ";
}
注意:break 只跳出当前一层循环。嵌套循环里想跳出外层?要么用 goto,要么用标志变量。我建议用标志变量——goto 容易把代码搞乱。
6. goto:被“妖魔化”的跳转
很多教材说“goto 是魔鬼,永远别用”。我不完全同意。goto 确实容易写出“意大利面条式代码”,但有些场景它确实方便。
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (someCondition) {
goto cleanup;
}
}
}
cleanup:
cout << "跳出双层循环" << endl;
我在项目中用过一次 goto——处理多层循环里的错误清理。当时用标志变量要写好几行,goto 一行搞定。但说实话,能用其他方式就别用 goto。
我的建议:goto 可以用,但仅限于“向前跳转”清理资源。别用它向后跳——那才是真正的“魔鬼”。
知识体系总览
下面这张图总结了本章的流程控制结构:
总结对比表
| 控制结构 | 适用场景 | 执行次数 | 注意事项 |
|---|---|---|---|
| if/else | 条件分支,范围判断 | 0或1次 | 注意else匹配,多用花括号 |
| switch | 多值匹配(整型/枚举) | 0或1次 | 别忘了break,小心穿透 |
| for | 已知循环次数 | 0~N次 | 循环变量别在内部修改 |
| while | 未知次数,已知条件 | 0~N次 | 小心死循环 |
| do-while | 至少执行一次 | 1~N次 | 条件写在后面 |
| break | 提前退出循环 | 0或1次 | 只跳出当前一层 |
| continue | 跳过本次循环 | 0~N次 | 注意循环变量更新 |
| goto | 多层跳出/错误处理 | 0或1次 | 尽量不用,用标志变量替代 |
好了,流程控制就讲到这里。这些东西看着简单,但写代码时处处都是坑。我建议你每学一个结构,就写几个小例子跑一跑。代码这东西,光看是学不会的。
一句话总结:if/else 做选择,for/while 做循环,break/continue 做控制,goto 做最后的“救命稻草”。