研究生课程_程序语言设计原理教程_第06章

上传人:aa****6 文档编号:56796667 上传时间:2018-10-15 格式:PPT 页数:23 大小:598.50KB
返回 下载 相关 举报
研究生课程_程序语言设计原理教程_第06章_第1页
第1页 / 共23页
研究生课程_程序语言设计原理教程_第06章_第2页
第2页 / 共23页
研究生课程_程序语言设计原理教程_第06章_第3页
第3页 / 共23页
研究生课程_程序语言设计原理教程_第06章_第4页
第4页 / 共23页
研究生课程_程序语言设计原理教程_第06章_第5页
第5页 / 共23页
点击查看更多>>
资源描述

《研究生课程_程序语言设计原理教程_第06章》由会员分享,可在线阅读,更多相关《研究生课程_程序语言设计原理教程_第06章(23页珍藏版)》请在金锄头文库上搜索。

1、第6章 函数和过程,命令式语言中子程序有两种形式:函数(必须返回值)也叫函数,过程(实施一组动作)也叫子例程subroutine。它们是程序的第一次分割,这种分割的好处: 实施的功能单一,便于调试; 相对独立,便于多人分工完成,且时间不受约束; 相对封闭,人们易于控制,是分解复杂性的有力措施。 子程序和主程序联系的接口特别重要。在这个界面上要指出该例程的数据特征, 即输入什么输出什么。而整个子程序体是完成从输入到输出的实现手段。 界面指出“做什么?”,而子程序体回答“怎么做”。 80年代程序完成第二次分割: 将子程序定义(即界面)和子程序体显式的分开, 成为相对独立的规格说明(Specific

2、ation)和体(body)。,6.1 函数和过程抽象,函数抽象是用一个简单的名字抽象代表一个函数。函数由函数型构(Signature)和函数体(body)组成。函数计算的目的是求值。函数体等同于一个复合的表达式。函数抽象是对表达式的抽象 过程抽象是用一个简单的名字抽象代表一个计算过程。过程由过程型构和过程体组成。过程调用的目的是执行一组命令过程抽象是对命令(即语句)集的抽象 函数由函数型构和函数体组成。形式是:,function FUNC (fp1,fp2,.):returntype;/函数型构B; /函数体,可包括任何声明和语句其中fp1,fp2,为形式参数,也叫形式变元(argument

3、)returntype 为函数返回值的类型 函数引用是应用函数的唯一手段,它在同名的函数名之下给出实 在参数(实在变元):FUNC (ap1,ap2,.);,各种语言函数定义 (a) FORTRANINTEGER FUNCTION FACT(N) /前缀指明返回类型INTEGER N,I,F /参数类型在此声明F = 1DO 10 I = 2,NF = F*110 CONTINUEFACT = F /必须至少定义函数名一次RETURN /至少有一返回语句END (b) PascalFUNCTION fact (n:Integer) :Integer; /参数类型在变元表中定义,BEGIN /后

4、缀指明返回类型 fact = 1;IF n = 1 OR n = 0 THENReturnELSEFact = n*fact(n-1); /也要定义函数名END,(c) Cint fact (n) /前缀指明返回类型int n; /参数在体中声名类型int i, f; /ANSI C改参数原型f = 1; if(n1)for (i = 2; i /用函数定义值if n = 1 then 1 else n*fact (n-1),续,多重入口和指定返回,FORTRAN 的多重入口示例SUBROUTINE DEG(R,THETA,X,Y)C = 3.14159/180.0THETA = C * TH

5、ETAENTRY RAD (R,THETA,X,Y)X = R * COS(THETA)Y = R * SIN(THETA)RETURNEND若THETA是度数值时,则调用语句为:CALL DEG (R,THETA,X,Y) /入口在子程序顶部 若THETA是弧度值时,则:CALL RAD(R,THERA,X,Y)/入口在子程序中,FORTRAN的指定返回 SUBROUTINE RM(X,Y,*,*,*). RETURN2 /返回语句标号80. RETURN1 /返回语句标号70. RETURN3 /返回语句标号120. ENDCALL RM(A,B,70,80,120),形实参数表中元素个数

6、,次序,类型应一致。早期语言都严格遵此准则。近代语言提供了较多的灵活表示法。Ada引入缺省参数,实参个数可少于形参个数;指明参数结合不考虑次序;Ada引入参数模式in,out,inout指明只读,只写,读写参数。C语言允许任意多个参数的调用。如内定义函数printf()调用时可以写任意个输出,只是第一参数中的格式个数与参数个数对应。过程定义与调用过程子程序定义形式procedure PROC (fp1,fp2,.) /过程型构B; /子程序体包含局声明对应的过程调用是:PROC (ap1, ap2, .);C语言一切过程,包括主程序都是函数过程。它以void(无值)关键字代替函数类型指明符,实

7、施子程序过程语义,引用或调用的形式,无参过程,- 函数和过程的参数表均可为空。有的语言保留(),有的只有一个名字。一般无参过程也要更新过程内部的值。函数过程还会返回不同的值。全局量在函数中有效。改变了全局量两次调用结果值当然不一样。这就是函数的副作用(side effect)。- 有副作用的函数C 在很大程度上利用函数副作用,例如,当需要跳过空白时写:while (c = getch() = );- Ada中常用的随机数:function RANDOM return FLOAT range 0.01.0; 引用时, 若FIELD已声明为常量:RESULT = RANDOM * FIELD; R

8、ANDOM若无副作用RESULT值不可能改变。,6.2 参数机制,语言中第一类对象均可作函数/过程参数。 由于变量的时空特性,传递的形-实参数可以有许多不同的实现结合的办法,即参数机制。,6.2.1 传值调用(call-by-value),1实参表达式先求值 2将值复制给对应的形参。形参和实参有同样大小的存储 3过程运行后一般不再将改变了的形参值复制回实参,Pascal中的传值调用PROCEDURE test1(J2,A2:Integer;P2:list)BEGINWriteln(J2,A2,P2.value);J2= J2 + 1;P2= P2.next;Writeln(J2,A2,P2.v

9、alue)END.调用程序有:test1(J1,A1J1,P1.next);,第一次打印为:1 30 % 第二次打印为:2 30 $,6.2.2 传名调用(call-by-name),传名在过程/函数中加工的就是实参已分配的值,因此不需付出双倍存储代价。但传名过程的虚实结合是将程序体中所有形参出现的地方均以实参变元名置换。这样出现几次算几次效率是低的。传名调用程序示例 由于Pascal无传名机制,此处作一点扩充:PROCEDURE test2(NAME J2,A2:Integer;NAME P2:List);函数体同test1 执行同样调用: test2(J1,A1J1,P1.next);,名

10、结合后打印:1 30 % 执行后结果是:2 45 $,6.2.3 引用调用(call_by_reference),引用参数实现时, 编译器在子程序堆栈中设许多中间指针, 将形参名束定于此指针,而该指针的值是实参变量的地址(在主程序堆栈框架内),在子程序中每次对形参变量的存取都是自动地递引用到实参存储对象上。 引用调用的Pascal示例:PROCEDURE test3(VAR J2,A2:Integer;VAR P2:List);函数体同test1相应的调用程序是: test3(J1,A1J1,P1.next);,第一次打印是: 1 30 % 第二次打印是: 2 30 $,引用调用图示,6.2.

11、4 参数模式与返回调用(call-by-return),显式指明参数传递模式,可以为编译实现提供信息fun_name(x,y:Real; VAR s,q:Integer).x,y传值实现,它只读。s,q引用实现,可读/写 Ada只规定参数模式in,out,inout,传递方向的模式(mode)。 由编译选择实现方式: proc_name (X,Y:in Real;S:inout Integer;Q:outInteger)in模式可不写出(缺省)。 函数只能有in的模式,过程都有,且出现次序不受限制。x,y因在子程序中只读,传值实现可保证不受破坏。s读/写用引用实现,而q是只写参数,传值和引用都

12、不能保证”只”写实现返回调用机制有两种办法:其一是复制。另一种办法是引用实现增加”只写”保护,6.2.5 值-返回调用(call-by-value-and-return),是对by-reference的改进,因多进程竞争数据资源时多重引用(束定)易于引起混乱,P2,返回值由P2定 返回值由P1定 正常顺序执行对于并发多任务宜只读只写 值与返回调用机制是把值调用和返回调用组合起来,实现调用程序双向通道,这对于有多个存储器的多处理器系统和网络分布式系统值调用极度安全 在子程序执行期间因不是束定, 形参变量的值不会中途改变, 复制回去和拷贝进来处可设断点检查,P1,P2,P1,P2,P1,P2,6.

13、2.6 指针参数(call_by_point),指针作为参数其实现方式一般是复制机制,它复制的是地址(指针内容) 注意和引用调用之同异,例:指针Pascal引用版: 交换两变量的内容 PROCEDURE swap1( VAR a,b:Integer);VAR t:Integer; BEGINT = a; a = b; b = t END; 调用程序片断:j = 3; k = 5;swap1(j,k); /结果j = 5, k = 3,J =,3,K=,5,Caller-frame,= a,= t,= b,3,=,=,Swapl-frame,指针版:变换两变量的内容TYPE int_ptr =

14、Integer;VAR jp, kp:int_ptr;PROCEDURE swap2 (a,b:int_ptr);VAR t:Integer;BEGINt= a; a= b; b= tEND;相应调用程序片断:NEW (jp); jp= 3;NEW (kp); kp= 5;Swap2(jp,kp);,C语言的指针参数传递void swap3(int *a, int*b) int t;t = *a; *a = *b; *b = t; 形参是两指针, 实参不用指针的版本:main() int j = 3; k = 5; /声明并初始化两整数swap3(/类型匹配吗? ,实参是指针的版本: main

15、() int j = 3, k = 5;int *jp = ,6.3 变元求值策略 ML:fun sqr(n : int) = n*n 若p=2,q=5有调用sqr ( p + q ) = sqr ( 2 + 5 ) = 7 * 7 = 49 急求值:表达式先求值再入体。 正规求值:(p+q) * (p+q) = (2+5)*(2+5) = 7 * 7 = 49 按演算,先置换原表达式,体中代入值计算 懒求值:(p+q) * (p+q) = (2+5) * (2+5) = (2+5) * 7 = 49 只在界面置换原表达式,何时用该值何时计算,相同的只算一次 Church-Rosser性质: 表达式的完全求值,仅当它前后一致地按正规顺序求值,几种求值方式得的结果应一致。若一表达式能以几种不同的求值次序求值(包括混合使用几种求值方案),则所有这些求值次序得到的结果值应该是一样的。,

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > PPT模板库 > 教育/培训/课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号