第八章结构、联合与枚举.ppt

上传人:sccc 文档编号:5665801 上传时间:2023-08-07 格式:PPT 页数:62 大小:465.01KB
返回 下载 相关 举报
第八章结构、联合与枚举.ppt_第1页
第1页 / 共62页
第八章结构、联合与枚举.ppt_第2页
第2页 / 共62页
第八章结构、联合与枚举.ppt_第3页
第3页 / 共62页
第八章结构、联合与枚举.ppt_第4页
第4页 / 共62页
第八章结构、联合与枚举.ppt_第5页
第5页 / 共62页
点击查看更多>>
资源描述

《第八章结构、联合与枚举.ppt》由会员分享,可在线阅读,更多相关《第八章结构、联合与枚举.ppt(62页珍藏版)》请在三一办公上搜索。

1、第八章 函 数,熟练掌握函数的定义、调用、返回值的方法及参数传递方式 掌握函数使用的常用方法了解变量的作用域和变量的存储类别,8.1 概 述,一、C函数的概念,将一个C程序分为若干模块,每个模块实现一个特定的功能,在C语言中用函数来实现模块的功能。,函数:具有某种功能的独立程序段。,从程序设计方法看C函数:它是实现模块化程序设计的语法元素。,从C语言中程序的组成方式看C函数:它是程序的基本组成单位。,二、C函数与C程序结构,C程序由主函数(main函数)和若干个子函 数构成;主函数调用子函数;子函数在定义时是并列的;子函数可相互调用,也可被多次调用。,main()/*主函数*/print_st

2、ar();/*调用print_star函数画*/print_message();/*调用print _message函数写字*/print_star();/*调用print_star函数画*/print_star()/*定义print_star函数*/prinf(“n*”);print_message()/*定义print_message函数*/prinf(“n Hello!”);,函数调用例:,运行结果:*Hello!*,三、C函数的特点,一个源文件由一个或多个函数组成,它是一 个独立编译单元。一个C程序由一个或多个源文件组成;C程序执行总是从main函数开始,调用其 他函数后流程回到mai

3、n函数,在main函数 中结束整个程序的运行。函数不能嵌套定义,但可以互相调用。注意不能调用main函数。,四、函数的分类,1.从函数的参数形式看,函数可分为两类:,无参函数;有参函数,有参函数例:(输出两数中大者)#include int max(int x,int y);main()int num1,num2,a;scnaf(%d,%d,int max(int x,int y)int z;if(xy)z=x;else z=y;,2.从用户使用的角度看,函数有两种:,标准函数(库函数);用户自己定义的函数,库函数:是由编译系统提供的已设计好的函数,用户只需调用而无需要去实现它。前 几章用过的

4、scanf,printf,getchar,putchar等都是库函数。,用户自定义函数:由程序员自己定义和设计的 函数。需要程序员自己来编写函数 功能实现代码。,8.2 函数定义的一般形式,一、无参函数的定义形式,类型标识符 函数名()说明部分 语句,例如:print_message()printf(“n Hello!”);,无参数传递,二、有参函数的定义形式,类型标识符 函数名(形式参数表列)说明部分 语句,有参数传递,例如:int max(int x,int y)/*求x和y二者中大者,x,y为形参*/int z;/*函数体中变量的说明*/z=xy?x:y;return(z);/*将z的值

5、作为函数返回值*/,三、空函数的定义形式,类型标识符 函数名(),例如:dummy(),功能:调用后什么也不做。,用处:建立程序结构,在需要时补充功能。,四、对形参说明的传统方式,上面讲的形式参数表的说明形式是新版C语言表示形式(现代方式),即形式参数说明是类型和参数在一起说明。传统的形式参数说明是类型和参数分别说明。,如:按传统方式说明形参 int max(x,y)int x,y;,按现代方式说明形参 int max(int x,int y),这两种方式都可以使用,但推荐使用现代方式。,8.3 函数参数和函数的值,一、形式参数和实际参数,形式参数:在定义函数时函数名后面括弧中的 变量名,简称

6、形参。,实际参数:在调用函数时函数名后面括弧中的 表达式,简称实参。,main()int a,b,c;scanf(“%d,%d,int max(int x,int y)int z;z=xy?x:y;return(z);,形参表,实参表,上例中形参与实参、函数名与返回值之间的关系:,关于参数的几点说明:,二、函数的返回值,定义:通过函数调用使主调函数得到一个确定 的值,称为函数的返回值。,例如:c=max(3,5);此时函数的返回值是5,因此c=5,2.函数的返回值语句 return,函数的返回值是通过 return语句 获得的。return语句将被调函数的一个确定的值带回主调函数中去。retu

7、rn语句的一般形式:,“函数返回值”是有确定值的常量、变量或表达式。,说明:,一个函数中可以有多个return语句,但是一次 函数执行只能执行其中的一个。当执行到某个 return语句时,则终止函数执行,并带回函数值。,若函数体内没有return语句,就一直将函数执行 完,再返回调用函数,有一个不确定的值带回。,return后面可以无“返回值”(即 return;),则 该return语句只起到 终止函数执行,返回主调函 数的作用。,三、函数值的类型,函数定义时应该指定函数的类型(即函数值的类型),应该与return语句的类型一致。,说明:,凡不加类型说明的函数,一律自动按整型处理。,如果函数

8、类型和return语句的类型不一致,以函 数类型为准。对数值型数据,可以自动进行类型 转换。既函数类型决定返回值的类型。,如果函数不返回值,可以将函数定义为“无类 型”void(或称“空类型”)。,例如:void print_star(),8.4 函数的调用,一、函数调用的一般形式,二、函数调用的具体方式,1.把函数调用作为一个语句,如:我们程序中对scanf函数和printf函数的调用。,2.函数调用出现在表达式(函数表达式)中。,如:a=3+max(num1,num2);,注意:无返回值函数的调用,不能出现在表达式中。,三、对被调用函数的说明(声明),对被调用函数说明的前提条件,被调用函数

9、必须是已存在的函数,如用户自定义函数或库函数。,2.被调用函数是用户自定义函数的函数说明,同变量一样,函数的调用也应该遵循“先说明,后使用”的原则。,如果使用用户自定义函数,而且主调函数和被调用函数在同一个文件中,应该在主调函数中说明被调函数的类型。其说明格式的一般形式如下:,一般形式:,在C语言中,以上的函数说明称为函数原型。,main()float add(float x,float y);float a,b,c;scanf(“%f,%f”,/*定义add函数*/float add(float x,float y)float z;z=x+y;return(z);,对被调用函数的说明,作为表

10、达式被调用,3.被调用函数是库函数的函数说明,如果使用库函数,需要在文件的开头用#include 命令将需要的库函数包含到文件中。,现在我们清楚了,为什么在使用库函数之前必须包含相应的头文件?那是因为对这些库函数的原型说明全部都写在对应的头文件里了。,我们现在用到的头文件有:#include“stdio.h”/*调用输入输出函数*/#include“math.h”/*调用数学函数*/#include“string.h”/*调用字符,字符串函数*/,在本书的附录C中列出了C语言可以使用的标准库函数,大约有75个。请在阅读时注意形参的要求、功能及返回值。,4.函数说明和函数定义的区别,函数说明的作

11、用是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。,旧版C语言函数说明只是对函数名极其返回类型的说明。如:float max();未进行全面检查,新版C语言兼容这种用法,但不提倡使用。,因此,下列函数说明都是合法的:float max(int x,int y);float max(int,int);float max();,函数定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。,5.可省略被调用函数说明的三种情况,函数的返回值为整型或字符型时,可以不进行 类型说明,系统按整型处理

12、。,main()int a,b,c;scanf(“%d,%d”,无函数说明,整型函数,被调用函数定义在主调函数之前,可以不进行 类型说明。,float add(float x,float y)float z;z=x+y;return(z);main()float a,b;scanf(“%f,%f,“,被调函数在主调函数之前,主调函数在被调函数之后,如果已在所有函数定义之前,在文件的开头,在函数的外部已说明了函数类型,则在各个主 调函数中不必对所调用的函数再做说明。,char letter(char,char);float f(float,float);int i(float,float);ma

13、in().char letter(char c1,char c2)float f(float x,float y)int i(float,float),在所有函数之前说明函数类型,此处不必说明,定义函数letter、f和i,8.5 数组作为函数的参数,数组元素可以做函数的实参数组名可以做函数的参数多维数组可以做函数参数,一、数组元素可以做函数的实参,由于表达式可以做实参,数组元素可以作为表达式的组成部分,因此,数组元素可以做函数的实参,并且可以单向传递给形参。,例:有两个数组A,B。各有10个元素,将它们逐个对应相比,如果A数组中的元素大于B数组中相应的元素数目多于B数组中的元素大于A数组中相

14、应的元素数目,则认为A数组大于B数组,并分别统计出两个数组相应元素大于,小于和等于的个数。,程序设计:,函数large(x,y):比较两个数组元素的 大小。,主函数:输入两个数组,调用large函数比较,计数,输出统计结果。,/*定义large函数*/large(int x,int y)int flag;if(xy)flag=1 else if(xy)flag=-1 else flag=0;return(flag);,运行输入:enter array a:1 3 5 7 9 8 6 4 2 0enter array b:5 3 8 9-1-3 5 6 0 4,运行结果::4=:1:5 a b,

15、二、数组名可以做函数的参数,由于数组名代表的就是数组在内存中存放区域的首地址。把数组名作为函数参数来实现大量数据的传递是一个非常好的数据传递方法。,在主调函数和被调函数中分别定义数组;,数组名可以做函数的参数的具体方法:,实参数组和形参数组类型应一致;,实参数组和形参数组大小不一定一致,形参数 组可以不指定大小(这里指一维数组)。,说明:数组名做函数的实参和形参时不是“值传 递”,而是“地址传递”。因此,形参数 组各元素的值如果发生变化会使实参数组 各元素的值发生同样的变化。,例:用选择法对数组中10个整数按由小到大排序.,程序设计:,函数sort(array,n):对数组元素按由小到大排序。

16、,主程序:输入array数组,调用 sort 函数比较,输 出排序后的array数组。,void sort(int array,int n)int v,j,k,t;for(i=0;in;i+)k=i;for(j=i+1;jn;j+)if(arrayjarrayk)k=j;t=arrayk;arrayk=arrayi;arrayi=t;,这是数组作形参时常使用的技巧,main()int a10,i;printf(“enter array:n”);for(i=0;i10;i+)scanf(“%d”,由于地址传递,实参数组 a 改变,数组名做参数的好处:,由于只需复制一个地址值,而无须复制全部需要处

17、 理的数据,因此节约存储空间并提高效率。,由于主调函数和被调函数是在相同的内存区域上对 数据进行操作,因此可以实现数据的同步更新。,三、多维数组可以做函数的参数,多维数组元素可以做实参多维数组名可以做参数,说明:,形参数组定义时可以指定或省略第一维的大小。,如:int array 310;或 int array 10;,但 int array 3;和 int array;,实参数组可以大于形参数组。,如:实参数组定义为:int array 510;形参数组定义为:int array 310;,这时形参数组只取实参数组的一部分,其余部分不起作用。,8.6 函数的嵌套调用,嵌套调用:在调用一个函数

18、的过程中,又调用另 一个函数。,嵌套定义:在定义一个函数时,该函数体内包含 另一个函数的定义。,C语言不能嵌套定义,但可以嵌套调用。在调用一个函数的过程中,又调用另一个函数。,例8.6 用弦截法求方程的根,本例较复杂,重点是了解如何将复杂的问题分解,然后在整合,最终解决问题。,数学函数(公式)为:y=f(x)=x 3-5x+16x-80=0,问题可转化为:求曲线与x轴交点的 x 坐标,1.解题方法:,在曲线上取两点P和 Q 坐标为(x1,f(x1)和(x2,f(x2),如果f(x1)和f(x2)符号相反,则(x1,x2)区间内必有一根,反之,改变 x1和 x2 的值,直到f(x1)和f(x2)

19、异号为止。,求连接P和 Q 点的线段与x轴的交点x。x=(x1*f(x2)-x2*f(x1)/(f(x2)-f(x1),如果 f(x)和 f(x1)符号相同,(x,x2)区间内必有一 根,此时将x作为新的x1。如果 f(x)和 f(x2)符号相同,(x 1,x)区间内必有一根,此时将x作为新的x2。,重复步骤 和,不断缩小(x1,x2)的距离,同时 f(x)越来越趋于0,直到|f(x)|。,2.程序设计:,函数 f(x):求 x 3-5x2+16x-80,函数 xpoint(x1,x2):求(x1,f(x1)和(x2,f(x2)的连线与x轴的交点x。,函数 root(x1,x2):求(x1,x

20、2)区间内的根。,程序流程图:,求f(x)函数流程图:,/*定义f函数的源程序*/float f(float x)float y;y=x*x*x-5.0*x+16.0*x-80.0;returu(y);,求xpoint(x1,x2)函数流程图:,/*定义xpoint函数的源程序*/float xpoint(float x1,float x2)float x;x=(x1*f(x2)-x2*f(x1)/(f(x2)-f(x1);return(x);,求root(x1,x2)函数流程图:,/*定义root函数的源程序*/float root(float x1,float x2)float x,y,y

21、1;y1=f(x1);do x=xpoint(x1,x2);y=f(x);if(y*y10)y1=y;x1=x;else x2=x;while(fabs(y)=0.0001);returu(x);,主函数流程图:,main()float x1,x2,f1,f2,x;do printf(“input x1,x2:n”);scanf(“%f,%f”,注意:由于程序中用到库函数fabs,故应在文件 的开头加上:#include“math.h”,上题函数的嵌套调用关系:,8.7 函数的递归调用,定义:在调用一个函数的过程中直接或间接 地调用该函数本身。,说明:不应出现无终止的递归调用,因此,应该 给定

22、一个限制递归次数的条件。,递归调用对应的一般算法:,递归函数的执行过程:,递归调用:记住本次现场,递归调用。,终了调用:返回上次调用现场。,例:用递归法求n!,算法:,main()int n,f;printf(“Input n:”);scanf(“%d”,int jx(int n)int f;if(n=1)f=1;else f=jx(n-1)*n;return f;,8.8 局部变量和全局变量,一、局部变量,定义:在函数内部或复合语句内部定义的变量,称作局部变量。,作用域:函数内或复合语句内。,注意:,主函数 main 定义的变量只在主函数中有效,主函数不能使用其它函数定义的变量。,不同函数中

23、的同名变量互不影响。,形参也是局部变量。,二、全局变量,定义:在函数外部定义的变量称作全局变量(也称外部变量)。,作用域:可以为本文件中所有的函数公用。,注意:,从定义变量的位置开始到本文件结束,这段 程序中的函数可直接使用外部变量。,如果在定义点之前的函数想使用外部 变量,则应该在该函数中用关键字 extern 作“外部 变量”说明。,如果在同一源文件中,外部变量和局部变量 同名,则在局部变量的作用范围内,外部变 量不起作用。,从程序设计的观点看使用全局变量:,优点:,增加了函数间数据联系 同一文件中的一些函数引用全局变量,当某个函数中改变了全局变量的值,其 它函数中的全局变量值也随之改变。

24、,函数可以得到多个返回值,缺点:,全局 变量在程序的全部执行过程中都占 用存储单元。,使用全局变量不符合程序设计中要求模块 间“强内聚性、弱偶合性”的原则。,使用全局变量过多,会降低程序的可读性 和可维护性。,8.9 变量的存储类别,一、静态存储方式和动态存储方式,静态存储方式:程序运行期间分配固定存储 空间的方式。,动态存储方式:程序运行期间根据需要进行 动态的分配存储空间的方式。,程序区,静态存储区,动态存储区,全局变量,局部静态变量,形式参数局部变量(自动)函数调用的现场保护和返回地址,二、静态存储变量和动态存储变量,静态存储变量:用静态存储方式存储的变量。,动态存储变量:用动态存储方式

25、存储的变量。,特点:在 静态存储区分配存储单元,整个程序 运行期间都不释放。,特点:函数开始调用时为变量分配存储空间,函数结束时释放这些空间。一个程序两 次调用同一函数,其中同一个局部变量 的内存地址可能不同。,存储类型:数据在内存中的存储方式。即静态存储方式和动态存储方式。通过存储分类符来表示。,三、变量的属性及其定义,数据类型:整型,实型,字符型,存储分类符:,auto(自动的)、register(寄存器的)static(静态的)、extern(外部的),定义变量的一般形式:,存储分类符 类型标识符 变量名;,如:auto int a;static int b;register int d

26、;,1.auto(自动的),例如:在一函数内有定义 auto int a;则定义a为自动变量(即存储类型是自 动的),其数据类型是整型的。,四、变量的存储类型,auto只适用于说明局部变量,该局部变量是 自动变量;,自动变量存放在动态存储区,属于动态存储变量;,此类变量的作用域是其所在的函数内部,即程序 在未进入函数之前或退出函数之后,其内部所定 义的所有自动变量都没有意义。,说明:,在一个函数内如果局部变量不作存储类 型说明,均为自动变量;,形式参数缺省存储类型是auto,但不能 将auto加在形参说明之前。,如:int b,c=3 等价于 auto int b,c=3;,如:int max

27、(auto int x,auto int y),2.static(静态的),static可用于说明,局部变量局部静态变量,全局变量外部静态变量,局部静态变量,局部静态变量作用域仅限于定义它的函数内部。,存放在静态存储区,整个程序运行期间都不释放。而自动变量函数调用结束后即释放。,编译时赋初值,每次调用时不再赋初值,只保 留调用结束时变量的值。而自动变量调用一次,重新赋值一次。,如果局部静态变量不赋初值,编译时自动赋0。而自动变量不赋初值,其值不确定。,例如:打印1!5!int fac(int n)static int f=1;f=f*n;return(f),main()int i;for(i=

28、1;i=5;i+)printf(“%d!=%dn”,i,fac(i);,外部静态变量,外部静态变量只能在本源程序文件中被使用,其他的源程序文件不能引用该静态全局变量。,全局变量(不论是否加static说明)编译时分配 在静态存储区。,3.register(寄存器的),寄存器:它是CPU中运算器的组成部分,用来暂 时存放数据的存储装置。,寄存器变量:直接放置在运算器的寄存器中的变量 称为寄存器变量。引入寄存器变量 是为了提高“存取”速度。,寄存器变量属于动态存储变量,但并不放在动态 存储区中,它放在寄存器中。,说明:,寄存器变量的作用域与自动变量相同。,regiser只适用于说明局部变量;,例如

29、:register int i;定义了i是寄存器变量,其数据类型是整型的。,由于计算机的寄存器数目有限,不宜定义太多 寄存器变量。不同的系统允许使用的寄存器个 数是不同的。,只有局部变量(非静态的)和形式参数可以作为寄存器变量。,例如:register static int i;,4.exturn(外部的),exturn只适用于说明全局变量;,在多个源程序文件组成的程序中,/*文件A.c*/int a;main(),例如:,/*文件B.c*/exturn int a;power(),也可以写成exturn a;,如果B文件中引用在A文件中定义的全局变量(该 全局变量不是static变量),需要

30、在B文件 中,用 关键字extern说明。,在同一个源文件中,全局变量的作用域之外的函 数中使用该全局变量时,也需用extern对其说明。,若在A文件中的全局变量是静态外部变量(static),则即使在B文件中用extern对其说明,也无法在 A文件中使用该全局变量。,/*文件A.c*/static int a;main(),例如:,/*文件B.c*/exturn int a;power(),无法使用变量a,8.10 内部函数和外部函数,一、内部函数,定义:如果一个函数只能被本文件中其它函数 调用,称为内部函数(又称静态函数)。,格式:,static 类型标识符 函数名(形参表),例如:sta

31、tic int fun(a,b).,作用:函数的作用域限于所在文件,不同文件中 同名函数互不干扰,便于程序的局部化。,二、外部函数,定义:如果一个函数允许被其它文件调用,称 为外部函数。,格式:,exturn 类型标识符 函数名(形参表),例如:exturn int fun(a,b).,int fun(a,b).,或,类型标识符 函数名(形参表),或,通常不加 static 标识符的函数都是外部函数。,在需要调用此函数的文件中,一般要用exturn说明所用的函数是外部函数。,本章作业:,1.编写并上机调试习题 8.1、8.3、8.7、8.10,2.预习本章其余内容和书中第九章(预处理命令)。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/施工/环境 > 农业报告


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号