这套练习覆盖整个程序结构模块:数据类型、局部与全局作用域、参数、返回值,以及把逻辑与输入输出分开。所有程序和数值都是虚构的。
题目由易到难。先写出你的答案,再打开解答。追踪表都完整列出,方便你逐行对照。追踪题可以用受限伪代码追踪训练器,安全 Python 推理沙盒可以用来核对结果,失误请记在错题记录与重测队列里。
题目
1. 为下列各项选择最合适的数据类型:(a) 礼堂的座位数,(b) 温度 31.5,(c) 票号 “0045”,(d) 单个回答 ‘Y’ 或 ‘N’,(e) 是否在下雨。
显示答案
(a) INTEGER,整数计数。(b) REAL,带小数部分。(c) STRING,因为不参与计算,而且开头的零必须保留。(d) CHAR,单个字符。(e) BOOLEAN,只有 TRUE 或 FALSE。
2. 某程序保存 15 / 4 的结果。写出这个值以及需要的数据类型。
显示答案
15 / 4 = 3.75。结果带小数部分,所以需要 REAL。INTEGER 变量无法存放 3.75。
3. 写出输出。
Count ← 10
PROCEDURE Change()
DECLARE Count : INTEGER
Count ← 99
ENDPROCEDURE
CALL Change()
OUTPUT Count
显示答案
过程声明了自己的局部 Count 并把它设为 99。全局的 Count 是另一个变量,仍然是 10。输出是 10。
4. Count 在主程序中声明。Temp 在过程 Calc 内声明。指出各自是局部还是全局,并说明 Calc 运行之后主程序能否输出 Temp。
显示答案
Count 是全局变量。Temp 是 Calc 的局部变量。主程序不能输出 Temp,因为局部变量在过程结束时就不存在了。
5. 写一个函数 Area,接收两个 REAL 参数 Length 和 Width,返回它们的乘积(REAL)。写出 Area(4.5, 2) 的值。
显示答案
FUNCTION Area(Length : REAL, Width : REAL) RETURNS REAL
RETURN Length * Width
ENDFUNCTION
Area(4.5, 2) 返回 4.5 × 2 = 9.0。
6. 追踪函数,写出 RepeatAdd(6, 4) 返回的值。
FUNCTION RepeatAdd(A : INTEGER, B : INTEGER) RETURNS INTEGER
DECLARE Result : INTEGER
Result ← 0
FOR I ← 1 TO B
Result ← Result + A
NEXT I
RETURN Result
ENDFUNCTION
显示答案
| I | Result |
|---|---|
| 开始 | 0 |
| 1 | 6 |
| 2 | 12 |
| 3 | 18 |
| 4 | 24 |
函数返回 24,即 6 × 4。
7. 这个函数本应让 SumTo(3) 返回 1 + 2 + 3。写出它实际返回什么,并加以改正。
FUNCTION SumTo(N : INTEGER) RETURNS INTEGER
DECLARE Total : INTEGER
Total ← 0
FOR I ← 1 TO N
Total ← Total + I
RETURN Total
NEXT I
ENDFUNCTION
显示答案
RETURN 在循环里面,所以第一圈 Total 变成 0 + 1 = 1,函数随即结束,返回 1。
改正:把 RETURN Total 移到 NEXT I 之后。这样 Total 依次是 1、3、6,函数返回 6。
8. 下面的函数按百分比降低价格。写出 Discount(80, 25) 的值,然后解释把实参换成 Discount(25, 80) 会怎样。
FUNCTION Discount(Price : REAL, Percent : REAL) RETURNS REAL
RETURN Price - Price * Percent / 100
ENDFUNCTION
显示答案
Discount(80, 25):80 × 25 / 100 = 20,80 − 20 = 60。
Discount(25, 80):Price 是 25,Percent 是 80。25 × 80 / 100 = 20,25 − 20 = 5。实参按位置对应形参,所以顺序弄反会得到错误答案,而且没有任何错误提示。
9. 写一个函数 ToFahrenheit,接收 REAL 类型的摄氏温度,返回 摄氏温度 × 9 / 5 + 32。给出 30 和 100 的结果。
显示答案
FUNCTION ToFahrenheit(Celsius : REAL) RETURNS REAL
RETURN Celsius * 9 / 5 + 32
ENDFUNCTION
30:30 × 9 = 270,270 / 5 = 54,54 + 32 = 86。100:100 × 9 = 900,900 / 5 = 180,180 + 32 = 212。函数里没有 INPUT 或 OUTPUT,这些由主程序负责。
10. 写出输出。
FUNCTION Score(Correct : INTEGER, Wrong : INTEGER) RETURNS INTEGER
RETURN Correct * 3 - Wrong
ENDFUNCTION
A ← Score(8, 2)
B ← Score(5, 5)
OUTPUT A + B
显示答案
Score(8, 2) = 8 × 3 − 2 = 24 − 2 = 22,所以 A = 22。Score(5, 5) = 15 − 5 = 10,所以 B = 10。输出是 22 + 10 = 32。
11. 对下面每项任务,说明用过程还是函数更合适,并给出理由:(a) 显示一行欢迎语,(b) 计算含 8% 服务费的账单,并把总额交回给调用者。
显示答案
(a) 用过程:它只是做一件事,没有值要送回。(b) 用函数:调用者需要总额,所以使用 RETURN。服务费在函数里加上,怎样显示结果由主程序决定。
12. 写出输出,并解释为什么第二次调用不是从 0 开始。
DECLARE Count : INTEGER
Count ← 0
FUNCTION Next(Step : INTEGER) RETURNS INTEGER
Count ← Count + Step
RETURN Count
ENDFUNCTION
DECLARE A : INTEGER
DECLARE B : INTEGER
A ← Next(2)
B ← Next(3)
OUTPUT A + B
显示答案
Count 是全局变量,所以改动在多次调用之间保留。第一次调用:Count = 0 + 2 = 2,返回 2,所以 A = 2。第二次调用:Count = 2 + 3 = 5,返回 5,所以 B = 5。输出是 2 + 5 = 7。
这样写行得通,但让函数依赖了全局变量,而这正是本模块建议避免的习惯。更干净的设计是把当前计数作为参数传入。
如果你做错了
把每种错误对应到相应的课,重做那一课的自测,几天后再试这道题。
| 错误类型 | 去看 |
|---|---|
| 类型选错,尤其是把编码存成数字(1、2) | 选择合适的数据类型 |
| 局部或全局变量的输出或可见性(3、4、12) | 局部与全局作用域 |
| 参数顺序或函数头部(5、8、11) | 构建参数清晰的子程序 |
| 追踪后数值出错、过早 RETURN(6、7、10) | 追踪返回值 |
| 把计算与输入输出混在一起(9、11) | 把逻辑与输入输出分开 |
如果你的错误分散在好几课,我们Computer Science 补习的一对一老师可以帮你排出优先顺序。