第8章 函 数 一、函数与调用约定 二、函数的总体概念.

Slides:



Advertisements
Similar presentations
2.8 函数的微分 1 微分的定义 2 微分的几何意义 3 微分公式与微分运算法则 4 微分在近似计算中的应用.
Advertisements

2.5 函数的微分 一、问题的提出 二、微分的定义 三、可微的条件 四、微分的几何意义 五、微分的求法 六、小结.
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
第五章 二次型. 第五章 二次型 知识点1---二次型及其矩阵表示 二次型的基本概念 1. 线性变换与合同矩阵 2.
Oracle数据库 Oracle 子程序.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
不确定度的传递与合成 间接测量结果不确定度的评估
第14章 c++中的代码重用.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
第8讲 函数 8.1 函数的定义与调用 8.2 函数的参数 8.3 函数重载与递归 8.4 标识符作用域与变量的存储特性.
4.3函数 4.3.1函数的概念及定义 1、函数的概念: 可以被其它程序调用具有 特定功能的一段相对独立的 程序(模块),称函数。
第八章 函数 §8.1 概述 一个较大程序一般分为若干个程序模块,每一个模块实现一个特定的功能。所有的高级语言中都有子程序的概念,在C中子程序就是函数。 一个C程序可由一个主函数和若干个函数构成,由主函数调用其它函数,其它函数也可以相互调用.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言程序设计基础 刘新国.
第 十 章 指 针.
第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归
《C++程序设计》 主讲教师:张玉宏.
管理信息结构SMI.
走进编程 程序的顺序结构(二).
辅导课程六.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
第二章 Java语言基础.
动态规划(Dynamic Programming)
SOA – Experiment 2: Query Classification Web Service
若2002年我国国民生产总值为 亿元,如果 ,那么经过多少年国民生产总值 每年平均增长 是2002年时的2倍? 解:设经过 年国民生产总值为2002年时的2倍, 根据题意有 , 即.
第一章 函数与极限.
第4章 PHP流程控制语句.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
1.3 C语言的语句和关键字 一、C语言的语句 与其它高级语言一样,C语言也是利用函数体中的可执行 语句,向计算机系统发出操作命令。按照语句功能或构成的不 同,可将C语言的语句分为五类。 goto, return.
C语言程序设计 主讲教师:陆幼利.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
$9 泛型基础.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
THE C PROGRAMMING LANGUAGE
第7章 函 数 7.1 函数的定义与调用 7.2 函数的嵌套调用与递归调用 7.3 数组作为函数参数 7.4 内部变量与外部变量
VB与Access数据库的连接.
C语言程序设计.
目录 7.1 用户自定义函数的种类 7.2 函数的定义 7.3 被调函数的声明 7.4 函数的调用 7.5 函数的嵌套调用
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第五章 函 数 要点:掌握函数的定义,函数的原形,函数的返回值,函数的调用,函数的形式参数和实际参数之间的关系;掌握函数重载的使用方法,关键字inline的含义与使用,掌握变量的作用域与生存期,了解函数的作用域。
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
iSIGHT 基本培训 使用 Excel的栅栏问题
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第4课时 绝对值.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
ASP.NET实用教程 清华大学出版社 第4章 C#编程语言 教学目标 教学重点 教学过程 2019年5月5日.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第二节 函数的极限 一、函数极限的定义 二、函数极限的性质 三、小结 思考题.
本节内容 结构体.
第17章 运算符重载 一、运算符重载的概念 二、禁止重载的运算符 三、运算符重载的规则 四、单目运算符函数 五、双目运算符函数.
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
第三节 数量积 向量积 混合积 一、向量的数量积 二、向量的向量积 三、向量的混合积 四、小结 思考题.
C++语言程序设计教程 第4章 函数 第4章 函数.
声明 使用本课件至少128M内存,并使用office 2000以上版本或使用自带播放工具pptview。
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
本节内容 this指针 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
Presentation transcript:

第8章 函 数 一、函数与调用约定 二、函数的总体概念

一、函数与调用约定 将经常使用的功能组合成一个有机的整体,程序就划分 为功能相对独立的模块。这些独立的模块对应着程序的函 数。 函数是代码最重要的重用机制。函数的来源分为两种: 一、程序员编写的函数; 二、系统提供的标准库函数。 系统的库函数是预先编好的可供程序员调用的函数。调 用时需要将库函数的原型通过头文件的方式包含在主控函数 的源文件中。 例如: 通过#include<math.h>,就可以使用math.h中的数学 函数如sin,cos等。

调用约定是为实现函数调用而建立的一种协议。函数定 义之后,可以在别的地方对它进行调用。在定义时用形式参 数(简称形参),调用时则替换成实际参数(简称实参)。 首先,参数的传递是指入口形参输入传递,它是一个 形实替换过程。 如果一个程序向另一个程序发送参效的规则和后者接收 参数的规则不符合,那么程序就可能因为出错而导致系统崩 溃。 其次,参数的传递也包括函数返回的数据传递。

1. 传值调用 (call by value) 在各种高级语言中比较流行的参数的传递方式主要为如 下两种: 传值是一种最简单的参数传递方法,传值首先指输入传 值,它把实参的值单方向地传递给相应的形参。对于变量、 指针等实参,被调用段无法改变实参的值,传值是一种最安 全的参数传递方法。 传值包括形参的输入传值与数据的返回传值。例如: int ifi (int x) {return x+1;} //int型的数值入口和int型的数值返回 int* pfp (int* p) {return p+2;} // int*型的数值入口和int*型的指针数值返回

输入传值过程把实参值存放在一个被调用段可以取得的 地方即形参中,每一个入口形参位于被调函数新开辟的堆栈 空间而非原来的变量中。 进入被调用段后,首先在临时的堆栈空间取出实参值, 然后象对待一个局部变量一样对形参进行处理。 在被调函数中,一切操作都针对此局部的独立的形参单 元进行。如果实参不是变量的地址,则被调用段是无法改变 实参对应的变量值的,即对原实参对应的变量无影响。 实参为指针的情况,传值也是传递指针所具有的数值不 是指针的地址,即传递另一个变量的地址给被调程序,作为 被调程序指针形参的初始值,在被调用段可以改变指针指向 的存储单元的值,不能改变原实参对应的指针的值。传值调 用传递一个不含实参地址属性信息的右值。

传值调用的特点是先计算出表达式的值,输入的时候对 于大的对象或结构变量须把其一系列具体的数据值放置在刚 开辟的堆栈空间中,堆栈空间的开销趋大。 传值返回的时候根据返回数据类型的大小系统将结果值 或通过EAX等寄存器或通过临时建立的存储单元返回给主控 程序。 C语言函数的参数传递方式只有一种就是数值传递。

2. 引用调用(call by reference) 传递。指针的传值与变量的引用传递都是转送另一个变量的 地址但对应两种不同的调用约定。 引用调用包括变量和指针以及函数指针等的引用传递, 包括引用输入与引用返回。例如: int& rif (int& x) {return x+=1;} //int&变量的引用入口和引用返回 int*& rpf (int*& p) {return p+=2;} //int*&指针的引用入口和引用返回

引用输入传递也是用得最多的参数传递方式,它是把实 际参数的地址传递给相应的形式参数。引用调用传递一个含 实参地址属性信息的左值。其实现过程下: 在被调函数中,每一个形参都对应了一个形参单元,这 个单元用来存放相应实参的地址。 如果实参是变量则直接传递它的地址;如果实参是常数 或表达式,则应该首先计算出它的值并放入一个临时单元, 再把这个临时单元的地址传给函数。 当进入被调用函数后,对应的形参单元中存放的是实参 的固定地址,在处理数据时,针对这些形参指向的实参地址 进行访问,但程序段中采用的是变量名的语法。在被调函数 返回时,这些形参单元所对应的实际单元就直接得到结果值.

如果实参的类型不同于形参的类型,不同版本编译器做 出的反应是不同的: 或者建立临时变量,将临时变量的地址作为下一步计算 的依据; 或者禁止引用形参和实参的类型不一致(vc6.0属此情 况)。引用形参关键之点是被调函数直接操作实参代表的内 存空间。 引用调用的核心在于: 变量具有双重属性,变量的地址属性和变量的值属性, 被调函数拥有实参的双重属性; 传址就是通过变量的地址属性,快捷地存取变量的值, 在函数体中,间接寻址的地址未变,而其地址对应的内容可 发生变化。

引用调用在变量输入的时候不论是小的字符变量或是大 的对象只将实参变量的地址压入堆栈。 传址返回的时候也直接返回相关变量的地址属性,不需 要额外建立临时对象或临时变量。 C++作为C的超集,继承了C语言根深蒂固的参数传值 调用方式,又借鉴FORTRAN 等高级语言中高效的引用调 用,形成两种调用并存的局面。 C++语言是典型的混合编程语言。

二、函数的总体概念 C/C++中函数是由称之为函数体的可整体运行的若干语 句构成,这些语句对表征数据状态的名称进行预定的运算操 作。 编译器根据函数名、形参类型、形参个数与形参位置来 鉴别函数体代码段入口地址的唯一性,函数调用作为表达式 可返回某种类型的数据。 类名抽象type,T1, T2, T等可以是int, char,long,float 等,也可是结构名、或类类型名等。

1.函数的返回类型 函数的返回类型由函数名前的类型标识符指定。不失一般性以两个形参进行说明。根据函数的调用机制与返回结果可以分为两大种类: a. 函数操作结果没有返回值。例如 void vf (T1,T2*){ return ;} [例] void vf (int a,int* p) { a+=3; p++;} 用关键字void前置加以声明的函数称为void型函数。 void型函数只独立调用,一般不参入表达式的嵌套运算,除 非出现在三目操作数表达式的后两个操作数中以及逗号运算 符分隔的操作数中。

b. 函数操作的结果具有确定的返回值,这样的函数调 用是表达式,可参入表达式的嵌套运算,也可单独调用。 主要可分为两种形式: (1)返回一个数值类型的数据。例如: type funct (T1 v, T2* p) ; type* pfunct (T1 x , T2* q) ; [例] long min(short s,long* p) {return s<*p?s:*p; } long* pan(int n , long* p){ return p+n;};

这种形式的函数操作的结果常见的有两种: (一)、type型的传值返回; (二)、指针的传值; 返回即函数返回的结果为type*型的指针值。指针的值 最终必然用于操作内存的数据,因此该指针监控的内存空间 的生存期对于主控程序应是有效地可访问的。 返回算术或指针类型数值的函数调用为右值表达式。 例如: 函数调用min (s,p)是long型的右值,pan(n,p)是long* 型的右值地址,但间接访问*pan (n,p)是long型的左值。

(2)返回一个引用类型的数据。例如: type& rf (T1&, T2& ) ; type*& rf (T1&, T2* &); [例] long& rmax (long& n,long& m) { return n>m?n:m; } long*& rpan (int& n,long*& p) { return p+=n; } 返回type&类型的函数为返回变量的引用的函数。返回 type*&类型的函数为返回指针的引用的函数。返回引用的函 数调用为左值表达式。 例如:函数调用rmax(n,m)是long型的左值变量,函数 调用rpan ( n, p)是long*型的左值指针。引用概念是C++所 独有的。 函数不能返回函数和数组,但可以返回指向数组或函数的 指针。

2.函数的定义 a.函数数值传递的定义 type funct (T1 x, T2* y) /*标题头*/ { /*x是变量的数值形参,y是指针数值形参*/ 语句序列; return expre; /*expre是可转换为type型的表达式*/ } /*最外的一对花括号界定函数体*/ 例: long min (long x,short* y) { if (x<*y) return x; else return *y; }

b.函数引用传递的定义 type & rf (T & v, T* & p) { /*v是变量的引用形参,p是指针引用形参*/ 语句序列; return Lvalue; /*Lvalue 为type型的左值*/ } 例: int& rmin (int& v, int*& p) { if (v<*p) return v; else return *p;

由于传值的输入不改变相关实参变量的值,如果要保持 原先函数的这一特性,在引用形参前进一步加上修饰词 const,得到: const T& cf(const T& v, T*& p) { 语句序列; return (T型的变量); } 例: const int& cmin (const int& v, int*& p) { if (v<*p) return v; else return *p;

形参表中的const引用形参v是局限于函数体的不变量, 这种出现在形参位置的不变量虚实结合时可以获得不同的实 参变量,在函数体中只作为右值。 函数的返回类型前加const关键字界定,此时限制返回 引用的函数调用不作为左值但保留数据传递的效率。 函数名代表了函数的入口地址。圆括号中()可以无任何 参数,称为无参函数,此时圆括号中可放置关键字void。在 这种情况下对函数的调用称为无参调用。 圆括号()包括的参数称为形式参数,代表函数与调用 段的数据接口。T1,T2, T,type 是类型名,声明数据的类型, v,p, x,y是形参名。

函数名、类型名和形参名遵循标识符的命名规定。参数 之间用逗号分隔,函数名前的类型就是函数的返回类型。 函数不能嵌套定义即在函数体中定义另外一个函数实 现。 函数定义意味形参未曾进行实参化,函数调用则对应虚 实结合过程。 函数体内无论多少条语句,花括号是不可省的。用花括 号括起来的语句序列组成了函数体。

语句序列可以是0条、1条或多条语句。 当函数体是0条语句时,称该函数为空函数。空函数作 为一种什么都不执行的函数也是有意义的。 例如: 下面的NoOperate()就是一个空函数。 void NoOperate (void) { } 函数可以略去形参名仅带类型参数,通常表示预定的接口 准备。例如: void PreOperate (long/*cx*/,float/*dx*/) { }

3.函数原型 函数的类型首先指函数执行后返回值的类型,其次包括 函数的入口类型,两者一起确定函数的类型属性。函数原型 (function prototype)反映函数的类型属性,函数原型称为 函数说明。C++中所有的名称在索引点之前必须有效说明。 函数定义在先调用在后,调用前可以不必说明;函数定 义在后,调用在先,调用前必须说明。一般将函数原型的说 明放在程序全局范围的开始部分。 函数原型表明入口参数的类型、位置、个数和返回类 型。函数原型的说明方法如下: type funct (T1 v, T2* p); 类型 函数名(类型1 形参1,类型2* 形参2);

函数原型中的形参名可以和标题头相应的形参名不同。 例如: long& rmax (long& n,long& m); long& rmax (long& x,long& y); 原型中形参名是可有可无的,但函数原型中形参的位 置、类型、个数与函数名一起构成函数原型的关键因素。写 成略去形参名的形式: long& rmax (long&,long&); 或一般地: type funct (T1 , T2* ); 类型 函数名 (类型1,类型2* );

从函数原型可知funct函数第一个形参的数据类型为 T1,第二个形参为T2*型的指针数值形参,返回type型的数 据。 函数原型与函数定义的标题头十分类似:将函数定义的 标题头进行复制就得到函数原型的说明,但记住在末尾加一 个分号";"。 编译器根据函数原型或标题头来识别不同的函数实现, 函数实现部分中的语句序列对于函数的区别并不重要。

下面是两个重要函数printf和scanf的原型,原型是从系 统stdio.h头文件拷贝过来的,进行了适当简化。三点省略 号...表示可变参量列表,表示实参的个数是动态可变动的。 int printf (const char *format, ...); int scanf (const char *, ...); const char *表示只读指针形参,实参常见的是格式控 制字符串常数。例如: printf ("abcd"); printf ("%d,%d",x,y); scanf("%d,%d",&x,&y); 可以改写为: const char * r="abcd"; const char *fmt="%d,%d"; printf (r); printf (fmt,x,y); scanf (fmt,&x,&y);

4.return 语句 函数的返回通过return语句实现。return语句有三种格 式,如下所示: 格式一: return; 格式二: return expre; return (表达式); 格式三: return Lvalue; return 左值表达式; return语句后面的圆括号是可选的,return (expre);等 价于return expre;

关于return语句的使用说明如下: 格式一用于void型无返回值的情况。无返回值的函数须 用void来说明。该函数中可以有return语句,也可以无 return语句。 当一个被调用函数中无return语句时,程序执行到函数 体的最后一条语句时,返回到调用函数,相当于函数体的花 括号有返回的功能。 函数中也可以有多个return,它们大多出现在if语句 中。当使用无表达式的返回语句时,返回程序执行的控制 权。

格式二是用于数值返回的调用函数中,这也是传统的C 语言中的返回方式,return之后表达式的值就是函数调用的 值。最简单的表达式是变量或常数。 格式三用于引用返回的函数调用中,这是C++新增的函 数返回约定。这种约定对应着对引用或相关变量的直接操 作,因此当函数引用返回时返回语句return后不要跟右值表 达式,而只返回左值表达式。表达式expre或Lvalue可以是 返回值的函数调用。

具有return 语句实现过程如下: a. 先计算出表达式expre或Lvalue的值,表达式完成所 有的副作用。 b. 算术表达式expre的类型与函数的类型不相同时,将 表达式的类型自动转换为函数的返回类型,这种转换是强制 性的,可以出现不保值的情况。 返回引用时的左值一般应与返回类型一致。指针表达式 也应与函数的返回类型一致。 c. 将程序执行的控制权由被调函数转向主控函数, 执 行主控函数后面的语句。

图 函数调用和返回过程 void func1() { func2(); int func2() 语句; { 语句; ::: return; } int func2() { 语句; ::: return 1; } void main(void) { 语句; func1(); 语句1; ... funck(); 语句k; funcn(); 语句n; } void funck() { func(); 语句; ::: return; } char func() { 语句; ::: return '1'; } 图 函数调用和返回过程

函数体中的变量为局部变量,非静态的局部变量存放在 堆栈空间。 堆栈空间是动态变化的,函数是分层分层调用的。主控 函数与被调函数各自的局部变量都位于堆栈空间中,被调函 数的局部变量位于堆栈空间变化快的部分,主控函数的局部 变量位于堆栈空间变化慢的部分。不要返回变化快的局部变 量的堆栈地址给上层的主控函数。 即上面的 Lvalue 应是形参表中的引用或全局变量或全 局数组元素或静态变量。

5.函数的使用 函数定义之后就可以使用,使用函数也称为函数调用。 函数名加上圆括号包括的不带类名的实参序列构成函数 调用。 函数调用分三个主要步骤: a. 虚实结合 b. 执行函数体中的代码序列 c. 函数返回 函数调用对应形参初始化。实参对形参初始化是按其位 置对应进行,即第一个实参的值赋给第一个形参,第二个实 参的值赋给第二个形参,依此类推。

实参表达式在虚实结合之前已进行求值计算,编译器习 惯上从右到左的次序对实参表达式进行求值计算。 但可以从左边对应的实参开始求值一直往右,这种实参 求值次序的不同可能引起函数调用的一些副作用,因此编程 时保证实参表达式的值独立于编译器左右求值的不确定性。 对于算术型数值形参,如果实参类型不同于形参类型则 进行必要的类型转换,转换的方向从实参的类型到形参的类 型。指针形参和引用形参要求严格匹配相应的实参类型。 数值形参重要的性质是其安全地承前启后的作用,在堆 栈获得初始值之后,数值形参本身在函数体中的变化不影响 主控函数,并且它们占有的独立的内存可以充分加以利用。

引用形参对应的实参是变量或左值表达式,执行传址调 用之前系统得到的是实参变量的地址,传递给形参的是左值 实参,隐含地通过左值实参的地址间接操作实参的数值。 函数单独调用构成函数调用语句,有值返回的函数单独 调用时,系统会建立一个临时变量以保存函数的返回值。 函数调用的一般格式为: 函数指针表达式(实参表达式列表) 函数名是最简单的函数指针表达式。

函数调用根据函数的返回类型来确定: (1). 无值返回的函数单独调用。如: vf (v1,v2); swap (&a,&b); swap (a,b); //函数调用语句 (2). 返回右值的函数可作为右值表达式参入各种运算。 如: var=20* funct (v1,v2); int x=min (n,p); long* q=pan (n,p); (3). 返回左值即返回引用的函数可作为左值表达式参入 各种运算。如: rf (v1,v2)+=1; rmax (x,y)-=2; rpan (n,p)--;

返回值的函数调用作为表达式其结果就是return中转送 过来的表达式,这称为函数对于相应表达式的映射。 返回引用的函数Lvalue可以出现的地方函数调用 rf(v1,v2)作为左值可以等价地出现,返回算术或指针数值的 函数funct将expre映射成右值表达式。 在这种映射之前函数可以执行许多有意义的运算。 返回值的函数既具有动作本身又携带数据信息,这一性 质表明函数是算法和数据封装的基石。

请打开“第8章(2).ppt”