第二节 自定义过程
自定义函数通常被设计成求一个函数值,一个函数只能得到一个运算结果。若要设计成能得到若干个运算结果,或完成一系列处理,就需要自定义“过程”来实现。
[例4.3]
把前面[例2.2 ](输入三个不同的整数,按由小到大排序)改为下面用自定义过程编写的Pascal程序:
Program exam43;
Var a,b,c:
integer;
Procedure Swap (var x,y:
integer); {自定义交换两个变量值的过程
}
Var t : integer;
Begin
{过程体}
t:=x; x:=y;
y:=t {交换两个变量的值
end;
Begin {主程序}
Write('input a,b,c=');
Readln(a,b,c);
if a>b
then swap (a,b); {调用自定义过程}
if a>c
then swap (a,c);
if b>c
fhen swap (b,c);
Writeln (a:6,
b:6, c:6);
Readln
End.
程序中Procedure Swap是定义过程名,从作用来看,过程与函数是相似的,都能将复杂的问题划分成一些目标明确的小问题来求解,只不过函数有值返回而过程则没有。自定义过程的一般格式如下:
Procedure
过程名 (形式参数表);
{过程首部}
局部变量说明部分;
begin
语句部分;
{过程体部分}
end;
[例4.4]如果一个自然数除了1和本身,还有别的数能够整除它,
这样的自然数就是合数。例如15,除了1和15,还有3和5能够整除,所以15是合数。14,15,16是三个连续的合数,试求连续十个最小的合数。
解:从14,15,16三个连续合数中可看出,它们正好是两个相邻素数13和17
之间的连续自然数,所以求连续合数问题可以转化为求有一定跨度的相邻两个素数的问题。因此,求连续十个最小的合数可用如下方法:
①从最小的素数开始,先确定第一个素数A;
②再确定与A相邻的后面那个素数B;(作为第二个素数);
③检查A,B的跨度是度否在10
以上,如果跨度小于10,就把B
作为新的第一个素数A,重复作步骤②;
④如果A、B跨度大于或等于10,就打印A、B之间的连续10个自然数,即输出
A+1, A+2, A+3
…,
A+10。
Pascal程序:
Program exam44;
var a,b,s,n:
integer;
yes: boolean;
procedure sub(x:
integer;var yy: boolean); {过程:求x是否为素数
}
var k,m:
integer; {
用yy逻辑值转出
}
begin
k:=trunc(sqrt(x));
for m:=3 to k
do
if odd(m) then
if x mod m=0 then
yy:=false;
end;
begin {主程序
}
b:=3;
repeat
a:=b;
{a
为第一个素数 }
repeat
yes:=true;
inc(b,2);
{b是a后面待求的素数}
sub(b,yes);
{调用SUB过程来确认b是否为素数
}
if yes then s:=b-a;
{如果b是素数,则求出跨度s
}
until yes;
until s > = 10;
for n:=a+1
to a+10 do
write(n:6);
writeln;
readln
end.
程序中的过程SUB,用来确定b是否为素数。过程名后面圆括号内的变量是形式参数,简称为形参。过程SUB(x:
integer; Var yy: boolean) 中的x是值形参,而前面冠有Var的yy是变量形参。值形参只能从外界向过程传入信息,但不能传出信息;变量形参既能传入又能传出信息。本程序过程SUB中的x是由调用过程的实在参数b传入值,进行处理后,不需传出;而yy是把过程处理结果用逻辑值传出,供调用程序使用。
试把[例4.3]程序中的过程
SWAP(Val x,y: integer),将x,y前面的Var去掉,就变成了纯粹的值形参,就不能将过程所处理的结果传出去,也就无法得到处理后的结果,通过运行程序比较,可以非常明显地看到值形参和变量形参的区别。
调用过程的格式为:
过程名(实在参数表) ;
调用过程名后面圆括号内的实在参数与定义过程的形参表必须相对应,调用过程相当于一个独立语句,可单独使用。
[例4.5]将合数483的各位数字相加(4+8+3)=15,如果将483分解成质因数相乘:
483=3*7*23,把这些质因数各位数字相加(3+7+2+3),其和也为15。即某合数的各位数字之和等于它所有质因数的各数字之和。求500以内具有上述特点的所有合数。
解:①设n为所要求的合数,让n在1~500间循环做以下步骤;
②用t1,t2分别累计合数n及n的质因数的各位数字之和,初值均为0;
③调用过程SUB3进行非素数判定,以布尔变量yes的真假值判定是否,yes的初值为true,如果为
(not true)非素数,就做步骤④,⑤,⑥;否则取新的n值,重复步骤③;
④调用SUB1,求n的各数字之和,传送给t1;
⑤调用SUB2,求n的各质因数,对于每个质因素都通过SUB1求它各位数字之和,将所有各质因数字传送给t2。
⑥如果t1=t2(各位数字之和等于它所有质因数的各数字之和),则输出此n。
PASCAL程序:
program exam45;
var n,t1,t2,tatol:
integer;
yes: boolean;
procedure sub1(x:integer;
var t:integer); {过程:分离x的各位数字
}
begin {并求各位数字之和
}
repeat
t:=t+x mod
10;
x:=x div 10;
until x=0
end;
procedure sub2(x:
integer; var t: integer); {过程:分解质因数
}
var xx,tt:integer;
begin
xx:=2;
while x>1 do
if x mod xx=0 then
begin
tt:=0;
sub1(xx,tt);
t:=t+tt;
x:=x div
xx
end
else inc(xx)
end;
procedure sub3(x:
integer;var yy: boolean); {过程:判断x是否为素数
}
var k,m:
integer;
begin
k:=trunc(sqrt(x));
for m:=2 to k
do
if x mod m=0 then
yy:=false;
end;
begin {主程序}
for n:=1 to
500 do
begin
t1:=0;t2:=0;
yes:=true;
sub3(n,yes);
{调用过程求素数
}
if not yes
then {如果非素数就…
}
begin
sub1(n,t1);
{调用过程求n的各位数字之和
}
sub2(n,t2);
{调用过程求n的各质因数的数字之和
}
if t1=t2
then write(n:6); {打印合格的合数
}
end
end;
readln
end.
程序定义了三个过程SUB1,SUB2,SUB3,其中SUB2过程中又调用了SUB1。在过程中定义的变量或参数,只在本过程内部使用有效。这些变量称为局部变量。如SUB2中的xx只在SUB2中使用,属于局部变量。
习题:4.2
1.输入自然数n,求前n个合数(非素数),其素因子仅有2,3,或5。
2.自然数a的因子是指能整除a的所有自然数,但不含a本身。例如12的因子为:1,2,3,4,6。若自然数a的因子之和为b,而且b的因子之和又等于a,则称a,b为一对“亲和数”
。求最小的一对亲和数。
3.求前n个自然数的平方和,要求不用乘法。例如:3的平方不用3*3,可用3+3+3。
4.试用容积分别为17升、13升的两个空油桶为工具,从大油罐中倒出15升油来,编程显示出具体的倒油过程。
5.如果一个数从左边读和从右边读都是同一个数,就称为回文数。例如6886就是一个回文数,求出所有的既是回文数又是素数的三位数。
6.
任何大于2的自然数都可以写成不超过四个平方数之和。如:
8=22+22;
14=12+22+32
由键盘输入自然数N(2
< N < 2000) ,输出其不超过四个平方数之和的表示式。 |