C语言程序设计课件第7章用函数实现模块化程序设计.ppt
7.1 函数是什么7.2 函数的定义和调用7.3 函数的嵌套调用和递归调用7.4 数组作为函数参数7.5 变量的作用域和生存期,第7章 用函数实现模块化程序设计,P168,7.1 函数是什么,如果程序的功能比较多,规模比较大,把所有的程序代码都写在一个主函数中,就会使主函数变得庞杂、头绪不清,使阅读和维护程序变得困难。,P168,有时程序中要多次实现某一功能,就需要多次重复编写实现此功能的程序代码。这使程序冗长,不精炼。,7.1 函数是什么,P168,采用“组装”的办法简化程序设计过程事先编好一批函数实现各种不同的功能用到什么函数就直接装使用就可以这就是模块化的程序设计,7.1 函数是什么,P168,函数就是功能(Function)每一个函数用来实现一个特定的功能函数的名字应反映其代表的功能,7.1 函数是什么,P168,在设计一个较大的程序时,往往把它分为若干个程序模块,每一个模块包括一个或多个函数,每个函数实现一个特定的功能。,7.1 函数是什么,P168,一个程序可由一个主函数和若干个其他函数构成。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次,7.1 函数是什么,P168,7.1 函数是什么,P168,main,a,b,c,f,g,h,d,e,i,e,除了可以使用库函数外,还可以编写一些本领域或本单位常用到一些专用函数,供本领域或本单位的人员使用。、在程序设计中要善于利用函数,可以减少各人重复编写程序段的工作量,同时可以方便地实现模块化的程序设计。,7.1 函数是什么,P168,说明:(1)一个程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对于较大的程序,一般不把所有内容全放在一个源程序文件中,而是将它们分别放在若干个源文件中,由若干个源程序文件组成一个C程序。这样便于分别编写、分别编译,提高调试效率。一个源程序文件可以为多个C程序所调用。,说明:(2)一个源程序文件由一个或多个函数以及其他有关内容组成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不是以函数为单位进行编译的。,说明:(3)不论main函数出现在什么位置,总是从main函数开始执行。如果在main函数中调用其他函数,在调用后流程返回到main函数,在main函数中结束整个程序的运行。,说明:(4)所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。一个函数并不从属于另一个函数,即函数不能嵌套定义。函数间可以互相调用,但不能调用main函数。main函数是由系统调用的。,说明:(5)从用户使用的角度看,函数有两种。库函数,它是由系统提供的,用户不必自己定义而直接使用它们。应该说明,不同的C语言编译系统提供的库函数的数量和功能会有一些不同,当然许多基本的函数是共同的。用户自己定义的函数。它是用以解决用户专门需要的函数。,说明:(6)从函数的形式看,函数分两类。无参函数。函数没有参数,一般用来执行固定的一组操作。无参函数可以带回或不带回函数值,但一般以不带回函数值的居多。有参函数。在调用函数时,要给出实参。主调函数在调用被调用函数时,通过参数向被调用函数传递数据,一般情况下,执行被调用函数时会得到一个函数值,供主调函数使用。,7.2 函数的定义和调用,7.2.1 为什么要定义函数7.2.2 函数定义7.2.3 函数的调用 对被调用函数的声明和函数原型,P170,C语言要求,在程序中用到的所有函数,必须“先定义,后使用”指定函数名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。,7.2.1 为什么要定义函数,P170,指定函数的名字,以便以后按名调用指定函数类型,即函数返回值的类型指定函数参数的名字和类型,以便在调用函数时向它们传递数据指定函数的功能。这是最重要的,这是在函数体中解决的,7.2.1 为什么要定义函数,P170,如果程序中要调用库函数,只需用#include指令把有关的头文件包含到本文件模块中即可。如果想使用库函数中没有的函数,需要程序设计者在程序中自己定义。,7.2.1 为什么要定义函数,P170,7.2.2 函数定义,1.怎样定义无参函数函数名后面圆括号中空的,没有参数定义无参函数的一般形式为:类型名 函数名()函数体,P171,包括声明部分和语句部分,指定函数值的类型,7.2.2 函数定义,1.怎样定义无参函数函数名后面圆括号中空的,没有参数定义无参函数的一般形式为:类型名 函数名()函数体,P171,表示不需要带回函数值,void,7.2.2 函数定义,2.怎样定义有参函数定义有参函数的一般形式为:类型标识符 函数名(形式参数表列)函数体,P171,7.2.2 函数定义,2.怎样定义有参函数 int max(int x,int y)int z;if(xy)z=x;else z=y;return(z);,P171,求x和y二者中大者,7.2.3 函数的调用,1.调用无参函数的形式 函数名()如print_star()2.调用无参函数的形式 函数名(实参表列)如max(a,b),P172,如果有多个参数,用逗号隔开,例7.2 输入两个整数,输出二者中的大者。要求在主函数中输入两个整数,用一个函数max求出其中的大者,并在主函数中输出此值。,#include int max(int x,int y)int z;if(xy)z=x;else z=y;return(z);,参数类型,函数类型,定义函数,定义函数内使用的变量,c=max(a,b);(main函数)int max(int x,int y)(max函数)int z;z=xy?x:y;return(z);,#include void main()int max(int x,int y);int a,b,c;printf(”please input two number:”);scanf(“%d,%d”,形式参数,实际参数,函数调用的过程:,在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。,2,a,3,b,x,y,2,3,实参,形参,函数调用的过程:,2,a,3,b,x,y,2,3,实参,形参,调用结束,形参单元被释放实参单元仍保留并维持原值,没有改变如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值,调用函数的方式:,按函数在程序中出现的位置来分,可以有以下3种函数调用方式.函数语句调用没有返回值的函数,函数调用单独作为一个语句 如例7.1中的“print_star();”,调用函数的方式:,按函数在程序中出现的位置来分,可以有以下3种函数调用方式.函数表达式函数出现在一个表达式中,这种表达式称为函数表达式 如例7.2中的“c=max(a,b);”,调用函数的方式:,按函数在程序中出现的位置来分,可以有以下3种函数调用方式.函数参数函数调用作为一个函数的实参 如printf(%d,max(a,b);,对被调用函数的声明和函数原型,P175,在一个函数中调用另一个函数需要具备如下条件:(1)被调用函数必须是已经定义的函数(是库函数或用户自己定义的函数)。(2)如果使用库函数,应该在本文件开头加相应的#include指令。(3)如果使用自己定义的函数,而该函数的位置在调用它的函数后面,应该进行函数声明,对被调用函数的声明和函数原型,P175,函数原型的一般形式有两种:如 int max(int x,int y);int max(int,int);原型说明可以放在文件的开头,这时本文件中所有函数都可以使用此函数,7.3 函数的嵌套调用和递归调用,P177,7.3.1 函数的嵌套调用7.3.2 函数的递归调用,7.3.1 函数的嵌套调用,调用一个函数的过程中,又可以调用另一个函数,P177,7.3.1 函数的嵌套调用,P177,main函数,调用a函数,结束,a函数,调用b函数,b函数,7.4 数组作为函数参数,7.4.1 数组元素作函数实参7.4.2 数组名作函数参数,P184,7.4.1 数组元素作函数实参,由于实参可以是表达式,而数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参。,P185,7.4.2 数组名作函数参数,P186,希望在函数中处理整个数组的元素时,可以用数组名作为函数实参注意,此时只是将数组的首元素的地址传递给所对应的形参,因此对应的形参应当是指针变量(见第8章)。,例7.7 有10个学生成绩,用一个函数求全体学生的平均成绩。解题思路:在主函数中定义一个实型数组score,将输入的10个学生成绩存放在数组中设计函数average,用来求学生平均成绩需要把数组有关信息传递给average函数采取用数组名作为实参,把数组地址传给average函数,在该函数中对数组进行处理,#include void main()float average(float array10);float score10,aver;int i;printf(input 10 scores:n);for(i=0;i10;i+)scanf(%f,数组名作实参,float average(float array10)int i;float aver,sum=array0;for(i=1;i10;i+)sum=sum+arrayi;aver=sum/10;return(aver);,与score共占同一存储单元,实参、形参都是float型,相当于score0,相当于scorei,7.5 变量的作用域和生存期,7.5.1 变量的作用域-局部变量和全局变量7.5.2 变量的存储方式和生存期7.5.3 作用域和生存期的小结,P192,7.5.1 变量的作用域局部变量和全局变量,1 局部变量在函数和复合语句内定义的变量,称为内部变量或局部变量只在本函数或复合语句内范围内有效(从定义点开始到函数或复合语句结束)在此函数或复合语句以外是不能使用这些变量的,P192,2 全局变量一个程序可以包含一个或若干个源程序文件(即程序模块),而一个源文件可以包含一个或若干个函数在函数之外定义的变量是外部变量,也称为全局变量(或全程变量)全局变量的有效范围为从定义变量的位置开始到本源文件结束,在此范围内可以为本文件中所有函数所共用,2 全局变量在一个函数中既可以使用本函数中的局部变量,又可以使用有效的全局变量。如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”了,即它不起作用,此时局部变量是有效的。,7.5.2 变量的存储方式和生存期,变量的生存期:变量值存在的时间变量的两种存储方式:静态存储方式和动态存储方式静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式动态存储方式是在程序运行期间根据需要进行动态的分配存储空间的方式,P195,7.5.2 变量的存储方式和生存期,全局变量采用静态存储方式,在程序开始执行时给全局变量分配存储区,程序执行完毕释放。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放。,P195,7.5.2 变量的存储方式和生存期,在函数中定义的变量,在函数调用开始时分配动态存储空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的。,P195,7.5.2 变量的存储方式和生存期,每一个变量和函数都有两个属性:数据类型和数据的存储类别数据类型,如整型、浮点型等存储类别指的是数据在内存中存储的方式(如静态存储和动态存储),P195,1.auto声明自动变量(auto变量)函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属于此类在调用该函数时,系统给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明,int f(int a)auto int b,c=3;,可以省略,2.static声明静态变量以下情况需要指定static存储类别:希望函数中的局部变量值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量已有值,就是上一次函数调用结束时的值。这时就应用关键字static指定该局部变量为“静态局部变量”。,对静态局部变量的说明:(1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储区空间而不占静态存储区空间,函数调用结束后即释放,对静态局部变量的说明:(2)对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而对自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。,对静态局部变量的说明:(3)如在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不可知的。,对静态局部变量的说明:(4)虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的。因为它是局部变量,只能被本函数引用,而不能被其他函数引用。,对静态局部变量的说明:(5)用静态存储要多占内存(长期占用不释放,而不能像动态存储那样一个存储单元可供多个变量使用,节约内存),而且降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此,若非必要,不要多用静态局部变量。,3.register声明寄存器变量一般情况下,变量(包括静态存储方式和动态存储方式)的值是存放在内存中的寄存器变量允许将局部变量的值放在CPU中的寄存器中现在的计算机能够识别使用频繁的变量,从而自动地将这些变量放在寄存器中,而不需要程序设计者指定,4.extern声明外部变量的作用范围(1)在一个文件内扩展外部变量的作用域如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件结束如果由于某种考虑,在定义点之前的函数需要引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”,4.extern声明外部变量的作用范围(2)将外部变量的作用域扩展到其他文件在任一个文件中定义外部变量,而在另一文件中用extern对该变量作外部变量声明,7.5.3 作用域和生存期的小结,对一个变量的属性可以从两个方面分析,一是变量的作用域,一是变量的生存期。前者是从空间的角度,后者是从时间的角度。二者有联系但不是同一回事,P195,