Procedures, functions and structured programming · 过程、函数与结构化编程
| English | 中文 | Pinyin · 拼音 |
|---|---|---|
| subroutines/ˈsʌbruːtiːnz/ | 子程序 | zi chéng xù |
| function/ˈfʌŋkʃn/ | 函数 | hán shù |
| procedure/prəˈsiːdʒə/ | 过程 | guò chéng |
| structured programming/ˈstrʌktʃəd ˈprəʊɡræmɪŋ/ | 结构化编程 | jié gòu huà biān chéng |
| decomposition/ˌdiːkɒmpəˈzɪʃn/ | 分解 | fēn jiě |
| parameters/pəˈræmɪtəz/ | 参数 | cān shù |
| arguments/ˈɑːɡjuːmənts/ | 实参 | shí cān |
| signature/ˈsɪɡnɪtʃə/ | 签名 | qiān míng |
| pass by value/pæs baɪ ˈvæljuː/ | 传值 | chuán zhí |
| pass by reference/pæs baɪ ˈrefrəns/ | 传引用 | chuán yǐn yòng |
| global variable/ˈɡləʊbl ˈveərɪəbl/ | 全局变量 | quán jú biàn liàng |
| local variable/ˈləʊkl ˈveərɪəbl/ | 局部变量 | jú bù biàn liàng |
| scope/skəʊp/ | 作用域 | zuò yòng yù |
A tape of routines anyone could borrow
- By 1951 the EDSAC team in Cambridge kept a library of subroutines on punched paper tape: square roots, printing, logarithms. Any program could read one in and call it.
- The hard part was getting back. David Wheeler's trick, the "Wheeler jump", stored the return address so a routine could return to wherever it had been called from.
- Every function call you write today does the same thing, and every language library descends from that tape.
- This lesson is procedures and functions: how to define them, how to pass values in and out, and how to write one the way Paper 2 marks it.
一卷任何人都能借用的例程带
- 到 1951 年,剑桥的 EDSAC 团队在穿孔纸带上保存着一个子程序库:开平方、打印、对数。任何程序都能把其中一个读进来并调用它。
- 难的是怎么回去。David Wheeler 的技巧——"Wheeler 跳转"——保存返回地址,让例程能回到它被调用的地方。
- 你今天写的每一次函数调用都在做同样的事,每一种语言的库都是那卷纸带的后代。
- 这一课讲过程和函数:怎样定义它们,怎样把值传进传出,以及怎样按 Paper 2 的评分方式写一个。
Procedures and functions
- Structured programming 结构化编程 builds a program from small named subroutines 子程序, each with one job.
- A procedure 过程 is a named block that does an action and returns nothing:
PROCEDURE Greet(Name : STRING) … ENDPROCEDURE, run withCALL Greet("Ada"). - A function 函数 returns a value that becomes part of an expression:
FUNCTION Square(X : INTEGER) RETURNS INTEGER … RETURN X * X … ENDFUNCTION, used asResult ← Square(5) + 1.
A procedure does something; a function hands back a value
过程和函数
- 结构化编程(structured programming)用小的、有名字的子程序(subroutines)搭建程序,每个只做一件事。
- 过程(procedure)是一个有名字的、执行动作但不返回值的代码块:
PROCEDURE Greet(Name : STRING) … ENDPROCEDURE,用CALL Greet("Ada")运行。 - 函数(function)返回一个值,这个值成为表达式的一部分:
FUNCTION Square(X : INTEGER) RETURNS INTEGER … RETURN X * X … ENDFUNCTION,用作Result ← Square(5) + 1。

过程做一件事;函数交回一个值
The call stack: push on call, pop on return · 调用栈:调用时压入,返回时弹出
Calling a subroutine pushes a new frame on top; returning pops it and hands a value back to the caller. The call that is running is always the frame on top. · 调用一个子程序把一个新的帧压到顶上;返回弹出它并把一个值交回给调用者。正在运行的调用总是顶上的那个帧。
The key difference between a procedure and a function is that a function: · 一个过程和一个函数之间的关键区别是一个函数:
A function returns a value (used in an expression); a procedure performs an action and returns nothing. · 一个函数返回一个值(在表达式中使用);一个过程执行一个动作并不返回任何东西。
A function Square(x) returns · 返回值 x * x. What does the call Square(5) return? · 一个函数 Square(x) 返回 x * x。调用 Square(5) 返回什么?
5 × 5 = 25 — the value the function hands back to its caller (the frame popped off the call stack). · 5 × 5 = 25——函数交回给它的调用者的值(从调用栈弹出的帧)。
Where each is appropriate
- A procedure where the same group of steps is needed at several points: validate an input, print a menu, swap two values. The steps are written once and called by name.
- A function where a single value must be calculated and then used in an expression: a total, a
TRUE/FALSEresult, the larger of two numbers. The return value replaces the call. - Use a subroutine when logic appears in more than one place, when a block has a clear named purpose, when the program is complex enough to need decomposition 分解, or when you want to test one piece on its own.
各自适用的地方
- 过程用于同一组步骤在多处需要的地方:验证输入、打印菜单、交换两个值。步骤写一次,按名字调用。
- 函数用于必须计算一个值然后在表达式中使用的地方:总和、
TRUE/FALSE结果、两个数中较大的那个。返回值取代调用。 - 当逻辑出现在多处、一个代码块有清晰的命名目的、程序复杂到需要分解(decomposition),或者你想单独测试一个部分时,使用子程序。
A good reason to write a subroutine is that: · 写一个子程序的一个好理由是:
Subroutines remove duplication, give a named purpose, and can be tested in isolation. · 子程序消除重复,给出一个命名的目的,并能被单独测试。
Parameters, arguments and the interface
- Parameters 参数 are the variables a subroutine declares to receive values; the values the caller supplies are the arguments 实参.
- The header is the first line:
PROCEDURE Name(Param : TYPE)orFUNCTION Name(Param : TYPE) RETURNS TYPE. The interface, or signature 签名, is the name, the parameters in order with their types, and the return type: everything a caller must know. - The return value is what a function passes back with
RETURN.
参数、实参和接口
- 参数(parameters)是子程序为接收值而声明的变量;调用者提供的值是实参(arguments)。
- 头部是第一行:
PROCEDURE Name(Param : TYPE)或FUNCTION Name(Param : TYPE) RETURNS TYPE。接口,或签名(signature),是名字、按顺序带类型的参数和返回类型:调用者必须知道的全部。 - 返回值是函数用
RETURN交回的东西。
Match each term to what it means. · 把每个术语与它的含义配对。
Function vs procedure = returns a value or not; by value vs by reference = copy or original. · 函数对过程 = 是否返回一个值;按值对按引用 = 副本还是原件。
Worked example: describe each term in a header
FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN.FUNCTION: a subroutine that returns a value.Pass2: the identifier used to call it.Count: the parameter, the identifier that receives the argument passed in.INTEGER: the data type of that parameter.RETURNS BOOLEAN: the data type of the value the function returns. Five parts, one mark each.
例题:描述头部里的每个术语
FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN。FUNCTION:一个返回值的子程序。Pass2:用来调用它的标识符。Count:参数,接收传入实参的标识符。INTEGER:该参数的数据类型。RETURNS BOOLEAN:函数返回值的数据类型。五个部分,各一分。
In FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN, the identifier Count is the ____. · 在 FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN 中,标识符 Count 是 ____。
The parameter receives the argument the caller passes in and is used inside the function like a local variable. · 参数接收调用者传入的实参,在函数里像局部变量一样使用。
Pass by value and pass by reference
- Pass by value 传值: the routine receives a copy, so changes inside it do not reach the caller. Use it for inputs the routine only reads.
- Pass by reference 传引用: the routine receives a reference to the caller's own variable, so changes do reach the caller. Use it when the routine must update the argument, as in
Swap. - Cambridge writes the mode in the header,
BYVALorBYREF, before each parameter. If neither is written,BYVALis assumed.
A copy, or a link to the caller's variable
传值和传引用
- 传值(pass by value):例程收到一份副本,所以里面的改变不会到达调用者。用于例程只读的输入。
- 传引用(pass by reference):例程收到调用者自己变量的引用,所以改变会到达调用者。当例程必须更新实参时使用,比如
Swap。 - 剑桥在头部每个参数前写出方式,
BYVAL或BYREF。两者都不写时,默认为BYVAL。

一份副本,或一条通向调用者变量的链接
Worked example: what is output?
Xis a reference toA, soAbecomes 8.Yis a copy ofB, so doublingYleavesBat 3.- The output is
8, 3. Had the header saidBYVAL X,Awould still be 5.
例题:输出是什么?
PROCEDURE Adjust(BYREF X : INTEGER, BYVAL Y : INTEGER)
X <- X + Y
Y <- Y * 2
ENDPROCEDURE
A <- 5
B <- 3
CALL Adjust(A, B)
OUTPUT A, B
X是对A的引用,所以A变成 8。Y是B的副本,所以把Y加倍不影响B,它仍是 3。- 输出是
8, 3。如果头部写的是BYVAL X,A仍会是 5。
In the worked example, what is the value of A after CALL Adjust(A, B)? · 在例题中,CALL Adjust(A, B) 之后 A 的值是多少?
X is passed BYREF, so X ← X + Y adds 3 to the caller's A: 5 + 3 = 8. B stays 3 because Y was a copy. · X 以 BYREF 传入,所以 X ← X + Y 把 3 加到调用者的 A 上:5 + 3 = 8。B 仍是 3,因为 Y 是副本。
Local and global variables
- A local variable 局部变量 is declared inside a subroutine and exists only while it runs; a global variable 全局变量 is declared outside and is visible everywhere. The region where a name is visible is its scope 作用域.
- Locals are preferred: the same identifier can be reused elsewhere without a clash, the value cannot be changed accidentally by other parts of the program, the memory is released on return, and the subroutine is self-contained.
- A local is created new on every call, so it cannot carry a value between calls. A routine that builds up a string over repeated calls needs that string to be global, or passed
BYREF.
A global is visible everywhere; a local lives only inside its own subroutine
局部变量和全局变量
- 局部变量(local variable)在子程序内部声明,只在它运行时存在;全局变量(global variable)在外部声明,处处可见。一个名字可见的区域是它的作用域(scope)。
- 优先用局部变量:同一个标识符可以在别处重用而不冲突,值不会被程序的其他部分意外改变,返回时内存被释放,子程序自成一体。
- 局部变量每次调用都重新创建,所以不能在两次调用之间保留值。一个在多次调用中累积字符串的例程需要那个字符串是全局的,或者用
BYREF传入。

全局变量处处可见;局部变量只活在自己的子程序里
A local variable exists only inside the subroutine where it is declared, while a global variable is visible everywhere in the program. · 一个局部变量只在它被声明的子程序里存在,而一个全局变量在程序中到处可见。
Keeping variables local limits their scope, avoids name clashes, and makes a subroutine testable on its own — globals are best avoided. · 把变量保持局部限制它们的作用域,避免名字冲突,并使一个子程序能自己测试——最好避免全局。
Which are benefits of using local variables? Select all · 所有 that apply. · 使用局部变量有哪些好处?选出所有适用的。
A local is created fresh on every call, so it cannot keep a value between calls. That is the one job a global, or a BYREF parameter, does instead. · 局部变量每次调用都重新创建,所以不能在调用之间保留值。那正是全局变量或 BYREF 参数才能做的事。
Turning a procedure into a function
- Change
PROCEDUREtoFUNCTIONand addRETURNS <type>to the header. - Replace the
OUTPUT, or theBYREFparameter that carried the result out, with aRETURNstatement. - Change every call so the returned value is used:
Result ← Unpack(Text)instead ofCALL Unpack(Text, Result).
把过程变成函数
- 把
PROCEDURE改成FUNCTION,并在头部加上RETURNS <type>。 - 用一条
RETURN语句取代OUTPUT,或取代把结果带出去的BYREF参数。 - 修改每一处调用,使用返回值:用
Result ← Unpack(Text)代替CALL Unpack(Text, Result)。
To convert a procedure into a function you change the header to FUNCTION with RETURNS, replace the OUTPUT with RETURN, and change the calls to use the returned value. · 把过程转成函数,要把头部改成带 RETURNS 的 FUNCTION,用 RETURN 取代 OUTPUT,并修改调用以使用返回值。
Three changes, three marks: the header, the RETURN, and the calls. · 三处修改,三分:头部、RETURN 和调用。
Worked example: writing a module for Paper 2
- A global array
Score : ARRAY[1:50] OF INTEGERholds test scores. Write a functionCountAbove(Limit : INTEGER)that returns how many scores are greater thanLimit.
- The scheme awards a mark per feature: the header with parameter and return type, the local declarations, the counter initialised before the loop, the loop over every element, the condition with the right comparison, the update inside it, the constructs closed, and one
RETURNafter the loop. - An unfinished module still scores for every correct part, so write all of them.
Each part of a module answer carries its own mark
例题:为 Paper 2 写一个模块
- 全局数组
Score : ARRAY[1:50] OF INTEGER保存考试分数。写一个函数CountAbove(Limit : INTEGER),返回有多少个分数大于Limit。
FUNCTION CountAbove(BYVAL Limit : INTEGER) RETURNS INTEGER
DECLARE Index, Count : INTEGER
Count <- 0
FOR Index <- 1 TO 50
IF Score[Index] > Limit THEN
Count <- Count + 1
ENDIF
NEXT Index
RETURN Count
ENDFUNCTION
- 评分标准按特征给分:带参数和返回类型的头部、局部声明、循环前初始化的计数器、遍历每个元素的循环、比较正确的条件、条件里面的更新、关闭的构造,以及循环后的一条
RETURN。 - 没写完的模块仍能为每个正确的部分得分,所以全部都要写。

模块答案的每个部分都有自己的分
Put the parts of a Paper 2 module answer in the order they are written. · 把 Paper 2 模块答案的各部分按书写顺序排列。
Header, declare, loop, condition, update, return. Each part is a mark, even if another part is wrong. · 头部、声明、循环、条件、更新、返回。每个部分都是一分,即使别的部分错了。
Marks that slip away
- A routine that must change the caller's variable needs
BYREFin its header; without itBYVALis assumed and the change is lost. - A function has one
RETURN, after the loop, andENDFUNCTION. ARETURNinside the loop ends it on the first element. DECLAREevery local, and initialise a counter or total to 0 before the loop.- "Efficient pseudocode" means moving work that does not change out of the loop, stopping a search at the first match, and not repeating a call whose result could be stored.
容易丢掉的分
- 必须改变调用者变量的例程,头部需要
BYREF;不写就默认为BYVAL,改变会丢失。 - 函数有一条
RETURN,在循环之后,然后是ENDFUNCTION。循环里面的RETURN会在第一个元素就结束它。 DECLARE每个局部变量,并在循环前把计数器或总和初始化为 0。- "高效的伪代码"意味着把不变的工作移出循环、在第一次匹配时停止搜索,以及不重复调用结果可以保存的函数。
To make a loop more efficient, a value that does not change with the loop counter should be: · 要让一个循环更高效,一个不随循环计数器改变的值应该被:
Hoisting a loop invariant out avoids recomputing the same value on every iteration. · 把一个循环不变量提出来避免在每次迭代重新计算同样的值。
You've got it
- a procedure does an action and is
CALLed; a function returns a value used in an expression - the header names the routine, its parameters with types and the return type; arguments are the values passed in
- BYVAL passes a copy (the default); BYREF lets the routine change the caller's variable
- prefer local variables; a local is new on every call, a global keeps its value
- a Paper 2 module: header, declarations, initialisation, loop, condition, update, closed constructs, one
RETURN
你掌握了
- 过程执行动作并被
CALL;函数返回一个在表达式中使用的值 - 头部给出例程名、带类型的参数和返回类型;实参是传入的值
- BYVAL 传副本(默认);BYREF 让例程改变调用者的变量
- 优先用局部变量;局部变量每次调用都是新的,全局变量保留它的值
- Paper 2 模块:头部、声明、初始化、循环、条件、更新、关闭的构造、一条
RETURN