资源描述
Edit Master title,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,本资料仅供参考,不能作为科学依据。谢谢。本资料仅供参考,不能作为科学依据。感谢,第七章,1/114,本章关键点,函数概念,函数定义与调用,函数递归调用,变量作用域,函数作用域,2/114,主要内容,7.1 函数概述,7.函数定义普通形式,7.函数参数和函数值,7.函数调用,7.函数嵌套调用,3/114,主要内容,7.6 函数递归调用,7.7 数组作为函数参数,7.8 变量作用域-局部变量和全局变量,7.9 变量存放方式和生存期,7.10 关于变量申明和定义,7.11 内部函数和外部函数,4/114,7.1 函数概述,一个程序可由一个主函数和若干个其它函数组成。一个较大程序可分为若干个程序模块,每一个模块用来实现一个特定功效。在高级语言中用子程序实现模块功效。子程序由函数来完成。,函数间调用关系:,由主函数调用其它函数,其它函数也能够相互调用。同一个函数能够被一个或多个函数调用任意屡次。,5/114,6/114,例7.1,函数调用简单例子,#include,void main(),void printstar();,/*对printstar函数申明*/,void print_message();,/*对print_message函数申明*/,printstar();,*调用printstar函数*,print_message();,/*调用print_message函数*/,printstar();,*调用printstar函数*/,7/114,void printstar(),*定义printstar函数*,printf(*n);,void print_message(),*定义print_message函数*,printf(How do you do!n);,运行情况以下:,*,How do you do!,*,8/114,说明:,1.一个程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对于较大程序,通常将程序内容分别放在若干个源文件中,再由若干源程序文件组成一个,C,程序。这么便于分别编写、分别编译,提升调试效率。一个源程序文件能够为多个C程序公用。,9/114,说明:,2.一个源程序文件由一个或多个函数以及其它相关内容(如命令行、数据定义等)组成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译,而不是以函数为单位进行编译。,10/114,说明:,3.程序执行是从main函数开始,假如在main函数中调用其它函数,在调用后流程返回到main函数,在main函数中结束整个程序运行。,11/114,说明:,4.全部函数都是平行,即在定义函数时是分别进行,是相互独立。一个函数并不隶属于另一函数,即函数不能嵌套定义。函数间能够相互调用,但不能调用main函数。main函数是系统调用。,12/114,说明:,5.从用户使用角度看,函数有两种:,标准函数,即库函数。这是由系统提供,用户无须自己定义这些函数,能够直接使用它们。不一样C系统提供库函数数量和功效会有一些不一样,但许多基本函数是共同。,用户自己定义函数。用以处理用户专门需要。,13/114,说明:,6.从函数形式看,函数分两类:,无参函数。无参函数普通用来执行指定一组操作。在调用无参函数时,主调函数不向被调用函数传递数据。,有参函数。主调函数在调用被调用函数时,经过参数向被调用函数传递数据。,14/114,7.函数定义普通形式,7.2.1.为何要定义函数,C语言要求,在程序中用到全部函数,必须“先,定义,后使用”。定义函数包含以下几个内容:,指定函数名字,方便以后按名调用。,指定函数类型,函数值类型。,指定函数参数名字和类型,方便在调用函数时向它们传递数据。对无参函数不需要这项。,指定函数应该执行什么操作,也就是函数是做什么,即函数功效。这是最主要。,15/114,7.函数定义普通形式,7.2.1.为何要定义函数,对于C编译系统提供库函数,是由编译系统事先,定义好,程序设计者无须自已定义,只需#include,命令把相关头文件包含到本文件模块中即可。,比如,在程序中若用到数学函数(如sqrt,fabs,sin,cos,等),就必须在本文件模块开头写上:,#include,16/114,7.函数定义普通形式,7.2.2 怎样定义无参函数,定义无参函数普通形式为,:,类型标识符,函数名,(),申明部分,语句部分,17/114,7.函数定义普通形式,7.2.3 怎样定义有参函数,定义有参函数普通形式为,:,类型标识符,函数名,(形式参数表列),申明部分,语句部分,比如:,(int,int),;,/*函数体中申明部分*,?;,return();,18/114,7.函数定义普通形式,7.2.4 定义空函数,定义空函数普通形式为,:,类型标识符,函数名,(),比如:,void dummy(),主调函数调用空函数时,只表明这里要调用一个函数,但函数本身什么工作也不做等,以后扩充函数功效时补充上。,19/114,7.函数参数和函数值,7.形式参数和实际参数,形式参数:,函数名后面括弧中变量名称为“形式参数”(简称“,形参,”);,实际参数:,主调函数中调用一个函数时,函数名后面括弧中参数(能够是一个表示式)称为“实际参数”(简称“,实参,”);,函数返回值:,return后面括弧中值作为函数带回值(称,函数返回值,)。,20/114,主调函数和被调用函数之间有数据传递关系。在不一样函数之间传递数据,能够使用方法有:,参数:经过形式参数和实际参数,返回值:用return语句返回计算结果,全局变量:外部变量,21/114,例7.输入两个整数,要求用一个函数求出其中大者,并在主函数中输出此值。,#include,void(),int max(int,int);,/*对函数申明*/,int,;,scanf(,);,(,);,printf(,);,22/114,int max(int,int),*定义有参函数max*,int;,?;,return();,运行情况以下:,,,23/114,经过函数调用,可使两个函数中数据发生联络。,24/114,关于形参加实参说明:,1.,在定义函数中指定形参,在未出现函数调用时,它们并不占内存中存放单元。只有在发生函数调用时,函数max中形参才被分配内存单元。在调用结束后,形参所占内存单元也被释放。,2.,实参能够是常量、变量或表示式,,比如:,max(,);,但要求它们有确定值。在调用时将实参值赋给形参。,25/114,3.,在被定义函数中,必须指定形参类型。,4.,实参加形参类型应相同或赋值兼容。,5.,实参向形参数据传递是单向,“值传递”,,只能由实参传给形参,而不能由形参传回来给实参。在调用函数时,给形参分配存放单元,并将实参对应值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。,26/114,7.函数参数和函数值,7.3.2 函数返回值,函数返回值,是经过函数调用使主调函数得到确实定值。,比如:,例8.中,max(,)值是,max(,)值是5。赋值语句将这个函数值赋给变量。,27/114,说明:,1.函数返回值是经过函数中return语句取得。,一个函数中能够有一个以上return语句,执行到哪一个return语句,哪一个语句起作用。,return语句后面括弧也能够不要,比如:,“return;”等价于“return();”,return后面值能够是一个表示式。,比如:,(int,int),return,(,?:);,28/114,2.函数返回值应该属于某一个确定类型,在定义函数时指定函数返回值类型。,比如:,下面是3个函数首行:,int,max,(float,float),/*函数值为整型*/,char,letter,(char c1,char c2),/*函数值为字符型*/,double,min,(int,int),/*函数值为双精度型,*/,注意:,凡不加类型说明函数,自动按整型处理。,29/114,3.在定义函数时指定函数类型普通应该和return语句中表示式类型一致。,假如函数值类型和return语句中表示式值不一致,则以函数类型为准。对数值型数据,能够自动进行类型转换。即函数类型决定返回值类型。,4.对于不带回值函数,应该用“void”定义函数为“无类型”(或称“空类型”)。此时在函数体中不得出现return语句。,30/114,例 7.返回值类型与函数类型不一样,#include,void main(),int(float,float);,float,;,int;,scanf(,);,(,);,printf(,);,int max(float,float),float;/*z为实型变量*/,?;,return();,运行情况以下:,,,Max is ,31/114,7.函数调用,7.4.1 函数调用普通形式,函数调用普通形式为:,函数名,(实参表列),说明:,1.,假如是调用无参函数,则“实参表列”能够没有,但括弧不能省略。,2.,假如实参表列包含多个实参,则各参数间用逗号隔开。实参加形参个数应相等,类型应匹配。实参加形参按次序对应,向形参传递数据。,32/114,假如实参表列包含多个实参,对实参求值顺,序并不是确定,有系统按自左至右次序求实参,值,有系统则按自右至左次序。,例,如:,(,+);,若原值为,在 VC+6.0环境下运行结果,不是“3,4”,而为“4,4”。因为按自右而左次序,先求,+i得4,再向左进行,此时i已是4了。,假如想输出3和4,应写成:,i=3;,j=i+;,printf(”%d,%d”,i,j);,33/114,7.函数调用,7.4.2 函数调用方式,函数语句,把函数调用作为一个语句。这时不要求函数带回值,只要求函数完成一定操作。,函数表示式,函数出现在一个表示式中,这种表示式称为,函数表示式,。这时要求函数带回一个确定值以参加表示式运算。比如:,*(,);,按函数在程序中出现位置来分,能够有,以下三种函数调用方式:,34/114,函数参数,函数调用作为一个函数实参。,比如:,m=max(a,max(b,c),);,其中max(b,c)是一次函数调用,它值作为max另一次调用实参。m值是a、b、c三者中最大者。,35/114,7.函数调用,7.4.3 对被调用函数申明和函数原型,在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢?,1.首先被调用函数必须是已经存在函数(是库函数或用户自己定义函数)。但光有这一条件还不够。,36/114,3.假如使用用户自己定义函数,而该函数位置在调用它函数(即主调函数)后面,应该在主调函数中对被调用函数作申明。,2.假如使用库函数,还应该在本文件开头用#include 命令将调用相关库函数时所需用到信息“包含”到本文件中来。,37/114,例7.4 对被调用函数作申明,#include,void main(),float add(float x,float y);,*对被调用函数add申明*,float a,b,c;,scanf(f,f,a,b);,cadd(a,b);,printf(sum is f n,c);,float add(float,float),*函数首部*,float;,/*函数体*/,z;,return(z);,运行情况以下:,3.6,6.5,Sum is 10.100000,38/114,函数原型普通形式为:,1.函数类型 函数名(参数类型1,参数类型2);,2.函数类型 函数名(参数类型1,参数名1,参数类型2,参数名2);,申明作用是把函数名、函数参数个数和参数类型等信息通知编译系统,方便在碰到函数调用时,编译系统能正确识别函数并检验调用是否正当。,39/114,注意:,函数“定义”和“申明”不是一回事。,函数定义是指对,函数功效确实立,,包含指定函数名,函数值类型、形参及其类型、,函数体,等,它是一个完整、独立函数单位。,函数申明作用则是把函数名字、函数类型以及形参类型、个数和次序通知编译系统,方便在调用该函数时系统按此进行对照检验。它不包含,函数体,。,40/114,说明:,(1)假如被调用函数定义出现在主调函数之前,能够无须加以申明。,(2)假如已在文件开头(在全部函数之前),已对本文件中所调用函数进行了申明,则在各函数中无须对其所调用函数再作申明。,41/114,例7.5(例7.4改写),#include,float add(float,float),*函数首部*,float;,z;,return(z);,void main(),/*无须再对add函数作申明*/,float a,b,c;,scanf(f,f,a,b);,cadd(a,b);,printf(sum is f n,c);,42/114,7.函数嵌套调用,嵌套定义就是在定义一个函数时,其函数体内又包含另一个函数完整定义。,43/114,在主函数中调用一个max_4函数来求4个整数中最大数。然后在max_4函数中再调用一个max_2函数来求2个整数中最大数。最终在主函数中输出结果。,方法:,例7.6,输入4个整数,找出其中最大数。用函数嵌套调用来处理。,44/114,#include,void main(),int max_4(int a,int b,int c,int d);/*max_4函数申明*/,int a,b,c,d,max;,printf(Please enter 4 interger numbers:);,scanf(%d%d%d%d,max=max_4(a,b,c,d);/*调用max_4函数*/,printf(max=%d n,max);,int max_4(int a,int b,int c,int d)/*max_4函数定义*/,int max_2(int,int);/*max_2函数申明*/,int m;,45/114,m=max_2(a,b);/*调用max_2函数*/,m=max_2(m,c);/*调用max_2函数*/,m=max_2(m,d);/*调用max_2函数*/,return(m);/*函数返回值是4个数中最大者*/,/*max_4函数定义*/,int max_2(int a,int b),if(ab),return a;,else,return b;/*函数返回值是a和b中大者*/,运行情况以下:,Please enter 4 interger numbers:11 45 54 0,max=45,46/114,7.6 函数递归调用,在调用一个函数过程中又出现直接或间接地调用该函数本身,称为函数递归调用。语言特点之一就在于允许函数递归调用。,比如:,int f(int),,;,();/*在执行f函数过程中又要,调用f函数*/,return(*);,47/114,例 7.7:,有个人坐在一起,问第个人多少岁?他说比第个人大岁。问第个人岁数,他说比第个人大岁。问第个人,又说比第个人大岁。问第个人,说比第个人大岁。最终问第个人,他说是岁。请问第个人多大。,age(5)=age(4)+2,age(4)=age(3)+2,age(3)=age(2)+2,age(2)=age(1)+2,age(1)=10,能够用数学公式表述以下:,age(n)=10(),age(n-1)+2(),48/114,能够用一个函数来描述上述递归过程:,int age(int),*求年纪递归函数*,int;,*用作存放函数返回值变量*,if();,else ();,return();,运行结果以下:,用一个主函数调用age函数,求得第5人年纪。,#include,void main(),printf(,age();,49/114,例7.8 用递归方法求!,求!也能够用递归方法,即!等于!,而!。,可用下面递归公式表示:,!,(,),=()!(),50/114,程序以下:,#include,void main(),long fac(int n);/*对fac函数申明*/,int n;,long y;,printf(input an integer number:);,scanf(%d,y=fac(n);,printf(%d!=%ldn,n,y);,51/114,long fac(int n)/*定义fac函数*/,long f;,if(n0),printf(n%cn,x,y);,56/114,运行情况以下:,input the number of diskes:3,The steps to noving 3 diskes:,57/114,7.7 数组作为函数参数,7.7.1 数组元素作函数实参,因为实参能够是表示式,而数组元素能够是表示式组成部分,所以数组元素能够作为函数实参,与用变量作实参一样,是单向传递,即“值传送”方式。,58/114,例 7.10,有两个数组和,各有个元素,将它们对应地逐一相比(即与比,与比)。假如数组中元素大于数组中对应元素数目多于b数组中元素大于a数组中对应元素数目(比如,aibi6次,biai3次,其中i每次为不一样值),则认为a数组大于b数组,并分别统计出两个数组对应元素大于、等于、小于次数。,59/114,#include,void main(),int large(int x,int y);,/*函数申明*/,int 10,10,,;,printf(enter array a);,for(;),scanf(,);,printf();,printf(enter array);,for(;),scanf(,);,printf();,for(;),if(large(i,i)=);,else if(large(i,i)=)=+;,else;,60/114,printf(aibi%d timesnai=bi%d,timesnaik)printf(array a is larger than array bn);,else if(nB?A:B;,if(Cm)m=C;,return(m);,运行结果为:,Please enter three integer numbers:,34 21 78,max is 78,99/114,2.将外部变量作用域扩展到其它文件,#include,int A;,/*定义外部变量*/,void main(),int(int);,/*函数申明*/,int,;,printf(enter the number a and its power m:n);,scanf(,A,);,A*;,printf(*,A,);,();,printf(*n,A,);,例7.20,用extern将外部变量作用域扩展到其它文件。本程序作用是给定值,输入和,求和am值。文件file.中内容为:,100/114,文件file中内容为:,extern A;,/*申明A为一个已定义外部变量*/,int(int);,int,;,for(;),*A;,();,101/114,3.将外部变量作用域限制在本文件中,在程序设计中,一些外部变量只限于被本文件引用,而不能被其它文件引用。这时能够在定义外部变量时加一个申明。,比如:,file1.c file2.c,static int A;extern int A;,void main()void fun(int n),A=A*n;,102/114,7.9.2 全局变量存放类别,用static 申明一个变量作用是:,(1)对局部变量用static申明,把它分配在静态存放区,该变量在整个程序执行期间不释放,其所分配空间一直存在。,(2)对全局变量用static申明,则该变量作用域只限于本文件模块(即被申明文件中)。,注意:,用auto、register、static申明变量时,是在定义变量,基础上加上这些关键字,不能单独使用。下面使用方法不对:,int a;/*先定义整型变量a*/,static a;/*再对变量a申明为静态变量*/,103/114,7.9 变量存放方式和生存期,7.9.3 存放类别小结,从作用域角度分,有局部变量和全局变量。它们采取存放类别以下:,局部变量包含:,自动变量、静态局部变量、存放器变量。,形式参数能够定义为自动变量或存放器变量,全局变量包含:,静态外部变量、外部变量,104/114,(2)从变量存在时间来区分,有动态存放和静态存放两种类型。静态存放是程序整个运行时间都存在,而动态存放则是在调用函数时暂时分配单元。,动态存放:自动变量、存放器变量、形式参数,静态存放:态局部变量、静态外部变量 、外部变量,105/114,(3)从变量值存放位置来区分,可分为:,内存中静态存放区:静态局部变量、静态外部变量、,外部变量,内存中动态存放区:自动变量和形式参数,CPU中存放器:存放器变量,106/114,(4),static,对局部变量和全局变量作用不一样。对局部变量来说,它使变量由动态存放方式改变为静态存放方式。而对全局变量来说,它使变量局部化,但仍为静态存放方式。从作用域角度看,凡有static申明,其作用域都是局限,或者是局限于本函数内,或者局限于本文件内。,107/114,7.10 关于变量申明和定义,对变量而言,申明与定义关系稍微复杂一些。在申明部分出现变量有两种情况:一个是需要建立存放空间(如:int a;),另一个是不需要建立存放空间(如:extern a;)。前者称为“,定义性申明,”(defining declaration),或简称,定义,(definition)。后者称为“,引用性申明,”(referencing declaration)。广义地说,申明包含定义,但并非全部申明都是定义。对“int a;”而言,它既是申明,又是定义。而对“extern a;”而言,它是申明而不是定义。,108/114,普通为了叙述方便,把,建立存放空间申明称定义,,而,把不需要建立存放空间申明称为申明,。显然这里指申明是狭义,即非定义性申明。比如:,void main(),extern A;,/*是申明不是定义。申明A是一,个已定义外部变量*/,int A;,109/114,7.11 内部函数和外部函数,依据函数能否被其它源文件调用,将函数区分为,内部函数,和,外部函数,。,7.11.1内部函数,假如一个函数只能被本文件中其它函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型前面加static。即,static 类型标识符 函数名(形参表),比如:,static int fun(int a,int b),110/114,7.11.2 外部函数,(1)定义函数时,假如在函数首部最左端加关键字extern,则表示此函数是外部函数,可供其它文件调用。比如,函数首部能够写为extern int fun(int a,int b),这么,函数fun就能够为其它文件调用。假如在定义函数时省略extern,则隐含为外部函数。,(2)在需要调用此函数文件中,用extern对函数作申明,表示该函数是在其它文件中定义外部函数,111/114,例 7.21有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现,File.c(文件),#include,void main(),extern void enter_string(char str);,extern void detele_string(char str,char ch);,extern void print_string(char str);,*以上3行申明在本函数中将要调用在其它文件中定义3个函数*,char c;,char str80;,scanf(%c,detele_string(str,c);,print_string(str);,112/114,file(文件),#include,void enter_string(char str80),*定义外部函数,enter-string*,gets(str);,*向字符数组输入字符串*,file(文件),void delete_string(char str,char ch),*定义外部函数,delete_string*,int i,j;,for(i=j=0;stri!=0;i+),if(stri!=ch),strj+=stri;,stri=0;,113/114,file(文件),#include,void print_string(char str),printf(%sn,str);,运行情况以下:,(输入),(输入要删去字符),(输出已删去指定字符字符串),114/114,
展开阅读全文