一 : pascal-过程与函数
第十二课 过程与函数
前面我们曾经学习了程序设计中的三种基本控制结构(顺序、分支、循环)。[www.61k.com]用它们可以组成任何程序。但在应用中,还经常用到子程序结构。
通常,在程序设计中,我们会发现一些程序段在程序的不同地方反复出现,此时可以将这些程序段作为相对独立的整体,用一个标识符给它起一个名字,凡是程序中出现该程序段的地方,只要简单地写上其标识符即可。这样的程序段,我们称之为子程序。
子程序的使用不仅缩短了程序,节省了内存空间及减少了程序的编译时间,而且有利于结构化程序设计。因为一个复杂的问题总可将其分解成若干个子问题来解决,如果子问题依然很复杂,还可以将它继续分解,直到每个子问题都是一个具有独立任务的模块。这样编制的程序结构清晰,逻辑关系明确,无论是编写、阅读、调试还是修改,都会带来极大的好处。
在一个程序中可以只有主程序而没有子程序(本章以前都是如此),但不能没有主程序,也就是说不能单独执行子程序。pascal中子程序有两种形式:函数和过程。
一、函数
在此之前,我们曾经介绍并使用了pascal提供的各种标准函数,如ABS,SUCC等等,这些函数为我们编写程序提供了很大的方便。但这些函数只是常用的基本函数,编程时经常需要自定义一些函数。
(一)函数的说明
在pascal中,函数也遵循先说明后使用的规则,在程序中,函数的说明放在调用该函数的程序(主程序或其它子程序)的说明部分。函数的结构主程序的结构很相似。
函数定义的一般格式:
function <函数名> (<形式参数表>):<类型>; {函数首部}
说明:
①函数由首部与函数体两部分组成。
②函数首部以关键字function开头。
③函数名是用户自定义的标识符。
④函数的类型也就是函数值的类型,所求得的函数值通过函数名传回调用它的程序。可见,函数的作用一般是为了求得一个值。
⑤形式参数简称形参,形参即函数的自变量。自变量的初值来源于函数调用。在函数中,形参一般格式如下:
变量名表1:类型标识符1;变量名表2:类型标识符2;…;变量名表n:类型标识符n
可见形参表相当于变量说明,对函数自变量进行说明,但应特别注意:此处只能使用类型标识符,而不能直接使用类型。
⑥当缺省形参表(当然要同时省去一对括号)时,称为无参函数。
⑦函数体与程序体基本相似,由说明部分和执行部分组成。
⑧函数体中的说明部分用来对本函数使用的标号、常量、类型、变量、子程序加以说明,这些量只在本函数内有效。
⑨函数体的执行部分由begin开头,end结束,中间有若干用分号隔开的语句,只是end后应跟分号,不能像程序那样用句号"."。
⑩在函数体的执行部分,至少应该给函数名赋一次值,以使在函数执行结束后把函数值带回调用程序。
(二)函数的调用
我们可以在任何与函数值类型兼容的表达式中调用函数,或者说,函数调用只能出现在允许表达式出现的地方,或作为表达式的一个因子。 函数调用方式与标准函数的调用方式相同。
函数调用的一般格式:
<函数名>
或
<函数名>(实在参数表)
说明:①实在参数简称实参。实参的个数必须与函数说明中形参的个数一致,实参的类型与形参的类型应当一一对应。
②调用函数时,一般的,实参必须有确定的值。
③函数调用的步骤为:计算实参的值,"赋给"对应的形参;
(三)函数的应用举例
例1 求正整数A和B之间的完全数(A<B).
pascal函数 pascal-过程与函数
分析:所谓完全数是指它的小于该数本身的因子之和等于它本身,如6=1+2+3,6即是一个完全数。(www.61k.com]因此我们可定义一个布尔型函数perfect(x),若x是完全数,其值为TURE,否则为FALSE。整个程序算法如下: 1 for i:=A to B do
2 if perfect(i) then writeln(i);
源程序如下:
program ex7_1;
var
write('Input a,b:');
repeat {输入0<a<b}
{从 end.
自定义函数只是主程序的说明部分,若主程序中没有调用函数,则系统不会执行函数子程序。当主程序调用一次函数时,则将实在参数的值传给函数的形式参数,控制转向函数子程序去执行,子程序执行完毕后自动返回调用处。
补充:
若一个自然数,它所有的真因子(即除了自身以外的约数)的和恰好等于它本身,这种数叫做完全数。
完全数,又称完美数或完备数,是一些特殊的自然数:它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:第一个完全数是6,它有约数1、2、3、6,除去它本身6外,其余3个数相加,1+2+3=6。第二个完全数是28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4 + 7 + 14=28。后面的数是496、8128。 例如,
6=1+2+3
28=1+2+4+7+14
496=1+2+4+8+16+31+62+124+248
8128=1+2+4+8+16+32+64+127+254+508+1016+2032+4064
对于“4”这个数,它的真因子有1、2,其和是3。由于4本身比其真因子之和要大,这样的数叫做亏数。对于“12”这个数,它的真因子有1、2、3、4、6,其和是16。
pascal函数 pascal-过程与函数
由于12本身比其真因子之和要小,这样的数就叫做盈数。(www.61k.com]那么有没有既不盈余,又不亏欠的数呢?即等于它自己的所有真因子之和的数,这样的数就叫做完全数。
[编辑本段]
【性质】
完全数有许多有趣的性质:
⒈它们都能写成连续自然数之和。
如:6 = 1+2+3;
28 = 1+2+3+4+5+6+7;
496 = 1+2+3+……+30+31;
……
⒉它们的全部因数的倒数之和都是2,因此每个完全数都是调和数。
61阅读提醒您本文地址:
如:1/1+1/2+1/3+1/6=2;
1/1+1/2+1/4+1/7+1/14+1/28=2;
3.除了6之外,都有这样的一个性质:
如28,2+8=10,1+0=1;
496,4+9+6=19,1+9=10,1+0=1
二、过程
在pascal中,自定义过程与自定义函数一样,都需要先定义后调用。函数一般用于求值,而过程一般实现某些操作。
(一)过程的说明
过程说明的一般格式为:
procedure <过程名> (<形式参数表>); {过程首部}
说明: ①过程首部以关键字procedure开头。
②过程名是用户自定义的标识符,只用来标识一个过程,不能代表任何数据,因此不能说明"过程的类型"。
③形参表缺省(当然要同时省去一对括号)时,称为无参过程。
④形参表的一般格式形式如下:
[var] 变量名表:类型;…;[var] 变量名表:类型。
其中带var的称为变量形参,不带var的称为值形参。在函数中,形参一般都是值形参,很少用变量形参(但可以使用)。例如,下列形参表中:
(x,y:real;n:integer;var w:real;var k:integer;b:real)
x、y、n、b为值形参,而w、k为变量形参。
pascal函数 pascal-过程与函数
调用过程时,通过值形参给过程提供原始数据,通过变量形参将值带回调用程序。[www.61k.com)因此,可以说,值形参是过程的输入参数,变量形参是过程的输出参数。有关变参,这在后面内容具体叙述。
⑤过程体与程序、函数体类似。与函数体不同的是:函数体的执行部分至少有一个语句给函数名赋值,而过程体的执行部分不能给过程名赋值,因为过程名不能代表任何数据。
⑥过程体的说明部分可以定义只在本过程有效的标号、常量、类型、变量、子程序等。
(二)过程的调用
过程调用是通过一条独立的过程调用语句来实现的,它与函数调用完全不同。过程调用与调与标准过程(如write,read等)的方式相同。调用的一般格式为:
<过程名>
或
<过程名>(实在参数表)
说明: ①实参的个数、类型必须与形参一一对应。
②对应于值形参的实参可以是表达式,对应于变量形参的实参只能是变量。
③过程调用的步骤为:计算实参的值;将值或变量的"地址"传送给对应的形参;执行过程体;返回调用处。
过程与函数有下列主要区别:
①过程的首部与函数的首部不同;
②函数通常是为了求一个函数值,而过程可以得到若干个运算结果,也可用来完成一系列的数据处理,或用来完成与计算无关的各种操作;
③调用方式不同。函数的调用出现在表达式中,而过程调用是一个独立的语句。
(三)过程的应用举例
例2 输出以下一个图形:
*
**
***
****
*****
******
分析:我们前面学习可用的二重循环打印出上图形, 现我们设置一个过程打印出N个连续的"*"号。 源程序如下:
program ex7_2;
var i:integer;
procedure draw_a_line(n:integer); {该过程打印出连续n 个星号,并换行}
var j:integer;
begin
for j:=1 to n do
write('*');
writeln;
end;
begin
for i:=1 to 6 do
draw_a_line(i);{调用过程,第I行打印i个连续星号}
end.
三、过程、函数的数据传递
在程序调用子程序时,调用程序将数据传递给被调用的过程或函数,而当子程序运行结束后,结果又可以通过函数名、变参。当然也可以用全局变量等形式实现数据的传递。这一节我们,就来研究参数传递与局部变量、全局变量等问题。
(一)数值参数和变量参数
前面已经讲过,pascal子程序中形式参数有数值形参(简称值参)和变量形参(变参)两种。事实上,还有函数形参和过程形参两种,只是应用并不太多,我们不作深入地研究。
1、值形参
值参的一般格式如§7.1.1所示。应该强调的是:
pascal函数 pascal-过程与函数
①形参表中只能使用类型标识符,而不能使用类型。[www.61k.com)
②值形参和对应的实参必须一一对应,包括个数和类型。
③实参和值形参之间数据传递是单向的,只能由实参传送给形参,相当赋值运算。
④一个特殊情况是,当值形参是实型变量名时,对应的实参可以是整型表达式。
⑤值形参作为子程序的局部量,当控制返回程序后,值形参的存储单元释放。
2、变量形参
变量形参的一般格式如§7.2.1所示,必须在形参前加关键字var。
应该注意的是:
①与变量形参对应的实参只能是变量名,而不能是表达式。
②与变量形参对应的实参可以根据需要决定是否事先有值。
③变量形参与对应的实参的类型必须完全相同。
④对变量形参,运行时不另外开辟存储单元,而是与对应的实参使用相同的存储单元。也就是说,调用子程序时,是将实参的地址传送给对应的变量形参。
⑤当控制返回到调用程序后,变量形参的存储单元不释放,但变量形参本身无定义,即不得再使用。 ⑥选用形式参时,到底是使用值形参还是变量形参,应慎重考虑。值形参需要另开辟存储空间,而变量形参会带来一些副作用。一般在函数中使用值形参,而在过程中才使用变量形参,但也有例外。
例3 写出下列两个程序的运行结果。
program ex1; program ex2;
var a,b:integer; var a,b:integer;
procedure swap(x,y:integer); procedure swap(Var x,y:integer) ;
var t:integer; var t:integer;
begin begin
t:=x;x:=y;y:=t; t:=x;x:=y;y:=t;
end; end;
begin begin
a:=1;b:=2; a:=1;b:=2;
writeln(a:3,b:3); writeln(a:3,b:3);
swap(a,b); swap(a,b);
writeln(a:3,b:3); writeln(a:3,b:3);
61阅读提醒您本文地址:
end. end.
分析:这两个程序唯一的区别是ex1中将x,y作为值形参,而 ex2中将x,y作为变量形参,因此在ex2中对x,y的修改实际上是对调用该过程时与它们对应的变量a,b的修改,故最后,a,b的值为2,1。而ex1中调用swap过程时,只是将a,b的值传递给x,y,之后在过程中的操作与a,b无关。
答:ex1的运行结果为: ex2的运行结果为:
1 2 1 2
1 2 2 1
(二)全程变量、局部变量及它们的作用域
在主程序的说明部分和子程序的说明部分均可以说明变量,但它们的作用范围是特定的。
1、局部量及其作用域
在介绍过程和函数的说明时,我们曾指出,凡是在子程序内部作用的变量,应该在本子程序内加以说明。这种在子程序内部说明的变量称为局部变量。形式参数也只是在该子程序中有效,因此也属于局部变量。
一个变量的作用域是指在程序中能对此变量进行存取的程序范围。因此,局部变量的作用域就是其所在的子程序。实际上,局部变量只是当其所在的子程序被调用时才具有确定的存储单元,当控制从子程序返回到调用程序后,局部变量的存储单元就被释放,从而变得无定义。
事实上,在子程序内定义的标号、符号常量、类型、子程序也与局部变量具有相同的作用域。
2、全程量及其作用域
全程量是指在主程序的说明部分中说明的量。全程量的作用域分两种情况:
①当全程量和局部量不同名时,其作用域是整个程序范围(自定义起直到主程序结束)。
②当全程量和局部量同名时,全程量的作用域不包含局部量的作用域。
pascal函数 pascal-过程与函数
例4 写出下列程序的运行结果:
program ex7_4;
var x,y:integer;
procedure a;
var x:integer;
begin
x:=2;
writeln('#',x,'#');
writeln('#',y,'#');
end;{of a}
begin{main program}
x:=1;y:=2;
writeln('*',x,'*',y);
a;
writeln('***',x,'***',y);
end.
分析:程序中x,y是全局变量,但在过程a中也有变量x,故全程变量x的作用域为除过程a外的任何地方。(www.61k.com)而y的作用域包含了子程序a,即整个程序。
答:运行结果如下:
*1*2
#2#
#2#
***1***2
评注:变量作用域内对变量的操作都是对同一存储单元中的量进行的。
四、过程和函数的嵌套
Pascal语言中,使用过程和函数,能使程序设计简短,便于阅读,节省存贮单元和编译时间。程序往往设计成分层结构,由一个主程序和若干个过程及函数组成。在过程或函数中,还可以说明另一些过程或函数,即过程或函数可以分层嵌套。在同一层中亦可说明几个并列的过程或函数。例如:
上例过程的分层嵌套关系如下:0层主程序sample内并列两个1层过程P1a和P1b。过程P1a又嵌套两个2层过程p2a和p2b,2层的第二过程p2b又嵌套过程p3,p3就是第3层。其中p1b,p2a和p3不再嵌套别的过程,称为基本过程。这种分层结构的程序设计,特别要注意局部变量的使用范围和过程调用的要求。
在主程序sample中定义的变量,可以在所有的过程中使用,主程序可调用p1a和p1b两个过程。过程p1a中定义的变量,只能在p2a,p2b 和p3中使用。它能调用p2a,p2b两个过程,而不能调用p3和p1b。 在过程p1b中定义的变量,只能在p1b中使用,它只能调用过程p1a。过程p2a不能调用任何过程。过程p2b可以调用并列过程p2a和p3,而过程p3可以调用p2a过程。
过程调用是有条件的,过程定义在先,调用在后。同一层过程,后说明的过程可以调用先说明的过程。如果要调用在它后面定义的过程(或函数),可使用<向前引用>FORWARD这个扩充标识符。 要注意的是<向前引用>过程(或函数)首部中形式参数表写一次即可, 不必重复。如:
procedure extend(var a,b:integer);
forward;
表示过程extend<向前引用>。因此,过程extend 的说明部分只须如下书写:
procedure extend;
<说明部分>
begin
:
end;
五、子程序(模块化)结构的程序设计
例5 对6到60的偶数验证哥德巴赫猜想:不小于6的偶数可分解成两个素数之和。
分析:用布尔型函数prime(x)判断x是否是素数,若是, 函数值为真,否则,函数值为假。算法如下所示。
1. t:=6
pascal函数 pascal-过程与函数
2. while t≤60 do 3. t11; 4. repeat 5. t11+2; /* 找下一个素数a */ 6. until prime(t1)and prime(t-t1); /*直到a,b都是素数*/ 7. writeln(i,'=',t1,'+',t-t1); 8. tt+2; 9. endwhile 源程序如下: program ex9_7; var t,t1:integer; function prime(x:integer):boolean; var i:integer; begin if x=1 then prime:=false else if x=2 then prime:=true else begin prime:=true; i:=2; while (i<=round(sqrt(x)))and(x mod i<>0) do i:=i+1; if i<=round(sqrt(x)) then prime:=false; end; end;{of prime} begin t:=6; while t<=60 do begin t1:=1; repeat t1:=t1+2; until prime(t1) and prime(t-t1); writeln(t,'=',t1,'+',t-t1); t:=t+2; end; end. 例6 编写一个给一个分数约分的程序。(www.61k.com] 源程序如下: program ex7_6; ┌──变量参数 var a,b:integer; ↓ procedure common(var x,y:integer); var i,j,k:integer; begin {求x,y的最大公约数} i:=x;j:=y; repeat k:=i mod j; i:=j;j:=k; until k=0; {对x,y进行约分} x:=x div i;y:=y div i; end;
pascal函数 pascal-过程与函数
begin write('Input a,b=');readln(a,b); common(a,b); writeln(a,b:5); end. 如输入: Input a,b=12 8 则输出: 3 2
61阅读提醒您本文地址:
练习
1. 输入5个正整数求它们的最大公约数。(www.61k.com)(提示:可用一个数组将5个数存放起来,然后求第一个数和第二个数的公约数,再求第三个数与前两个数公约数的公约数,这样求得前三个整数最大公约数……如此类推可求出5个整数的最大公约数)
2. 给一维数组输入任意6个整数,假设为:
7 4 8 9 1 5
请建立一个具有以下内容的方阵:
7 4 8 9 1 5
4 8 9 1 5 7
8 9 1 5 7 4
9 1 5 7 4 8
1 5 7 4 8 9
5 7 4 8 9 1
(请用子程序编写)。
3. 求两个正整数的最小公倍数。
4. 输入一个任意位的正整数,将其反向输出。
5. 有五位同学,其各科成绩如下:
学号 数学 语文 英语 总分 名次
1 108 97 90
2 98 88 100
3 100 43 89
4 84 63 50
5 97 87 100
(1)编写一个过程enter,输入每个学生成绩并计算各人的总分。
(2)编写过程minci,用以排出每个人的名次。
(3)按学号顺序输出。
61阅读提醒您本文地址:
二 : pascal-过程与函数
第十二课 过程与函数
前面我们曾经学习了程序设计中的三种基本控制结构(顺序、分支、循环)。用它们可以组成任何程序。但在应用中,还经常用到子程序结构。
通常,在程序设计中,我们会发现一些程序段在程序的不同地方反复出现,此时可以将这些程序段作为相对独立的整体,用一个标识符给它起一个名字,凡是程序中出现该程序段的地方,只要简单地写上其标识符即可。这样的程序段,我们称之为子程序。
子程序的使用不仅缩短了程序,节省了内存空间及减少了程序的编译时间,而且有利于结构化程序设计。因为一个复杂的问题总可将其分解成若干个子问题来解决,如果子问题依然很复杂,还可以将它继续分解,直到每个子问题都是一个具有独立任务的模块。这样编制的程序结构清晰,逻辑关系明确,无论是编写、阅读、调试还是修改,都会带来极大的好处。
在一个程序中可以只有主程序而没有子程序(本章以前都是如此),但不能没有主程序,也就是说不能单独执行子程序。pascal中子程序有两种形式:函数和过程。
一、函数
在此之前,我们曾经介绍并使用了pascal提供的各种标准函数,如ABS,SUCC等等,这些函数为我们编写程序提供了很大的方便。但这些函数只是常用的基本函数,编程时经常需要自定义一些函数。
(一)函数的说明
在pascal中,函数也遵循先说明后使用的规则,在程序中,函数的说明放在调用该函数的程序(主程序或其它子程序)的说明部分。函数的结构主程序的结构很相似。
函数定义的一般格式:
function <函数名> (<形式参数表>):<类型>; {函数首部}
说明:
①函数由首部与函数体两部分组成。
②函数首部以关键字function开头。
③函数名是用户自定义的标识符。
④函数的类型也就是函数值的类型,所求得的函数值通过函数名传回调用它的程序。可见,函数的作用一般是为了求得一个值。
⑤形式参数简称形参,形参即函数的自变量。自变量的初值来源于函数调用。在函数中,形参一般格式如下:
变量名表1:类型标识符1;变量名表2:类型标识符2;…;变量名表n:类型标识符n
可见形参表相当于变量说明,对函数自变量进行说明,但应特别注意:此处只能使用类型标识符,而不能直接使用类型。
⑥当缺省形参表(当然要同时省去一对括号)时,称为无参函数。
⑦函数体与程序体基本相似,由说明部分和执行部分组成。
⑧函数体中的说明部分用来对本函数使用的标号、常量、类型、变量、子程序加以说明,这些量只在本函数内有效。
⑨函数体的执行部分由begin开头,end结束,中间有若干用分号隔开的语句,只是end后应跟分号,不能像程序那样用句号"."。
⑩在函数体的执行部分,至少应该给函数名赋一次值,以使在函数执行结束后把函数值带回调用程序。
(二)函数的调用
我们可以在任何与函数值类型兼容的表达式中调用函数,或者说,函数调用只能出现在允许表达式出现的地方,或作为表达式的一个因子。 函数调用方式与标准函数的调用方式相同。
函数调用的一般格式:
<函数名>
或
<函数名>(实在参数表)
说明:①实在参数简称实参。实参的个数必须与函数说明中形参的个数一致,实参的类型与形参的类型应当一一对应。
②调用函数时,一般的,实参必须有确定的值。
③函数调用的步骤为:计算实参的值,"赋给"对应的形参;
(三)函数的应用举例
例1 求正整数A和B之间的完全数(A<B).
分析:所谓完全数是指它的小于该数本身的因子之和等于它本身,如6=1+2+3,6即是一个完全数。因此我们可定义一个布尔型函数perfect(x),若x是完全数,其值为TURE,否则为FALSE。整个程序算法如下: 1 for i:=A to B do
2 if perfect(i) then writeln(i);
源程序如下:
program ex7_1;
var
write('Input a,b:');
repeat {输入0<a<b}
{从 end.
自定义函数只是主程序的说明部分,若主程序中没有调用函数,则系统不会执行函数子程序。当主程序调用一次函数时,则将实在参数的值传给函数的形式参数,控制转向函数子程序去执行,子程序执行完毕后自动返回调用处。
补充:
若一个自然数,它所有的真因子(即除了自身以外的约数)的和恰好等于它本身,这种数叫做完全数。
完全数,又称完美数或完备数,是一些特殊的自然数:它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:第一个完全数是6,它有约数1、2、3、6,除去它本身6外,其余3个数相加,1+2+3=6。第二个完全数是28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4 + 7 + 14=28。后面的数是496、8128。 例如,
6=1+2+3
28=1+2+4+7+14
496=1+2+4+8+16+31+62+124+248
8128=1+2+4+8+16+32+64+127+254+508+1016+2032+4064
对于“4”这个数,它的真因子有1、2,其和是3。由于4本身比其真因子之和要大,这样的数叫做亏数。对于“12”这个数,它的真因子有1、2、3、4、6,其和是16。
由于12本身比其真因子之和要小,这样的数就叫做盈数。那么有没有既不盈余,又不亏欠的数呢?即等于它自己的所有真因子之和的数,这样的数就叫做完全数。
[编辑本段]
【性质】
完全数有许多有趣的性质:
⒈它们都能写成连续自然数之和。
如:6 = 1+2+3;
28 = 1+2+3+4+5+6+7;
496 = 1+2+3+……+30+31;
……
⒉它们的全部因数的倒数之和都是2,因此每个完全数都是调和数。
如:1/1+1/2+1/3+1/6=2;
1/1+1/2+1/4+1/7+1/14+1/28=2;
3.除了6之外,都有这样的一个性质:
如28,2+8=10,1+0=1;
496,4+9+6=19,1+9=10,1+0=1
二、过程
在pascal中,自定义过程与自定义函数一样,都需要先定义后调用。函数一般用于求值,而过程一般实现某些操作。
(一)过程的说明
过程说明的一般格式为:
procedure <过程名> (<形式参数表>); {过程首部}
说明: ①过程首部以关键字procedure开头。
②过程名是用户自定义的标识符,只用来标识一个过程,不能代表任何数据,因此不能说明"过程的类型"。
③形参表缺省(当然要同时省去一对括号)时,称为无参过程。
④形参表的一般格式形式如下:
[var] 变量名表:类型;…;[var] 变量名表:类型。
其中带var的称为变量形参,不带var的称为值形参。在函数中,形参一般都是值形参,很少用变量形参(但可以使用)。例如,下列形参表中:
(x,y:real;n:integer;var w:real;var k:integer;b:real)
x、y、n、b为值形参,而w、k为变量形参。
调用过程时,通过值形参给过程提供原始数据,通过变量形参将值带回调用程序。因此,可以说,值形参是过程的输入参数,变量形参是过程的输出参数。有关变参,这在后面内容具体叙述。
⑤过程体与程序、函数体类似。与函数体不同的是:函数体的执行部分至少有一个语句给函数名赋值,而过程体的执行部分不能给过程名赋值,因为过程名不能代表任何数据。
⑥过程体的说明部分可以定义只在本过程有效的标号、常量、类型、变量、子程序等。
(二)过程的调用
过程调用是通过一条独立的过程调用语句来实现的,它与函数调用完全不同。过程调用与调与标准过程(如write,read等)的方式相同。调用的一般格式为:
<过程名>
或
<过程名>(实在参数表)
说明: ①实参的个数、类型必须与形参一一对应。
②对应于值形参的实参可以是表达式,对应于变量形参的实参只能是变量。
③过程调用的步骤为:计算实参的值;将值或变量的"地址"传送给对应的形参;执行过程体;返回调用处。
过程与函数有下列主要区别:
①过程的首部与函数的首部不同;
②函数通常是为了求一个函数值,而过程可以得到若干个运算结果,也可用来完成一系列的数据处理,或用来完成与计算无关的各种操作;
③调用方式不同。函数的调用出现在表达式中,而过程调用是一个独立的语句。
(三)过程的应用举例
例2 输出以下一个图形:
*
**
***
****
*****
******
分析:我们前面学习可用的二重循环打印出上图形, 现我们设置一个过程打印出N个连续的"*"号。 源程序如下:
program ex7_2;
var i:integer;
procedure draw_a_line(n:integer); {该过程打印出连续n 个星号,并换行}
var j:integer;
begin
for j:=1 to n do
write('*');
writeln;
end;
begin
for i:=1 to 6 do
draw_a_line(i);{调用过程,第I行打印i个连续星号}
end.
三、过程、函数的数据传递
在程序调用子程序时,调用程序将数据传递给被调用的过程或函数,而当子程序运行结束后,结果又可以通过函数名、变参。当然也可以用全局变量等形式实现数据的传递。这一节我们,就来研究参数传递与局部变量、全局变量等问题。
(一)数值参数和变量参数
前面已经讲过,pascal子程序中形式参数有数值形参(简称值参)和变量形参(变参)两种。事实上,还有函数形参和过程形参两种,只是应用并不太多,我们不作深入地研究。
1、值形参
值参的一般格式如§7.1.1所示。应该强调的是:
①形参表中只能使用类型标识符,而不能使用类型。
②值形参和对应的实参必须一一对应,包括个数和类型。
③实参和值形参之间数据传递是单向的,只能由实参传送给形参,相当赋值运算。
④一个特殊情况是,当值形参是实型变量名时,对应的实参可以是整型表达式。
⑤值形参作为子程序的局部量,当控制返回程序后,值形参的存储单元释放。
2、变量形参
变量形参的一般格式如§7.2.1所示,必须在形参前加关键字var。
应该注意的是:
①与变量形参对应的实参只能是变量名,而不能是表达式。
②与变量形参对应的实参可以根据需要决定是否事先有值。
③变量形参与对应的实参的类型必须完全相同。
④对变量形参,运行时不另外开辟存储单元,而是与对应的实参使用相同的存储单元。也就是说,调用子程序时,是将实参的地址传送给对应的变量形参。
⑤当控制返回到调用程序后,变量形参的存储单元不释放,但变量形参本身无定义,即不得再使用。 ⑥选用形式参时,到底是使用值形参还是变量形参,应慎重考虑。值形参需要另开辟存储空间,而变量形参会带来一些副作用。一般在函数中使用值形参,而在过程中才使用变量形参,但也有例外。
例3 写出下列两个程序的运行结果。
program ex1; program ex2;
var a,b:integer; var a,b:integer;
procedure swap(x,y:integer); procedure swap(Var x,y:integer) ;
var t:integer; var t:integer;
begin begin
t:=x;x:=y;y:=t; t:=x;x:=y;y:=t;
end; end;
begin begin
a:=1;b:=2; a:=1;b:=2;
writeln(a:3,b:3); writeln(a:3,b:3);
swap(a,b); swap(a,b);
writeln(a:3,b:3); writeln(a:3,b:3);
end. end.
分析:这两个程序唯一的区别是ex1中将x,y作为值形参,而 ex2中将x,y作为变量形参,因此在ex2中对x,y的修改实际上是对调用该过程时与它们对应的变量a,b的修改,故最后,a,b的值为2,1。而ex1中调用swap过程时,只是将a,b的值传递给x,y,之后在过程中的操作与a,b无关。
答:ex1的运行结果为: ex2的运行结果为:
1 2 1 2
1 2 2 1
(二)全程变量、局部变量及它们的作用域
在主程序的说明部分和子程序的说明部分均可以说明变量,但它们的作用范围是特定的。
1、局部量及其作用域
在介绍过程和函数的说明时,我们曾指出,凡是在子程序内部作用的变量,应该在本子程序内加以说明。这种在子程序内部说明的变量称为局部变量。形式参数也只是在该子程序中有效,因此也属于局部变量。
一个变量的作用域是指在程序中能对此变量进行存取的程序范围。因此,局部变量的作用域就是其所在的子程序。实际上,局部变量只是当其所在的子程序被调用时才具有确定的存储单元,当控制从子程序返回到调用程序后,局部变量的存储单元就被释放,从而变得无定义。
事实上,在子程序内定义的标号、符号常量、类型、子程序也与局部变量具有相同的作用域。
2、全程量及其作用域
全程量是指在主程序的说明部分中说明的量。全程量的作用域分两种情况:
①当全程量和局部量不同名时,其作用域是整个程序范围(自定义起直到主程序结束)。
②当全程量和局部量同名时,全程量的作用域不包含局部量的作用域。
例4 写出下列程序的运行结果:
program ex7_4;
var x,y:integer;
procedure a;
var x:integer;
begin
x:=2;
writeln('#',x,'#');
writeln('#',y,'#');
end;{of a}
begin{main program}
x:=1;y:=2;
writeln('*',x,'*',y);
a;
writeln('***',x,'***',y);
end.
分析:程序中x,y是全局变量,但在过程a中也有变量x,故全程变量x的作用域为除过程a外的任何地方。而y的作用域包含了子程序a,即整个程序。
答:运行结果如下:
*1*2
#2#
#2#
***1***2
评注:变量作用域内对变量的操作都是对同一存储单元中的量进行的。
四、过程和函数的嵌套
Pascal语言中,使用过程和函数,能使程序设计简短,便于阅读,节省存贮单元和编译时间。程序往往设计成分层结构,由一个主程序和若干个过程及函数组成。在过程或函数中,还可以说明另一些过程或函数,即过程或函数可以分层嵌套。在同一层中亦可说明几个并列的过程或函数。例如:
上例过程的分层嵌套关系如下:0层主程序sample内并列两个1层过程P1a和P1b。过程P1a又嵌套两个2层过程p2a和p2b,2层的第二过程p2b又嵌套过程p3,p3就是第3层。其中p1b,p2a和p3不再嵌套别的过程,称为基本过程。这种分层结构的程序设计,特别要注意局部变量的使用范围和过程调用的要求。
在主程序sample中定义的变量,可以在所有的过程中使用,主程序可调用p1a和p1b两个过程。过程p1a中定义的变量,只能在p2a,p2b 和p3中使用。它能调用p2a,p2b两个过程,而不能调用p3和p1b。 在过程p1b中定义的变量,只能在p1b中使用,它只能调用过程p1a。过程p2a不能调用任何过程。过程p2b可以调用并列过程p2a和p3,而过程p3可以调用p2a过程。
过程调用是有条件的,过程定义在先,调用在后。同一层过程,后说明的过程可以调用先说明的过程。如果要调用在它后面定义的过程(或函数),可使用<向前引用>FORWARD这个扩充标识符。 要注意的是<向前引用>过程(或函数)首部中形式参数表写一次即可, 不必重复。如:
procedure extend(var a,b:integer);
forward;
表示过程extend<向前引用>。因此,过程extend 的说明部分只须如下书写:
procedure extend;
<说明部分>
begin
:
end;
五、子程序(模块化)结构的程序设计
例5 对6到60的偶数验证哥德巴赫猜想:不小于6的偶数可分解成两个素数之和。
分析:用布尔型函数prime(x)判断x是否是素数,若是, 函数值为真,否则,函数值为假。算法如下所示。
1. t:=6
2. while t≤60 do 3. t11; 4. repeat 5. t11+2; /* 找下一个素数a */ 6. until prime(t1)and prime(t-t1); /*直到a,b都是素数*/ 7. writeln(i,'=',t1,'+',t-t1); 8. tt+2; 9. endwhile 源程序如下: program ex9_7; var t,t1:integer; function prime(x:integer):boolean; var i:integer; begin if x=1 then prime:=false else if x=2 then prime:=true else begin prime:=true; i:=2; while (i<=round(sqrt(x)))and(x mod i<>0) do i:=i+1; if i<=round(sqrt(x)) then prime:=false; end; end;{of prime} begin t:=6; while t<=60 do begin t1:=1; repeat t1:=t1+2; until prime(t1) and prime(t-t1); writeln(t,'=',t1,'+',t-t1); t:=t+2; end; end. 例6 编写一个给一个分数约分的程序。 源程序如下: program ex7_6; ┌──变量参数 var a,b:integer; ↓ procedure common(var x,y:integer); var i,j,k:integer; begin {求x,y的最大公约数} i:=x;j:=y; repeat k:=i mod j; i:=j;j:=k; until k=0; {对x,y进行约分} x:=x div i;y:=y div i; end;
三 : Pascal 标准函数
1.算术函数
函数标识符 自变量类型 意义 结果类型
abs 整型、实型 绝对值 同自变量
abs(-7.49)=7.49
arctan 整型、实型 反正切 实型
arctan(0)=0.0
cos 整型、实型 余弦 实型
cos(pi)=-1.0
sin 整型、实型 余弦 实型
sin(pi)= 0
exp 整型、实型 指数 实型
frac 整型、实型 小数部分 实型
frac(-3.71)=-0.71
int 整型、实型 整数部分 实型
int(-3.71)=-3.0
ln 整型、实型 自然对数 实型
pi 无自变量 圆周率 实型
sqr 整型、实型 平方 同自变量
sqr(4)=16
sqrt 整型、实型 平方根 实型
sqrt(4)=2
2.标量函数
函数标识符 自变量类型 意义 结果类型
odd 整型 判断奇数 布尔型
odd(1000)=false
odd(3)=true
pred 离散类型 求前趋 同自变量
pred(2000)=1999
pred('x')='w'
succ 离散类型 求后继 同自变量
succ(2000)=2001
succ('x')='y'3.
转换函数
函数标识符 自变量类型 意义 结果类型
chr byte型 自量对应的字符 字符型
ord 离散类型 自量对应的序号 longint
round 实型 四舍五入 longint
trunc 实型 截断取整 longint
杂类函数
函数标识符 自变量类型 意义 结果类型
random 无自变量 [0,1)之间的随机实数 real
random word [0,自变量)之间的随机整数 wird
randomize 无自变量 用一随机值初始化内部随机数产生器 longint
upcase 字符型 使小写英文字母变为大写 字符型
div整除整型整型
mod取余整型整型
<> 不等于 简单类型 布尔型
算术表达式中各个运算符的次序为: ( )-->函数-->*,/,div,mod-->+,1
(1)字符串函数
函数名 自变量及类型 意义 结果类型
concat s1[,s2……,sN]:string 连接字符串序列 string
copy s:string,index,count:integer 返回串s的一个子串 string
length s:string 返回串s的动态长度 integer
pos substr,s:string 返回子串substr在串s中的起始位置 byte
(1)字符串过程
过程名 自变量及类型 意义
delete var s,source:string;index,count:integer 从串S中删除一个子串
insert var s:string;index:integer; 在串S中插入一个指定子串
str var x[:width[:Decimals]];s:string 把一数值转换成相应的字符串表示
val var s:string;code:integer 把一字符串转换成相应的数值
1.值参数
形式参数表中前面没有var,后有类型的参数。[www.61k.com)它类似过程和函数的局部变量,仅为过程和函数的执行提供初值而不影响调用时实际参数的值。在调用过程或应用函数时,值参数所对应的实际参数必须是表达式,而且它的值不能使文件类型或包括文件类型的值。实参必须和形参赋值相容。
2.变量参数
形式参数表中前面有var后由类型的参数。如果需要子程序向调用程序返回值时,应采用变量参数。变量参数要求它的实参是和它同一类型的变量。因为在子程序执行时,遇到对相应形参的引用式定值,就是对相应实参的引用式定值,即对形参的任何操作就是对实参本身的操作。
3.无类型变量参数
形式参数表中前面有var而后面没有类型的参数。形参是无类型变量,对应的实参允许为任意类型的变量,但要在子程序中设置的强制类型转换(类型名(无类型变量参数名)),将无类型变量参数改变为相应类型。
4.子程序参数
用过程首部或函数首部作为形式参数。
其中nil是Turbo Pascal保留字,表示“空”,相当于C里面的null
类型文件扩展:pascal字符串函数 / pascal函数 / pascal函数大全
end.
文本文件
文本文件的内容有ASCII字符集中的字符组成,因此文本文件也称ASCII码文件,它可以用DOS中的type命令列出内容。文本文件具体是由一系列行组成,每一行可以包括0个或多个字符型成分,并以也行结束符结尾,文本文件类型TXT和类型文件file of char区别在于后者不包含行结束符。
文本文件和类型文件在读写上的差别在于前者只能按次序顺序读写,而后者可以不按照次序读写。适用文本文件的函数和过程除了用于类型文件操作的过程和函数外主要还有:
(1)readln过程
形式:readln(f,var表);或readln(f);
功能:从磁盘文件f中,将数据依次读到var表表示的各变量中(其中readln(f)只读数据),并将文件指针移到行结束符后,就是下一行开头。
(2)writeln过程
形式:writeln(f,var表)或writeln(f);
功能:将var表所表示的各个变量的值依次写到磁盘文件f上去(writeln(f)不写值),然后再写一个行结束符。
(3)append过程
形式:append(f);
功能:打开一个已经存在的磁盘文件,其文件名必须和assign过程中的变量名f相对应,该文件只能写,此时文件指针指向文件尾。
(4)eoln函数
形式:eoln(f);
功能:若文件指针指向行结束符或文件结束符,则返回true,否则返回false。
对文本文件的写操作步骤:
assign(f,str);
rewrite(f); 或append(f);
write(f,var表);或writeln(f);
close(f);
对文本文件的读操作步骤:
assign(f,str);
reset(f);
readln(f,var表);或readln(f);
close(f);
例:随机产生30个随机整数存放于文本文件zhoufei.txt 中
program zhoufei;
const n=30;
var ra:text;
i:integer;
begin
randomize;
assign(ra,'zhoufei,txt');
rewrite(ra);
for i:=1 to n do writeln(ra,random(100));
close(ra)
end.
扩展:pascal字符串函数 / pascal函数 / pascal函数大全
本文标题:pascal函数-pascal-过程与函数61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1