§7 过程、函数
Pascal语言实现结构化程序设计的主要手段之一是使用子程序——过程及函数,利用过程和函数,把程序中需要多次重复使用,且具有特定功能的程序段,单独编写成一个称为子程序的程序段,它存贮一次,但可以在程序的多个地方被调用,处理不同的数据。
§7.1 过 程 (子程序)
过程说明的一般形式:
procedure <过程名> (<参数表>); (说明部分); begin <语句>; …… <语句>; end;
其中procedure 是保留字,它说明这一段程序是过程,一个过程对应一个procedure。过程名是自定的标识符,程序通过过程名调用这段程序。参数表是用于向过程传递数据的变量的说明。说明部分则是过程内部所使用的变量的说明。
请分析下面程序的具体执行过程。 program ex1;
var u,v:integer;
procedure p1(x,y:integer); {过程说明} var i,j:integer; begin
for i:=1 to x do begin j:=y+i; write(j); end;
end;
Begin {主程序} u:=6; v:=5;
p1(u,v); {过程调用} writeln;
u:=u+v; v:=u*v; p1(u,v); {过程调用} write(‘end’); End.
分析如下: 程序从主程序的执行部分开始
① u←6 v←5
(过程调用)
――――――→ 参数传递: x ← u=6 y ← v=5 ② p1(u,v) 执行过程体,输出: 6 7 8 9 10 11
――――――→ 返回主程序调用处
(调用结束)
③ writeln;
④ u←6+5=11 v←11*5=55
(过程调用)
――――――→ 参数传递: x ← u=11 y ← v=55
⑤ p1(u,v) 执行过程体,输出: 56 57 58 59 60 61 62 63 64 65 66
――――――→ 返回主程序调用处
(调用结束)
⑥ 输出: end
以上例子仅说明过程在程序中如何说明和调用,有关参数的传递问题在下面细述: 1. 无参过程
过程中最简单的是无参过程,这种过程的首部只有过程名,而没有参数表部分。 【例1】利用过程画一条横线。
Program draws;
procedure line; {无参过程}
const length=10; var i : integer; begin
for i:=1 to length do write(‘-’); writeln; end; Begin line;
writeln (‘ Hello ! ’); line; End.
输出: ―――――――――― Hello!
――――――――――
无参过程只能执行一种固定的功能,如调用line过程时,只能固定地画出10个‘-’的横线,如果要在调用时能灵活地画出不同长度的横线,就必须运用有参过程。
2.有参过程
有参过程可以在每次调用时,根据不同的参数处理不同的数据,更大程度地发挥过程的优越性。
【例2】利用过程,按需要画出不同长度的横线。
Program drawline; var i,x,n:integer;
procedure line(length:integer); {有参过程,length为形式参数} var i:integer; begin
for i:=1 to length do write(‘-’); writeln; end; Begin
readln(n); {n为需要画的横线条数} for i:=1 to n do begin
readln(x); {x为每条横线的长度} if x<0 then line(0)
else if x>100 then line(100)
else line(x); {x为实际参数}
end; End.
运行结果: 3 ↙ 5 ↙
――――― -4 ↙ 8 ↙
―――――――― 上例过程是含有参数的过程,在过程说明时,过程名后参数表中的参数称为形式参数,而在调用过程时,过程名后括号中的参数称为实际参数。每次调用过程时,通过实际参数对形式参数进行赋值。实际参数对应于过程说明中的形式参数,实参和形参的个数、类型要一一对应。
3.值参数和变量参数
有三种类型的参数:值参、变参和无类型参数。
①当前面没有保留字var,后跟类型的参数称为值参数;如: procedure logon(x,y:real);
②当前面有保留字var,后跟类型的参数称为变量参数;如:
procedure ex(var ch:char);
③当前面有保留字var,但后不跟类型的参数称为无类型参数;如:
procedure sw(var a1,a2); 这里主要叙述值参数和变量参数。 请比较以下程序及运行结果: Program zc;
var n:integer;
procedure A(x:integer); var i:integer; begin
for i:=1 to x do write(‘-’); writeln; x:=x+10; end; Begin
read(n); A(n);
writeln(‘n=’,n); End. 运行结果: 5 ↙
――――― n=5
Program bc;
var n:integer;
procedure B(var x:integer); var i:integer; begin
for i:=1 to x do write(‘-’); writeln; x:=x+10; end; Begin
read(n); B(n);
writeln(‘n=’,n); End. 运行结果: 5 ↙
――――― n=15
值参数接受相应实际参数所传入的值,在过程A中,值参x的改变不会影响给它传递数值的实参n。调用过程时,值参数的形式单元直接接受相对应的实际参数的值,可称为输入参数,如图7.1_1所示。过程执行完,值参的值也不再保留,值参是这一过程的局部变量,仅在此过程内有意义,不能用它去传递过程的结果。
实际参数 n x 值参数 n x
5 5 5 图7.1_1
而变量参数在过程中的改变会直接影响给它传递数值的实际参数,即实数随时随着变参的变化而变化。因为实际参数给变参传递的是实参自身的地址,而不是数值,如图7.1_2所示,那么对变参的操作其实就是对变参的操作。
实际参数 n x 值参数
图7.1_2
5
4.全程变量和局部变量
在主程序的说明部分定义的变量,称为全程变量,它适用于整个程序,主程序以及它所包含的子程序都能对它进行存取访问。
在子程序的说明部分定义的变量,称为局部变量,它仅适用于相应的子程序,只允许在定义它的子程序范围内对它进行存取访问。
有些变量可能既在主程序中定义,又在子程序中定义,这种变量称为同名的全程变量和局部变量。程序运行时,在定义它的子程序中局部的那个变量起作用,在主程序及其它子程序中全程的那个变量起作用。因为它们占用不同的存贮单元,所以不会造成混乱。
【例3】下面的程序有两个过程,一个是求连续数的和,一个是求连续数的积。请通过这个程
序,比较全程变量和局部变量。 Program dd;
var x,n:integer; {x,n为全程变量} procedure sum; {连续求和}
var i:integer; {i为局部变量} begin x:=0;
for i:=1 to n do x:=x+i; end;
procedure pro; {连续求积}
var j:integer {j是局部变量} begin n:=1;
for j:=1 to x do n:=n*j; end;
Begin {主程序} readln(n); sum;
writeln(‘x1=’,x); pro;
writeln(‘n1=’,n); sum;
writeln(‘x2=’,x); End.
运行结果: 输入: 2
输出: x1 = 3 n1 = 6 x2 = 21