Appearance
题目
已知程序如下:
c
int S(int n) {
return (n <= 0) ? 0 : S(n - 1) + n;
}
void main() {
cout << S(1);
}程序运行时使用栈来保存调用过程的信息,自栈底到栈顶保存的信息依次对应的是( )。
错因
B
把方向读反了——B 是自栈顶到栈底(也就是出栈顺序)。S(0) 是递归底,最先 return、最先出栈,所以它在栈顶;main 最先入栈、压在最底。题目问的是"自栈底到栈顶",应从 main 写起。先返回的恰恰是最晚进栈的,B 把整个序列倒了过来。
C
记得 main 在栈底(最先入栈),但把 S(1) 与 S(0) 的先后弄反了。S(0) 是 S(1) 内部调用产生的——必须先有 S(1) 在栈上、走到 S(n-1)+n 这一步才能调 S(0)。所以 S(1) 一定先于 S(0) 入栈,位置应在 S(0) 下面(更靠栈底)。选 C 的人可能直觉上觉得"参数小的先来",但函数调用顺序是由调用关系决定的,不看参数大小。
D
漏了 main 这一帧。程序入口就是 main,main 的活动记录最先压栈、压在栈最底,最后才弹出。任何函数调用都是在 main 已经在栈上的前提下发生的——栈底必然是 main。把 main 排在最后等于把它扔到了栈顶,与"程序入口最先入栈"矛盾。
总解析
关键概念:每次函数调用,系统会为该调用分配一个活动记录(也叫栈帧)压入运行时栈,记录返回地址、参数、局部变量等。函数返回时弹出该帧。栈遵循 LIFO:先进的压在底,后进的盖在顶。
本题的调用链(按时间顺序):
- 程序启动 → 进入
main(),main 的活动记录入栈(位于栈底)。 - main 执行
cout << S(1)→ 调用S(1),S(1) 的活动记录入栈(压在 main 上方)。 - 在 S(1) 内:
n=1>0,求值S(n-1)+n=S(0)+1→ 调用S(0),S(0) 的活动记录入栈(压在 S(1) 上方,此时位于栈顶)。 - S(0) 内:
n=0≤0,返回 0 → S(0) 出栈。 - S(1) 拿到 0,计算
0+1=1,返回 1 → S(1) 出栈。 - main 输出 1,结束 → main 出栈。
S(0) 调用瞬间,栈的快照(自下而上):
| 位置 | 帧 |
|---|---|
| 栈顶 | S(0) |
| 中间 | S(1) |
| 栈底 | main() |
自栈底到栈顶 依次是:
方向陷阱:题目问"自栈底到栈顶" = 入栈顺序 = main 在前。选项 B 给的是反方向(自栈顶到栈底,也就是出栈顺序),正好对应"先 return 的先写"。读题先认准"栈底/栈顶"或"进栈/出栈",方向反了立刻全错。
最终答案是 A(main() → S(1) → S(0))。