570 likes | 747 Views
过程与函数. 过程和函数. 顺序结构. 程 序 的基本结构. 程序设计的基本思想:. 自顶向下、逐步求精. 选择结构. 循环结构. 程序的模块化. 过程和函数. 说明: 程序中可以只有主程序而没有子程序,但不能没有主程序,也就是说不能单独执行子程序。. 结构化程序设计思想:. 方法 1 、模块化: (1) 把一个较大的程序划分为若干子程序,每一个子程序独立成为一个模块; (2) 每一个模块又可继续划分为更小的子模块; (3) 程序具有一种层次结构。 注:运用这种编程方法,考虑问题必须先进行整体分析,避免边写边想。. 结构化程序设计思想:.
E N D
过程和函数 顺序结构 程 序 的基本结构 程序设计的基本思想: 自顶向下、逐步求精 选择结构 循环结构 程序的模块化 过程和函数 说明:程序中可以只有主程序而没有子程序,但不能没有主程序,也就是说不能单独执行子程序。
结构化程序设计思想: 方法1、模块化:(1)把一个较大的程序划分为若干子程序,每一个子程序独立成为一个模块;(2)每一个模块又可继续划分为更小的子模块;(3)程序具有一种层次结构。 注:运用这种编程方法,考虑问题必须先进行整体分析,避免边写边想。
结构化程序设计思想: 方法2、自顶向下:(1)先设计第一层(即:顶层),然后步步深入,逐层细分,逐步求精,直到整个问题可用程序设计语言明确地描述出来为止。(2)步骤:首先对问题进行仔细分析,确定其输入、输出数据,写出程序运行的主要过程和任务;然后从大的功能方面把一个问题的解决过程分成几个问题,每个子问题形成一个模块。 (3)特点:先整体后局部,先抽象后具体。
结构化程序设计思想: 方法3、自底向上:(1)先设计底层,最后设计顶层;(2)优点:由表及里、由浅入深地解决问题; (3)不足:在逐步细化的过程中可能发现原来的分解细化不够完善;(4)注意:该方法主要用于修改、优化或扩充一个程序。
标准函数有: abs(x)/ sqrt(x)/ round(x)… X:=abs(-10); Y:=sqrt(81); Z:=round(35.9); 标准函数的调用
例1-1:编程求12+22+...+1002的和 例2_1:编程求1!+2!+3!+...+10!的和。 PROGRAM sum(input,output); VAR i:integer; s:longint; BEGIN s:=0; for i:=1 to 100 do s:=s+sqr(i) ; fac(i) writeln('s=',s); END.
一、函数的定义及调用 函数首部 Function 函数名(形参表):函数类型; 局部变量说明; begin 语句1; …; 函数名:=表达式; end; 函数的类型 函数体 将函数值传递给函数名 注意:自定义函数先定义后使用。 函数值通过函数名传送回调用程序。 在表达式中调用:函数名(实参) 如:x= Abs(n) abs为函数名,n为实参,函数类型为integer or real
例2-2 编写一个求n!的函数fac. 形式参数 函数首部 function fac(n:integer):longint; var k:integer; t:longint; begin t:=1; for k:=2 to n do t:=t*k; fac:=t; end; {endfac} 函数的结果类型 局部变量说明 函数说明 函数执行部分 将函数值传递到函数名中
注意: 1、使用函数前应先说明。 2、函数首部以保留字function开头,函数名由用户自定义的一个标识符,用来存放最终函数值。 3、形参就是函数的自变量,其初值来源于主程序的调用,只有在程序的执行过程中调用了函数,形参才能得到具体的值并参与运算,得到函数值。注意:形参表类似于变量说明,但只能使用类型标识符,且不能直接使用类型。形参可缺省。 4、函数的类型也就是函数值的类型,函数值将通过函数名传送回调用程序。 5、函数体内所用的类型、常量、变量等只在本函数内有效,退出函数体后,分配的存储单元被释放。这些量与函数体外的同名变量无关。 6、在函数体中至少有一条将函数值传给函数名的赋值语句。
例7-1 编写一个求n!的函数fac. 若求3!+5!+7!的值,如何修改程序? Program ex1-2a(input,output); var s:longint; 形式参数 函数首部 function fac(n:integer):longint; var k:integer; t:longint; begin t:=1; for k:=2 to n do t:=t*k; fac:=t; end; {endfac} 局部变量说明 函数说明 函数执行部分 将函数值传递到函数名中 begin S:=fac(3)+fac(5)+fac(7); Writeln(‘s=‘,s) End. 主程序 函数调用出现在表达式中
调用函数时注意: 1、自定义函数中的形参,不是实际存在的变量,故又称为虚拟变量,它们并不占用内存单元,只是在调用函数时,才临时开辟相应的内存单元,存放实在参数的值,如fac(3)中的3。它是在调用函数时的所用的自变量。形参实质上是实参的一个“替身”。在调用函数时,实参将值赋给形参,因此实参的个数、类型应与形参一一对应,并且要有确定的值。 2、函数调用步骤是:首先在调用程序中计算实参的值,传送给对应的形参,接着执行函数体,最后将函数值返回给调用程序。 3、函数的定义是静态的,若定义后未被调用,则该函数永远不会被执行。
b2 b1 b6 用海伦公式求三角形的面积:s= p(p-a)(p-b)(p-c) b3 b5 b7 b4 例2-3 计算如图所示的多边形面积。 分析: a,b,c为三角形的边长,p为半周长,即p=(a+b+c)/2 Program ex1-2(input,output); var b1,b2,b3,b4,b5,b6,b7,s:real; 函数首部 function area(a,b,c:real):real; var p:real; begin p:=(a+b+c)/2; area:=sqrt(p*(p-a)*(p-b)*(p-c)); end; 函数area结果类型为实型 三个形式参数 给函数名area赋值 Begin readln(b1,b2,b3,b4,b5,b6,b7); s:=area(b1,b5,b6)+area(b2,b6,b7)+area(b3,b4,b7); writeln(‘s=’,s:10:3); End. 调用函数
例2-4 自定义一个专门求两自然数的最大公约数的函数GCD; function GCD(x,y: integer): integer; Var n:integer; begin While x mod y <>0 do begin n:=x; x:=y; y:=n mod y end; GCD:=y end;
思考: 1、若求3个数的最大公约数,能否定义函数?求4个数最大公约数的函数能否定义?求N个数呢? 2、函数中能否调用已定义函数?自己能否调用自己?
练习:设计一个函数digit(N,K),它能将自然数N的从右边开始的第K位上的数字取出来。例如:digit(13579,3)=5,digit(2468,6)=0,调用此函数,求出10次输入后,得到的第K位上的数字之和。练习:设计一个函数digit(N,K),它能将自然数N的从右边开始的第K位上的数字取出来。例如:digit(13579,3)=5,digit(2468,6)=0,调用此函数,求出10次输入后,得到的第K位上的数字之和。 拓展:1、从左边开始的第K位上的数字如何取出? 2、从中间的第K位开始取M个数字如何取出?
在屏幕上输出如图所示的图形。 * *** ***** * *** ***** ******* ********* *********** * *** ***** ******* ********* *********** ************ ************** * * * * * * Program exam; var I,j:integer; begin for i:=1 to 3 do begin write(‘ ‘:(40-i)); for j:=1 to 2*i-1 do write('*'); writeln; End.
2、过程定义及调用 read/readln/write/writeln 标准过程有: 标准过程调用: Read(a,b,c); 自定义过程的格式: Procedure 过程名(形参表); 局部变量说明; begin 语句1; 语句2; … end; 过程首部 过程体
在屏幕上输出如图所示的图形。 * *** ***** * *** ***** ******* ********* *********** * *** ***** ******* ********* *********** ************ ************** *************** * * * * * * procedure draw (n:integer); var I,j:integer; begin for i:=1 to n do begin write(‘ ‘:(40-i)); for j:=1 to 2*i-1 do write('*'); writeln; end; Begin {main} Draw(4);draw(6);draw(9); for k:=1 to 5 do writeln(‘*’:39); End.
将例2-2中n!用过程fa来定义。 思考:n!的结果存放在哪里? Procedure fa(n:integer); var k:integer; begin t:=1; for k:=2 to n do t:=t*k; end; t 在主程序中说明,为全程量。 n!的结果是如何回传给主程序的? 是通过t带回主程序的。 注意: 1、过程体内所用的类型、常量、变量只在本过程内有效,退出过程体后,该单元被释放。 2、不能给过程名赋值,过程名不能代表任何数据。
练习:2-3-b 定义一个求三角形面积的过程area。 Procedure area(a,b,c:real; var m:real); var p:real; begin p:=(a+b+c)/2; m:=sqrt(p*(p-a)*(p-b)*(p-c)); end; a、b、c、m四个参数,a、b、c为值参,参数m前面有var,是变参。该过程被调用后,由变参m将结果传回调用程序。
b2 b1 b6 b3 b5 b7 b4 过程调用: 过程名:实在参数表; 例:用过程编写程序求如图所示的五边形面积。 Program lx1-1(input,output); var b1,b2,b3,b4,b5,b6,b7,s,sum,real; Procedure area(a,b,c:real; var s:real); var p:real; begin p:=(a+b+c)/2; s:=sqrt(p*(p-a)*(p-b)*(p-c)); end; begin readln(b1,b2,b3,b4,b5,b6,b7); area(b1,b5,b6,s); 三角形的面积通过变参s传回主程序。 sum:=0; area(b2,b6,b7,s); sum:=sum+s; sum:=sum+s; area(b3,b4,b7,s); sum:=sum+s; writeln(‘sum=‘,sum:10:3); end.
过程 函数 过程和函数的主要区别: 完成一系列的数据处理,或与计算无关的各种操作 操作 往往求一个函数值 函数有类型,最终要将函数值传送给函数名。 无 结果类型 由独立的过程调用语句来完成 函数调用出现在表达式中 调用方式 返回值的方法 通过变参将运算的结果传给调用程序 函数值是通过函数名传回调用程序
3、变量及其作用域 例1-5 a读程序写结果。 m为全程变量。 Program ex1-5(input,output); var m:integer; procedure test1; begin m:=100; end; begin m:=5; writeln(‘m=‘,m); test1; writeln(‘m=‘,m); end. 全程量的作用域有两种情况: 1、在全程变量和局部变量不同名时,其作用域是整个程序。 2、在全程变量和局部变量同名时,全程变量的作用域不包含同名局部变量的作用域。 m=5 结果为: m=100
例1-5b 读程序写结果。 Program ex1-5b(input,output); var m:integer; procedure test2; var m:integer; begin m:=100; end; begin m:=5; writeln(‘m=‘,m); test2; writeln(‘m=‘,m); end. M是局部量,结果被屏蔽,它不影响到全程量m的值。 m=5 结果为: m=5
全局变量:在主程序中被说明 作用域:整个程序; 局部变量:在子程序中被说明 作用域:主程序及其下级的程序。 全程量的作用域分两种情况: ①当全程量和局部量不同名时,其作用域是整个程序。 ②当全程量和局部量同名时,全程量的作用域不包含局部量的作用域。 当局部变量所在子程序被调用时,局部变量才被分配有效的存储单元;当返回调用程序时,局部变量所占的存储单元就被释放。
练一练: Program ex1-2(input,output); var x,y:integer; procedure change; var x:integer; begin x:=2; y:=2; writeln(x,y); end; begin x:=1; y:=1; writeln(x,y); change; writeln(x,y); end. 结果为: • 1 • 2 • 1 2
4、参数的传递 Function fac(x,y:integer):real; 值形参 形参 变形参 procdure fac(var x,y:integer); 参数 实参 a:=fac(5,6); 值参类似于局部变量,仅为过程和函数的执行提供初值而不影响调用时实际参数的值。 对变参操作实际上就是对实参本身的操作。
Program ex1-6-1(input,output); var a:integer; procedure sum(b:integer); begin b:=b+10; writeln(‘b=‘,b); end; begin a:=10; sum(a); writeln(‘a=‘,a); end. Program ex1-6-2(input,output); var a:integer; procedure sum(var b:integer); begin b:=b+10; writeln(‘b=‘,b); end; begin a:=10; sum(a); writeln(‘a=‘,a); end. 值参 变参 运行结果为: b=20 a=10 运行结果为: b=20 a=20
Program lx1-2-1(input,output); var x,n:integer; procedure chan(x:integer; var y:integer); begin x:=x+5; y:=y+5; writeln(‘x=’,x, ‘y=’,y); end; begin x:=10; n:=10; writeln(‘x=’,x, ‘n=’,n); chan(x,n); writeln(‘x=’,x, ‘n=’,n); end. 练一练 结果为: X=10 n=10 X=15 y=15 X=10 y=15
读下列程序体会子程序的功能: Program lx_2_2a(input,output); var x,y:integer; procedure swap1; var t:integer; begin t:=x; x:=y; y:=t; end; begin x:=10; y:=20; writeln(‘x= ’,x, ‘y=’: 6,y); swap; writeln(‘x=’,x,’y=’:6:y) End. Program lx_2_2b(input,output); var x,y:integer; procedure swap1(var x,y:integer); var t:integer; begin t:=x; x:=y; y:=t; end; begin x:=10; y:=20; writeln(‘x= ’,x, ‘y=’: 6,y); swap; writeln(‘x=’,x,’y=’:6:y) End.
值参 实参 过程 变参 过程 实参 值参与变参的区别: 1、传值:为值参分配存储单元,过程体内对值参的操作不影响实参的值。一旦过程体执行结束后,系统将收回值参所占用的存储单元,值参的值也就不再存在。 2、变参是传地址:变参所占用的存储单元中存放的是实参的地址,因此对变参的操作就是对实参的操作。一旦过程体执行完毕,系统将收回变参所占用的存储单元,但运算结果已保留在对应的实参中。 形参种类不同决定了实参的单、双向传递。值参实现单向传递,仅将过程外部的值传递给过程,故称为输入参数,它所对应的实在参数可以是常量、变量或表达式;变参实现的是双向传递,除了将过程外部的值传递给过程外,更重要的是它能将过程中变化的形参值带出来,故又称为输出参数,其对应的实参必须是变量。
练习: 指出程序中的全程变量、局部变量、值参、变参,并写出程序运行后的输出结果。 Program lx(input,output); var a,b,c:integer; Procedure suan(var x:integer;y:integer); var m,n:integer; begin m:=x*y;x:=x+1; y:=y+10;n:=x+y; writeln(‘x=‘,x, ‘ y= ’:4,y,’m=’:4,m‘ n=’:4,n) end; begin a:=3;b:=3; suan(a,b); suan(a,b); suan(a,b) end. 全程变量 a,b,c 局部变量 m,n 值参:y 变参:x 结果: x=4 y=13 m=9 n=17 x=5 y=13 m=12 n=18 x=6 y=13 m=15 n=19
[例2-5]如果一个自然数除了1和本身,还有别的数能够整除它,这样的自然数就是合数。例如15,除了1和15,还有3和5能够整除,所以15是合数。14,15,16是三个连续的合数,试求连续十个最小的合数。[例2-5]如果一个自然数除了1和本身,还有别的数能够整除它,这样的自然数就是合数。例如15,除了1和15,还有3和5能够整除,所以15是合数。14,15,16是三个连续的合数,试求连续十个最小的合数。 分析:①从最小的素数开始,先确定第一个素数A; ②再确定与A相邻的后面那个素数B;(作为第二个素数); ③检查A,B的跨度是度否在10 以上,如果跨度小于10,就把B 作为新的第一个素数A,重复作步骤②; ④如果A、B跨度大于或等于10,就打印A、B之间的连续10个自然数,即输出 A+1, A+2, A+3 …, A+10。
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.
n! 例1-7 求组合数C +C 的和。 3 6 5 9 m n C = m!(n-m)! 6、子程序的嵌套 1、嵌套 一个函数或过程可能要求调用另一个函数或过程,这种调用称为函数或过程的嵌套。 n!=n*(n-1)*…*2*1 用fac函数实现。 组合用cnm函数实现。被调用的函数写在调用它的函数前面。 Program ex1-7(input,output); var s:real; function fac(k:integer):real; var I,fa:integer; begin fa:=1; for I:=2 to k do fa:=fa*I; fac:=fa end; 求组合函数 Function cnm(n,m:integer):real; begin cnm:=fac(n)/(fac(m)*fac(n-m)); end; Begin s:=cnm(6,3)+cnm(9,5); writeln(‘s=‘,s:6:0); End. 调用fac函数 求n!函数 调用cnm函数 主程序
程序的执行过程: 1 开始 3调用fac(6) 函数fac 函数cnm 主程序 2调用cnm(6,3) 4返回 5调用fac(3) 6返回 7用fac(6-3) 9返回 8返回 继续执行主程序
Function fac(k:integer):real; var I,fa:integer; begin fa:=1; for I:=2 to k do fa:=fa*I; fac:=fa end; Function cnm(n,m:integer):real; begin cnm:=fac(n)/(fac(m)*fac(n-m)); end; Function cnm(n,m:integer):real; function fac(k:integer):real; var I,fa:integer; begin fa:=1; for I:=2 to k do fa:=fa*I; fac:=fa end; begin cnm:=fac(n)/(fac(m)*fac(n-m)); end;
过程a的说明 . . . 调用b . . . 过程b的说明 . . . 调用a . . . 提前引用子程序: 在程序中并列的过程或函数需要相互调用。 Procedure b(c,y;var y:real); forward; Procedure a(p:real; var q:real); begin … b(p,q); … end; Procedure b; begin … a(x,y); … end; 说明: 把需要提前引用的过程或函数的首部放置在前面,并加上保留字forward;
例1_7b(提前引用子程序示例) Function cnm(n,m:integer):real; begin cnm:=fac(n)/(fac(m)*fac(n-m)); end; 求组合数C +C 的和。 3 6 5 9 function fac(k:integer):real; var I,fa:integer; begin fa:=1; for I:=2 to k do fa:=fa*I; fac:=fa end; function fac(k:integer):real; forward; function cnm(n,m:integer):real; begin cnm:=fac(n)/(fac(m)*fac(n-m)); end; function fac(k:integer):real; var I,fa:integer; begin fa:=1; for I:=2 to k do fa:=fa*I; fac:=fa end;
综合应用: 例2-9 对6-1000内的偶数验证哥德巴赫猜想:任何一个大于6的偶数总可以分解为两个素数之和。 分析:哥德巴赫猜想是一个古老而著名的数学难题,它的理论证明十分复杂。在这里我们用计算机对有限范围内的数加以验证,即任意输入一个大于6的偶数,若能拆分成两个素数,则认为该猜想成立。 解题的关键是判素数。假设定义函数pan(x),用来判断x是否为素数。若x为素数,则函数pan值为1,若不是素数则pan值为0。
Program ex1_9(input,output); var n,m:integer; Function pan(x:integer):integer; var f,k:integer; begin f:=1; for k:=2 to trunc(sqrt(x)) do if x mod k=0 then f:=0; pan:=f end; begin repeat write(‘n=‘); readln(n); until(n>6) and (n<1000) and (n mod 2=0); for m:=2 to n div 2 do if pan(m)+pan(n-m)=2 then writeln(n,’=‘,m,’+’,n-m); end.
结构化程序设计思想: 方法1、模块化:(1)把一个较大的程序划分为若干子程序,每一个子程序独立成为一个模块;(2)每一个模块又可继续划分为更小的子模块;(3)程序具有一种层次结构。 注:运用这种编程方法,考虑问题必须先进行整体分析,避免边写边想。
结构化程序设计思想: 方法2、自顶向下:(1)先设计第一层(即:顶层),然后步步深入,逐层细分,逐步求精,直到整个问题可用程序设计语言明确地描述出来为止。(2)步骤:首先对问题进行仔细分析,确定其输入、输出数据,写出程序运行的主要过程和任务;然后从大的功能方面把一个问题的解决过程分成几个问题,每个子问题形成一个模块。 (3)特点:先整体后局部,先抽象后具体。
[例2-12]将合数483的各位数字相加(4+8+3)=15,如果将483分解成质因数相乘: 483=3*7*23,把这些质因数各位数字相加(3+7+2+3),其和也为15。即某合数的各位数字之和等于它所有质因数的各数字之和。求500以内具有上述特点的所有合数。 分析: 要建立以下几个过程: (1)过程1:要分离X上的各个数字并求和 (2)过程2:分解因子并求所有因子数字和 (3)过程3:判断是否为素数
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.