📄 一句话概括
goto 标签; —— 无条件跳转:跳到代码里某个带标签的位置,想跳哪跳哪。实例06 用 goto + if 手搓了一个循环(能算出 55,语法完全成立),但它把"跳来跳去"当成了循环结构。结论很干脆:认得它、别用它——结构化三件套(顺序/分支/循环)就是为取代它而生的。
📝 本节和前面几节的关系
5.2.2 的 for(;;) 变体在说"循环怎么写得紧凑",本篇说的是反例:用 goto 手工拼循环,写出来跟 for 一模一样的效果,却丢了"一眼看出结构"的好处。它和 break/continue 也完全不同:后两者是结构化的跳出(跳去哪里语言规定死),goto 的落点由你随便标。
一、实例 06:用 goto 实现循环
#include <iostream>
using namespace std;
int main() {
int i = 1, sum = 0;
loop: // 标签:goto 的落点
sum += i;
i++;
if (i <= 10) goto loop; // 还没数到 10,跳回标签
cout << "1 到 10 的累加结果是 " << sum << endl;
return 0;
}
看到什么算成功:输出 55,和实例01/03 结果一样——这正说明 goto 能替代循环,也正说明没必要:同样 4 行逻辑,用 for 写成 for (int i=1; i<=10; i++) sum += i;,读者一眼看出"从头数到 10 的循环";goto 版得靠人脑拼 loop: 和 goto loop; 的连线。
语法要点:标签就是一个标识符 + 冒号(loop:),可以起名、可以多个;goto 只能跳同一个函数里的标签,不能跨函数。
二、为什么"人见人嫌":三条硬伤
| 硬伤 | 说明 |
|---|---|
| 结构不可预测 | 编译器不报错,但读代码的人在 goto 处不知道接下来去哪;流程图会画成一团乱线("面条代码") |
| 容易绕过初始化 | 跳转落点之前若有必须的准备(变量初始化、资源打开),一跳就全跳过,行为诡异 |
| 难调试难维护 | 断点、单步执行的"顺着走"假设失效;改一处跳转,牵连一片 |
历史注脚:1968 年 Dijkstra 那篇著名的信《Goto 语句有害》推动了结构化编程——顺序、分支、循环三种结构足够表达一切逻辑,且保持"可读"。所以 goto 在教学书里只作为"了解"出现。
极少数合法场景(知道有这回事即可,本课不用):从多重嵌套的最内层一次性跳到函数尾部做统一清理。稳妥做法是多用函数拆分 + return,或标志变量逐层退。
三、常见误区
- "goto 能跨越函数"——不能,只能跳同一函数内的标签;跨函数是
return/函数调用的事。 - "标签可以写在任何语句前"——语法上可以,但跳到变量声明之后再用该变量是未定义行为;goto 与作用域天生不友好。
- "goto 更快/更灵活"——现代编译器对结构化代码的优化比手搓跳转好;灵活换来的是可读性崩盘,不划算。
自测三问(点开对答案)
1. `goto 标签;` 的执行效果?——无条件跳到同函数内该标签处,中间语句全部跳过。 2. 实例06 为什么说"没必要"?——同样逻辑 for/while 写得更短、结构一眼可见。 3. goto 能跳去另一个函数吗?——不能,只能在同一个函数内部跳。- ☐ 5.4 循环的嵌套(下一节)
相关笔记
- 循环控制 —— 四条路的全景
- for循环的变体 —— 结构化写法怎么替代它
- 🔷 C++基础 · 索引 —— 全课路线图