资源描述
第八章函数疗者先加陶然旗但5您第八步第八章函数本章要点函数的概念函数的定义与调用函数的递归调用变量的作用域函数的作用域第八章函数主要内容8.1 概述8.2 函数定义的一般形式8.3函数参数和函数的值8.4 函数的调用8.5 函数的嵌套调用8.6 函数的递归调用8.7 数组作为函数参数8.8 局部变量和全局变量8.9 变量的存储类别8.10 内部函数和外部函数第八章函数8.1概述第八章函数 I8.1概述一个c程序可由一个主函数和若干个其他函数构 成。一个较大的程序可分为若干个程序模块,每一个模 块用来实现一个特定的功能。在高级语言中用子程序实现模块的功能。子程序由 函数来完成。函数间的调用关系:由主函数调用其他函数,其他 函数也可以互相调用。同一个函数可以被一个或多 个函数调用任意多次。第八章函数例8.1 一个函数调用的简单例子#include void main()void printstarQ;/*对printstar函数声明*/void print_message();/*对print message函数声 明*/printstar();print_message();printstarQ;/*调用printstar函数*/*调用 printmessage 函数*/*调用printstar函数*/第八章函数void printstarQ/*定义printstar函数*/printf(*n),void print_message()/*定义print message函数*/printf(uHow do you do!nu);运行情况如下:vix XT%How do you do!%!y?x:y;return(z);第八章函数 一8.2.3空函数定义空函数的一般形式为:类型标识符函数名()例如:void dummyO 王调函数调用空函数时,只表明 这里要调用一个函数。函数本身什么工作也不做,以后 扩充函数功能时补充上。第八章函数8.3函数参数和函数的值形参、实参和函数返回值第八章函数 一8.3函数参数和函数的值8.3.1形式参数和实际参数形式参数:函数名后面括号中的变量名称为“形式参数”(简称“形参”)。实际参数:主调函数中调用一个函数时,函数名 后面括号中的参数称为“实际参数”(简称“实 参”)。函数返回值:re turn后面的括号中的值作为函 数带回的值。例8.2调用函数时的数据传递#include void m a i n()(int max(int x 9int y);/*对m a x 函数的声明*/int a,b,c;scanf(%d,%d ,&a,&b);c=ma x(a,b);printf(Max i s%d ,c);int max(int x,int y)/*定义有参函数max*/Et z;运行情况如下:z=xy?x:y;7,8return(z);Max i s 8第八章函数通过函数调用,可使两个函数中的数据发生联系。c=max(a,b);(main 函数)-:-;,一int max(int x,int y)(max 函数)int z;z=xy?x:y;return(z);)关于形参与实参的说明:(1)定义函数中指定的形参,未出现函数调用 时,不占内存中的存储单元。(2)实参可以是常量、变量或表达式,例如:max(3,a+b);在调用时将实参的值赋给形参。在被定义的函数中,必须指定形参的类型。int max(int x,int y)int z;z=xy?x:y;return(z);第八章函数实参与形参的类型应相同或赋值兼容。c=max(a,b);(main 函数)-:-|int max(int x,int y)(max 函数)int z;z=xy?x:y;return(z);)值传递:实参向形参的数据传递是单向“值 传递”。只能由实参传给形参。第八章函数 一8.3.2函数的返回值函数的返回值是通过函数调用使主调函数 得到的确定值。例如:例8.2中,max(2,3)的值是3,max(5,2)的值是5。说明:函数的返回值是通过函数中的return语句获得的。c=max(a 9 b);(main 函数)_int max(int x int y)(max 函数)int z;z=xy?x:y;return(z);Ireturn语句后面的括弧也可以不要例如:“return z;”等价于“return(z);”return后面的值可以是一个表达式。例或口:max(int x)int y)return(x y?x:y);第八章函数(2)定义函数时指定函数返回值的类型o例如:int max(float x,float y)char letter(char cl,char c2)double min(iiit x,int y)注意:凡不加类型说明的函数,自动按整型处理。第八章函数定义函数时指定的函数类型一般和return语句中表 达式类型一致。如果不一致,则以函数类型为准。(4)对于不带回值的函数,应当用“void”定义函数为“无类型”(或称“空类型”)o此时在函数体中不得 出现return语句。例 8.3 返回值类型与函数类型不 运行情况如下:#include 5 2 5void main()一1 int m a x(float x afloat y);ax 1 sfloat a,b;int c;scanf(n%f,%f a,&b);c=m a x(a 5 b);printf(n M a x i s%dn”,c);int max(float x,float y)float z;/*z为实型变量刃z=x y?x:y;return(z);(9第八章函数8.4函数的调用函数调用的一般形式,函数调用的方式,函数原型第八章函数8.4函数的调用8.4.1函数调用的一般形式函数调用的一般形式为:函数名(实参表列)说明:如果是调用无参函数,则“实参表列”可以没有。如果实参表列包含多个实参,则各参数间用逗号隔开。(3)如果实参表列包括多个实参,对实参求值的顺序并 不是确定的,有的系统按自左至右顺序求实参的值,有 的系统则按自右至左顺序。例8.4实参求值的顺序#include void main()int f(int a,int b);/*函数声明*/int i=2,p;p=f(i,+i);/*函数调用*/printf(H%diin,p);int f(int a,int b)/*函数定义*/int c;if(ab)c=l;else if(a=b)c=0;else c=-l;return(c);第八章函数对于函数调用第八章函数 81MMi8.4.2函数调用的方式按函数在程序中出现的位置来分,可以有以下三种 函数调用方式:1.函数语句把函数调用作为一个语句。这时不要求函数带回值,只要求函数完成一定的操作。例如:printstar();2.函数表达式函数出现在一个表达式中,这种表达式称为函数表达式。例出口:c=2*m a x(a,b);第八章函数3.函数参数函数调用作为一个函数的实参。例如:m=max(a,max(b 5 c);其中max(b,c)是一次函数调用,它的值作为 max另一次调用的实参。第八章函数8.4.3对被调用函数的声明和函数原型1.被调用的函数必须是已经存在的函数(是库函数或 用户自己定义的函数)。2.使用库函数,应该在本文件开头用#111(3111(16命令 将调用有关库函数时所需用到的信息“包含”到文 件中来。3.使用用户自己定义的函数,应该在主调函数中对被 调用的函数作声明。&S JI TtYl 米 Zt例8.5对被调用的函数作声明#include void main()float add(float x,float y);/*对被调用函数add的声明*/float%b,c;scanf(%f,%,&a,&b);c=add(a5b);printf(sum is%f n ,c);float add(float x,float y)/*函数首部*/float z;/*函数体*/z=x+y;return(z);第八章函数函数原型的一般形式为:1.函数类型 函数名(参数类型1,参数类型2);2.函数类型 函数名(参数类型1参数名1,参数类型2 参数名2);声明的作用是把函数名、函数参数的个数和参数 类型等信息通知编译系统,以便在遇到函数调用时,编 译系统能正确识别函数并检查调用是否合法。第八章函数 注意:函数的“定义”和“声明”的区别:函数的定义是指对函数功能的确立,包括指定函 数名,函数值类型、形参及其类型、函数体等,它是 一个完整的、独立的函数单位。函数的声明的作用则是把函数的名字、函数类型 以及形参的类型、个数和顺序通知编译系统,以便 在调用该函数时系统按此进行对照检查。第八章函数TUIZCLH HMI/PPIQITV PQPCQ例8.5对被调用的函数作声明#include float add(float x 用oat y)float z;z=x+y;return(z);void main()/*函数首部*/*函数体*/float a,b,c;scanf(%f,%f ,&a,&b);c=add(a5b);printf(n sum is%f n”,c);第八章函数8.5函数的嵌套调用第八章函数 一8.5函数的嵌套调用嵌套定义就是在定义一个函数时,其函数体内又包含 另一个函数的完整定义。嵌套定义就是在定义一个函数时,其函数体内又包含第八章函数1.取两个不同Axl,x2,如果f(xl)和f(x2)符号相反,则(xl,x2)区间内必有一个根。如果f(xl)与f(x2)同符 号,则应改变xl,x2,直到f(xl)、f(x2)异号为止。2.连接(xl,f(xl)和(x2,f(x2)两点,此线(即弦)交 X,由于X。3.若f(x)与f(xl)同符号,则根必在(x,x2)区间内,此 时将x作为新的xl。如果f(x)与f(x2)同符号,则表示 根在(xl,x)区间内,将x作为新的x2。4.重复步骤(2)和(3),直到|f(x)|s为 止,8为一个很小的数,例如10-6.此时认为 f(x)0 o第八章函数实现各部分功能的几个函数:1.用函数f(x)代表x的函数:x3-5x2+16x-80。2.用函数调用xpoint(xl,x2)来求用1,f(xl)和(x2,f(x2)的连线与x轴的交点x的坐标。3.用函数调用root(xl,x2)来求用1,x2)区间的 那个实根。显然,执行root函数过程中要用到函 数xpoint,而执行xpoint函数过程中要用到f函数。第八章函数#include#include float f(float X)/*定义 f 函数,以实现f(x)=x3-5x2+16x-80*/(float y;y=(x-5.0)*x+1 6.0)*x-8 0.0;return(y);第八章函数float xpoint(float xl5float x2)(float y;y=(x l*f(x 2)-x 2*f(x 1)/(f(x 2)-f(x 1);return(y);/*定义xpoint函数,求出弦与x轴交点*/xi0)-x2/(xi)X-/(、2)一/(X1)第八章函数float root(float x 1 afloat x 2)/*定义root函数,求近似根*/float x,y,y 1;y 1=f(x 1);do x=xpoint(x l,x 2);y=f(x);if(y*y 1 0)/*f(x)与 f(x 1)同符号*/y 1=y;x 1=x;else x 2=x;while(fabs(y)=0.0001);return(x);第八章函数TS1NGHUA UNIVERSITY PRESSvoid main()float x 1,x 2,f 1,f 2,x;主函数doprintf(46input x 1,x 2:n);scanf(%f,%f ,&x 1,&x 2);f 1=f(x 1);f 2=f(x2);while(f 1*f 2=0);x=root(x 1,x 2);printf(n A root of equation is%8.4 f n ,x);运行情况如下:i nput x1,x2:2,6A root of equation is 5.0000第八章函数第八章函数8.6函数的递归调用第八章函数 一8.6函数的递归调用在调用一个函数的过程中又出现直接或间接地 调用该函数本身,称为函数的递归调用。第八章函数例8.7:有5个人坐在一起,问第5个人多少岁?他说 比第4个人大2岁。问第4个人岁数,他说比第3个人 大2岁。问第3个人,又说比第2个人大2岁。问第2 个人,说比第1个人大2岁。最后问第1个人,他说是 1 0岁。请问第5个人多大。age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(l)=10用数学公式表述如下:age(n)=10(n=1)age(n-l)+2(n 1)第八章函数例8.8用递归方法求n求n!也可以用递归方法,即4!=3!x 4 1!=1 o可用下面的递归公式表示:n!=1n (n-1)!5!等于4!x 5,而(n=0,1)(n 1)第八章函数8.7数组作为函数参数第八章函数8.7数组作为函数参数8.7.1数组元素作函数实参数组元素可以作为函数的实参,与用变量作实参 一样,是单向传递,即“值传送”方式。第八章函数.TSJNGHlNiySJTY PRESS例 8.10有两个数组a和b,各有1 0个元素,将它们对应地 逐个相比(即a 0 与b 0 比,a 1 与b 1 比.)o如果a数组中的元素大于b数组中的相应元素的数目多于b数组中元素大于a数组中相应元素 的数目(例如,a i b i 6次,b i a i 3次,其中i每 次为不同的值),则认为a数组大于b数组,并分别统计 出两个数组相应元素大于、等于、小于的次数。#include void main()int large(int x,int y);/*函数声明*/int a 10,b 10,i,n=0,m=0,k=0;printf(rrenter array a:n);for(i=0;i 1 0;i+=)scanf(d a i);printf(n);printf(enter array b:n);for(i=0;i 1 0;i+=)scanf(rr%d,&b i);printf(rr n);for(i=0;i bi%d timesnai=bi%dtimesnaik)printf(Harray a is larger than array bnH);else if(n y)flag=1;else if(x y)flag=1;else flag=0;return(flag);第八章函数8.7.2数组名作函数参数用数组名作函数参数时,此时形参应当用数 组名或用指针变量。例8.11有一个一维数组score,内放10个学生成绩,求平均成绩。BAOM#include void main()float average(float array10);I*函数声明*/float scoreflO 5 aver;int i;printf(input 1 0 scores:n);for(i=0;i 1 0;i+=scanf(n%f n,&score i);printf(n);aver=average(score);printf(average score is%5.2 f n”,aver);第八章函数.float average(float array10)I int i;H float aver,sum=arrayO;I for(i=1;i 1 0;i+=)s u m=s u m+a r r a y i;.aver=sum/10;I return(aver);运行情况如下:I input 1 0 scores:I 100 56 7 8 98.5 76 87 99 67.5 7|average score is 83.40笛八音函新例8.1 2形参数组不定义长度#include void main()float average(float array 9int n)float score l 5=9 8.5,9 7,91.5,6 0,5 5;float score_210=67.5,89.5,99,6 9.5,77,89.5,76.5,54,60,99.5;printf(the average of class A is%6.2Rn”,average(score_l55);printf(the average of class B is%6.2nn”,a ver age(score_24 0);第八章函数float average(float array9mt n)int i;float aver,sum=arrayO;for(i=1;i n;i+=sum=sum+array i;aver=sum/n;return(aver);运行结果如下:the average of class A is 80.40The average of class B is 78.20第八章函数例813用选择法对数组中10个整数按由小 到大排序。所谓选择法就是先将10个数中最小的 数与a 0对换;再将a 1到a 9中最小的数 与a 1对换.每比较一轮,找出一个未经排序的数中最小的一个。共比较9轮。第八章函数未排序时的情况:a0 al a2 a3 a43 6 1 9 4将5个数中最小的数1与a0对换:1 6 3 9 4将余下的4个数中最小的数3与al对换1 3 6 9 4将余下的3个数中最小的数4与a2对换1 3 4 9 6将余下的2个数中最小的数6与a3对换1 3 4 6 9MAOM程序:#include void main()void sort(int array5int n);int a 10,i;printf(enter the array);for(i=0;i 1 0;i+)scanf(%d”,&a i);sort(a 51 0);printf(the sorted array:n);for(i=0;i 1 0;i+)printf(%d,a i);printf(n);第八章函数void sort(int array4nt n)/女排序函数女/int i,j,k,t;for(i=0;i n 1;i+)k=i;for(j=i+1;j n;j+)if(ar r ay j array k)k=j;t=array k;array k=arr ay i;array i=t第八章函数8.7.3.多维数组名作函数参数用多维数组名作为函数实参和形参。在被调函数 中对形参数组定义时可以指定每一维的大小,也可 以省略第一维的大小。程序:#include void main()max_value(int array 4);int 3114=1,3,5,7,2,4,6,8,15,17,34,12;printf(rrmax value is%d n”,max_value(a);第八章函数max_value(int array4)int i,j,k,max;max=array 0 0;for(i=0;i 3;i+)for(j=0;j max)max=array ij;return(max);运行结果如下:Max value is 34第八章函数8.8局部变量和全局变量第八章函数8.8局部变量和全局变量8.8.1局部变量内部变量:在一个函数内部定义的变量 称内部变量。它只在本函数范围内有效,即:只有在本函数内才能使用这些变量,故称为“局部变量”O第八章函数例:float fl(int a)/*函数fl*/int b9c;./*a、b、c有效刃char f2(int xJnt y)/*函 数f2*/int iJ;/*x、y、i、j有效刃void main()/*主函数*/int m,n;./*m、n有效刃(1)主函数中定义的变量 只在主函数中有效。(2)不同函数中可以使 用相同名字的变量。形式参数也是局部 变量。(4)在一个函数内部,可 以在复合语句中定义 变量,变量只在本复 合语句中有效。第八章函数Bvoid main()int a,b;.a l _int c;c=a+b;c在此范围内有效%b在此范围内有效第八章函数8.8.2全局变量外部变量:函数之外定义的变量称为外部 变量。外部变量可以为本文件中其他函数 所共用。它的有效范围为从定义变量的位 置开始到本源文件结束。所以也称全局变 量。第八章函数int p=l,q=5;/*外部变量*/float fl(int a)/*定义函数fl*/int b5c;)char cl,c2;/*外部变量*/char f2(int x,int y)/*定义函数f2*/int i,j;)void main()/*主函数*/int m9n;全局变量C1C2的作用范围 全局变量小q的作用范围第八章函数TUIZCLH 1A HMI/PPIQITV PQPCQ例8.15有一个一维数组,内放1 0个学生成绩,写一个函数,求出平均分、最高分和最低分。#include float Max=0,Min=0;/*全局变量*/void main()float average(float arrayint n);float ave5score10;int i;for(i=0;i 1 0;i+)scanf(%f”,&score i);ave=average(score51 0);printf(“max=%6.2fnmin=%6.2Rnaverage=%6.2n5Max5Miii5ave);第八章函数float average(float array int n)/*定义函数,形参为数组*/int i;float aver5sum=array 0;Max=Min=array 0;for(i=1;i Max)Max=array i;else if(array i Min)Min=array i;sum=sum+array i;aver=sum/n;return(aver);第八章函数全局变量Max Minmain 函数average 函数第八章函数例 8.1 6外部变量与局部变量同名#include int a=3,b=5;void main()int a=8;/*%b为外部变量*/*a为局部变量刃printf(%d”,max(即b);外部变量与局部变 量同名时,则在局 部变量作用范围内 外部变量被“屏 蔽”。max(int%int b)int c;c=ab?a:b;return(c);运行结果为8第八章函数8.9变量的存储类别第八章函数 一8.9变量的存储类别8.9.1动态存储方式与静态存储方式变量的作用域=全局变量和局部变量。变量值存在时间静态存储方式和动态存储方式。静态存储方式:指在程序运行期间由系统分配固定 的存储空间的方式。动态存储方式:则是在程序运行期间根据需要进行动态的分配存储空间的方式。第八章函数内存中供用户使用的存储空间情况:用户区第八章函数-变量和函数有两个属性:数据类型和数据的存储类 别。存储类别指的是数据在内存中存储的方式。存储方式分为两大类:静态存储类和动态存储类。包含:自动的(auto);静态的(static);寄存器的(register);外部的(extern)。根据变量的存储类别,可以知道变量的作用域和生 存期。第八章函数.夕 r*/一 xjkf D/*f-b i/*一*f*.?/A k/l JI,丁 l X jw,,/:方f,二 二,-3。索丁.8.9.2 auto变量自动变量auto:不专门声明为stati c存储类别的局部 变量都是动态分配存储空间,在调用该函数时系统会 给它们分配存储空间,在函数调用结束时就自动释放 这些存储空间。因此这类局部变量称为自动变量。函数中的形参和在函数中定义的变量,都属此类。自动变量用关键字auto作存储类别的声明。例如:int f(int a)/*定义f函数,a为形参*/auto int b,c=3;/*定义b、c为自动变量*/第八章函数8.9.3用static声明局部变量当函数中的局部变量的值在函数调用结束后不 消失而保留原值时,该变量称为静态局部变量。用 关键字static进行声明。US#include void main()int f(int);int a=2,i;for(i=0;i 3;i+)printf(rr%d f(a);int f(int a)auto int b=0;static c=3;b=b+1;c=c+1;return(a+b+c);静态局部变量在编译时 赋初值,只赋初值一次,以后每次调用函数时不再 重新赋初值而只是保留上 次函数调用结束时的值。定义局部变量时不赋初 值的话,则静态局部变量,编译时自动赋初值。或空 字符。自动变量,如果不 赋初值则它的值是一个不 确定的值。第八章函数例81 8输出1到5的阶乘值#include void main()int fac(int n);int i;for(i=1;i=5;i+)printf(%d!=%d n,i,fac(i);Int fac(int n)static int f=1;f=f*n;return(f);第八章函数8.9.4 reg i ster 变量变量的值是存放在内存中的。当程序中用到哪一 个变量的值时,由控制器发出指令将内存中该变量的值 送到运算器中。运算器存|取数u S内存第八章函数如果有一些变量使用频繁,则为存取变量的值 要花费不少时间。为提高执行效率,C语言允许将局部变量的值 放在CPU中的寄存器中,需要用时直接从寄存器取出 参加运算。由于对寄存器的存取速度远高于对内存的存取 速度,因此这样做可以提高执行效率。这种变量叫做寄存器变量,用关键字reg is tei作 声明。第八例8.19使用寄存器变量#include void main()long fac(long);long in;scanf(M%ldM,&n);for(i=l;i=ii;i+)printf(M%ld!=%ldnM,i,fac(i);)long fac(long n)register long/*定义寄存器变量*/for(i=l;i=n;i+)f=f*i;return(f);第八章函数8.9.5用extern声明外部变量外部变量是在函数的外部定义的全局变量,它 的作用域是从变量的定义处开始,到本程序文件的 末尾。在此作用域内,全局变量可以为程序中各个 函数所引用。编译时将外部变量分配在静态存储区。用extern来声明外部变量,以扩展外部变量的 作用域。第八章函数1.在一个文件内声明外部变量例820用exteiTi声明夕卜部变量,扩展它在程序文件 中的作用域#include void main()int max(int,int);extern A,B;/*外部变量声明*/p rintf(M%dn.max(A,B);)int A=13,B=8;/*定义外部变量*/int max(int x,int y)/*定义max函数*/int z;z=xy?x:y;return(z);第八章函数2.在多文件的程序中声明外部变量例8.2 1用extern将外部变量的作用域扩展到其他文件。本程序的作用是给定b的值,输入A和m,求AX b和An1的值。文件file 1.c中的内容为:#include int A;/*定义外部变量刃void main()int power(int);/*函数声明*/int b=3,c,d,m;printf(nenter the number a and its power m:n);scanf(%d,%d,&A,&m);c=A*b;printf(n%d*%d=%dn A b,c);d=power(m);printf(n%d*%d=%d n”,A,m,d);第八章函数文件file 2.c中的内容为:extern A;/*声明A为一个已定义的外部变量*/int powre(int n);int i,y=1;for(i=1;i=n;i+)y*=A;return(y);第八章函数8.9.6 用stat ic声明外部变量在程序设计中,某些外部变量只限于被本文件引 用,而不能被其他文件引用。这时可以在定义外 部变量时加一个stai t ic声明。例如:filel.c file2.cstatic int A;void main()extern int A;void fun(int n)A=A*n;第八章函数 81MMlM8.9.7关于变量的声明和定义定义性声明:需要建立存储空间的(如:int a;)声明。引用性声明:不需建立存储空间的声明(extern a;)o 注意:声明包括定义,但并非所有的声明都是定义。对“int a;”而言,它既是声明,又是定义。而对 extern a;”而言,它是声明而不是定义。第八章函数8.10内部函数和外部函数第八章函数8.10内部函数和外部函数根据函数能否被其他源文件调用,将函数区分为内部 函数和外部函数。8.10.1内部函数如果一个函数只能被本文件中其他函数所调用,它称 为内部函数。在定义内部函数时,在函数名和函数类 型的前面加stat ic。static类型标识符 函数名(形参表)例如:static int fun(int a,int b)第八章函数 一8.10.2外部函数 定义函数时,如果在函数首部的最左端加关键字 extern,则表示此函数是外部函数,可供其他文件调 用。例如)extern int fun(int a,int b)o如果在定义函数时省略ex tern,则隐含为外部函数。(2)在需要调用此函数的文件中,用extern对函数作 声明,表示该函数是在其他文件中定义的外部函数。第八章函数例8.22有一个若干字符的字符串,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现。File,c(文件 1)#include void main()extern void enter_string(char str);extern void detele_string(char str char ch);extern void print_string(char str);char c;char str80;scanf(n%cn,&c);detele_string(str5c);print string(str);file 2.c(文件 2)#include void enter_string(char str80)/*定义外部函数 enter-string/gets(str);/*向字符数组输入字符串*/)file 3.c(文件 3)void delete_string(char str,char ch)/*定义外部函数 delete string*/int i,j;for(i=j=0;str i!=!0!;i+)if(stri!=ch)strj+=stri;stri=lOf;第八章函数 file 4.c(文件 4)#include void print_string(char str)printf(H%snlstr);运行情况如下:abcdefgc(输入 str)c/(输入要删去的字符)a b d e f g(输出已删去指定字符的字符串)第八章函数本章小结概述;函数定义(无参函数、有参函数,空函数);函数参数(形参、实参)和函数返回值;函数调用、嵌套调用、递归调用;数组作为函数参数(数组元素、数组名、多维数组名);局部变量和全局变量;变量四种存储类别;内部函数和外部函数
展开阅读全文