作用域(scope)说明变量在程序中的哪些位置可以使用。全局变量(global variable)属于主程序。局部变量(local variable)属于某一个子程序,子程序结束后它就不存在了。
本课属于程序结构模块。它承接选择数据类型,并为构建子程序做准备。考试可能要你判断变量是局部还是全局,追踪同时用到两者的程序,或解释为什么局部变量是好习惯。
怎样区分局部和全局?
看变量在哪里声明。
- 在主程序中、所有子程序之外声明:全局。程序的每个部分都可以读取和修改它。
- 在子程序内声明:局部。只有该子程序能用,而且每次调用子程序时都会重新创建。
- 子程序括号里的参数,对该子程序来说也相当于局部变量。
可以把全局变量想成教室里的白板,把局部变量想成你自己笔记本的一页。谁都可以在白板上写字,而笔记本那一页只有你用,每节课还会换新的一页。
例题
追踪下面的程序,并写出输出。
DECLARE Total : INTEGER
Total ← 0
PROCEDURE AddPoints(Points : INTEGER)
DECLARE Bonus : INTEGER
Bonus ← 5
Total ← Total + Points + Bonus
ENDPROCEDURE
CALL AddPoints(10)
CALL AddPoints(20)
OUTPUT Total
这里 Total 是全局变量。Points 和 Bonus 是 AddPoints 的局部变量。
| 步骤 | Points | Bonus | Total |
|---|---|---|---|
| 开始 | 尚未创建 | 尚未创建 | 0 |
| CALL AddPoints(10) | 10 | 5 | 0 + 10 + 5 = 15 |
| CALL AddPoints(20) | 20 | 5 | 15 + 20 + 5 = 40 |
| 调用结束后 | 已消失 | 已消失 | 40 |
输出是 40。Bonus 在每次调用时都会重新创建,所以第二次调用开始时 Bonus 是新的 5,而不是上次留下来的值。Total 因为是全局变量,所以一直保留。
最常见的错误是什么?
**错误答案:**在两次调用之后,在程序末尾加一句
OUTPUT Bonus。这是错误。
Bonus是AddPoints的局部变量,过程结束后就不存在了,主程序看不到它。
把值从子程序里取出来有两种正确做法:在子程序内部输出,或者用函数把它返回。返回值会在追踪返回值中讲。
第二个错误是以为与全局变量同名的局部变量会改变全局变量。如果过程自己声明了一个 Total,全局的 Total 完全不受影响。
自测
1. 在上面的例子中,指出哪些变量是局部的,哪些是全局的。
显示答案
全局:Total。AddPoints 的局部变量:Points 和 Bonus。
2. 写出输出。
X ← 3
PROCEDURE Test()
DECLARE X : INTEGER
X ← 8
ENDPROCEDURE
CALL Test()
OUTPUT X
显示答案
过程声明了自己的局部 X,并设为 8。全局的 X 从未被修改,所以主程序输出 3。
3. 给出程序员更喜欢局部变量的一个理由。
显示答案
局部变量不会被程序其他地方意外修改,所以出错时更容易找到。另一个有效理由:同一个名字可以在不同子程序里重复使用而不冲突。
接下来学什么?
作用域告诉你子程序能看到什么。下一步是构建参数清晰的子程序,让它通过参数拿到所需的数据,而不是去伸手拿全局变量。你可以用受限伪代码追踪训练器练习填写上面那样的表格,再用安全 Python 推理沙盒核对同样的逻辑。
如果你希望有人看着你追踪,在出错的第一行就提醒你,可以找一对一线上计算机科学补习的老师。