📄 一句话概括
嵌套调用 = 函数里再调用别的函数。它带来一条必须记牢的顺序规律——先进后出:最内层的函数最先执行完,然后一层层往外返回,像剥洋葱。进入时一层层往里钻,出来时一层层往外走,整个形状是一座对称的山。
📝 本节和前面几节的关系
6.3.1 讲了"跳进去、跳回来",这一节讲"跳进去之后又跳进别处"。它把 6.3 那个"调用栈"的机制用起来了:每跳进一个函数就在栈上记一笔,返回时按记住的顺序倒着来。搞懂这一节,下一节的递归才不会晕。
一、什么叫嵌套调用
void c() { cout << "C 干活" << endl; } // 第三层
void b() { cout << "B 开始"; c(); cout << "B 结束"; } // 第二层,调 C
void a() { cout << "A 开始"; b(); cout << "A 结束"; } // 第一层,调 B
int main() { a(); } // 起点
输出顺序是:
A 开始
B 开始
C 干活
B 结束
A 结束
规律:进入时一层层往下钻,出来时一层层往上返——这就是"先进后出"(也叫后进先出)。
二、为什么必须先进后出(回看调用栈)
把 6.3 的"记位置"想象成一摞便签:
| 动作 | 便签堆 |
|---|---|
main 调 a |
记下"main 停在 a() 这一行" |
a 调 b |
再记下"a 停在 b() 这一行" |
b 调 c |
再记下"b 停在 c() 这一行" |
c 返回 |
撕掉最上面一张,回到 b |
b 返回 |
再撕一张,回到 a |
a 返回 |
再撕一张,回到 main |
谁最后进去,谁最先出来——所以输出的形状必然是对称的。这不是巧合,是调用栈的物理属性。
三、嵌套调用的常见样子
| 场景 | 例子 |
|---|---|
| 分层处理 | main → processAll() → processOne() |
| 工具函数复用 | printMenu() 里调 printLine()(6.2.1 的 Demo 就是这么干的) |
| 表达式里层层调用 | max(max(a, b), c) —— 这是写法上的嵌套,调用关系也是两层的 |
| 递归 | 自己调自己——嵌套调用最特殊的一种(6.3.3) |
四、动手 Demo:三层嵌套看顺序
#include <iostream>
using namespace std;
void level3() { cout << " 第三层:干活" << endl; }
void level2() {
cout << " 第二层:开始" << endl;
level3();
cout << " 第二层:结束" << endl;
}
void level1() {
cout << " 第一层:开始" << endl;
level2();
cout << " 第一层:结束" << endl;
}
int main() {
cout << "main:开始" << endl;
level1();
cout << "main:结束" << endl;
return 0;
}
看到什么算成功:
main:开始
第一层:开始
第二层:开始
第三层:干活
第二层:结束
第一层:结束
main:结束
用缩进看形状:前三行一层比一层深(往里钻),后三行一层比一层浅(往外返)——一座对称的山。
30 秒实验:
1. 把 level3() 的调用搬到 level1 的末尾,看输出形状怎么变——"嵌套"改的是深度,不是行数。
2. 在 level2() 里调用两次 level3(),观察那座"山"变成什么样(两个小尖峰)。
这个"看形状"的习惯,将来调试复杂程序时非常有用。
五、常见误区
- "嵌套调用就是在一行里塞很多括号"——不是。嵌套调用说的是"函数里调函数"(关系);一行里写很多层括号说的是"表达式嵌套"(写法)。两者可以同时出现,但不是一回事。
- "被调用的函数必须定义在调用者前面"——不必,有声明就行(6.1.2)。但定义顺序清晰更好读:习惯上把最底层的小工具写在前面。
- "嵌套层数越多越厉害"——反了,层数多意味着"读懂一处逻辑要翻好几个函数"(耦合高)。3 层以内最舒服,超过就该想怎么拆。
- "嵌套调用和递归是一回事"——不是。嵌套是"A 调 B",递归是"A 调 A"。
⚠️ 必须记的一个坑:写嵌套调用时函数名别写错成自己——一旦某个函数体内直接调用了它自己,就变成了无限递归,程序会因栈溢出直接崩溃。编译器通常不报错,只在运行时炸,这就是 6.3.3 要专门讲的事。
自测三问(点开对答案)
1. 嵌套调用的执行顺序规律是什么?——先进后出:进入时一层层往里钻,返回时一层层往外返。 2. 为什么是这个顺序?——每次调用都在调用栈上记一笔,返回时必须按倒序撕掉。 3. 嵌套调用和递归的区别?——嵌套是"A 调 B",递归是"A 调 A"。- ☐ 6.3.3 递归调用(下一节)
相关笔记
- 传值调用 —— 跳进去时带的是复印件
- 函数调用 —— 调用栈的第一次登场
- 空函数 —— Demo 里
printMenu调printLine - 🔷 C++基础 · 索引 —— 全课路线图