第八章函数§8.1概述C程序结构:源程序文件1预编译命令说明部分执行部分函数1函数n源程序文件i源程序文件nC程序一个C源程序由若干函数构成。必须有且只能有一个名为main的主函数。C程序的执行总是从main函数开始,在main中结束。函数不能嵌套定义,可以嵌套调用。从用户角度:标准函数(库函数):由系统提供。用户自定义函数。从函数形式:无参函数。有参函数。函数分类:§8.2函数定义的一般形式函数类型函数名(有类型说明的参数表){说明部分语句部分}函数返回值类型合法标识符参数间用逗号分隔函数体三种函数形式:例:有参函数intmax(intx,inty){intz;z=xy?x:y;return(z);}例:无参函数voidprintstar(){printf(“**********\n”);}例:空函数dummy(){}有参函数无参函数空函数§8.3函数参数和函数的值形式参数和实际参数定义函数时,函数名后面括号中的参数称为“形式参数”(简称形参);在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”(简称实参)。例:#includestdio.hintmax(intx,inty){return(xy?x:y);}voidmain(){inta,b,c;scanf(%d%d,&a,&b);c=max(a,b);printf(maxis%d,c);}形式参数实际参数关于形参与实参的说明:形参必须指定类型。实参必须有确定的值。形参与实参类型一致,个数相同。若形参与实参类型不一致,自动按形参类型转换(函数调用转换)。形参在函数被调用前不占内存;函数调用时为形参分配内存;调用结束,内存释放。/*计算x的立方*/#includestdio.hfloatcube(floatx){return(x*x*x);}voidmain(){floata,product;printf(Pleaseinputvalueofa:);scanf(%f,&a);product=cube(a);printf(Cubeof%.4fis%.4f\n,a,product);}xaproduct××××1.21.21.7281.2函数的返回值通过函数调用使主调函数得到一个确定的值,这就是函数的返回值。函数的返回值是通过函数中的return语句获得的。return语句的一般形式:return(表达式);或:return表达式;return语句的作用是:将流程从当前函数返回主调函数。撤销调用函数时为各参数和变量分配的内存空间。向主调函数返回顶多一个值。例:#includestdio.hintmax(intx,inty){return(xy?x:y);}voidmain(){inta,b,c;intmax(intx,inty);scanf(%d%d,&a,&b);c=max(a,b);printf(maxis%d,c);}说明:一个函数体中可以有多个返回语句,但每次只能通过一个return语句执行返回操作。无返回值的函数是void类型的函数,return语句可省略。函数中return后面(表达式)的值应该与函数定义时的类型一致,否则,以函数类型为准。例:无返回值的函数voidswap(intx,inty){inttemp;temp=x;x=y;y=temp;}/*函数返回值类型转换*/#includestdio.hintmax(floatx,floaty){floatz;z=xy?x:y;returnz;}voidmain(){floata,b;intc;scanf(%f,%f,&a,&b);c=max(a,b);printf(Maxis%d\n,c);}输入:4.67.8输出:Maxis7§8.4函数的调用函数调用的一般形式为:函数名(实参表列);常量、变量、表达式或地址函数调用的作用:通过实参向形参传递数据。为形式参数及函数中声明的变量分配存储空间。暂时中断现行(主调)函数,将流程转向被调函数的入口处,开始执行被调函数。函数调用的三种方式:函数语句:max(a,b);函数表达式:c=max(a,b);作为另一个函数的实参:m=max(a,max(b,c));函数声明调用函数之前,应该对其进行说明,称为:函数声明(通知编译系统函数的类型、参数个数及类型,以便检验)。函数声明的一般形式为:函数类型函数名(形参表);如:floatfun(floatn,floatm,ints);说明:当被调函数定义在主调函数之后时,必须在函数调用之前给出函数声明。当被调函数定义在主调函数之前时,无须在函数调用之前给出函数声明。函数说明位置在程序的数据说明部分(定义部分)。(形参表)中可只给出参数类型,不写参数名。调用库函数不加说明,但要使用#include。如:floatfun(float,float,int);#includestdio.hvoidmain(){floata,b;intc;intmax(floatx,floaty);scanf(%f,%f,&a,&b);c=max(a,b);printf(Maxis%d\n,c);}intmax(floatx,floaty){floatz;z=xy?x:y;returnz;}输入:4.67.8输出:Maxis7§8.5函数的嵌套调用C规定:函数定义不可嵌套,但可以嵌套调用函数。即允许在一个函数中调用另一个函数。main()调用函数a结束a函数b函数调用函数b例:求三个数中最大数和最小数的差值。#includestdio.hintmax(intx,inty,intz){intr;r=xy?x:y;return(rz?r:z);}intmin(intx,inty,intz){intr;r=xy?x:y;return(rz?r:z);}intdif(intx,inty,intz){returnmax(x,y,z)-min(x,y,z);}voidmain(){inta,b,c,d;scanf(%d%d%d,&a,&b,&c);d=dif(a,b,c);printf(Max-Min=%d\n,d);}§8.6函数的递归调用定义:函数直接或间接的调用自身叫函数的递归调用。直接调用:f()调f间接调用:调f2调f1f1()f2()使用递归调用的关键在于:找到递归结束条件。构造一个适当的递归调用语句。例:求n的阶乘。)1()!1()1,0(1!nnnnn#includestdio.hintfac(intn){intf;if(n0)printf(n0,dataerror!);elseif(n==0||n==1)f=1;elsef=fac(n-1)*n;return(f);}voidmain(){intn,y;printf(Inputaintegernumber:);scanf(%d,&n);y=fac(n);printf(%d!=%15d,n,y);}实现递归分为以下两个阶段:“递推”(调用)阶段。“回归”(回代)阶段。如:n=3时,这两个阶段见下图:main函数fact(3)-----------输出:3!=6fact(3)3*fact(2)-----------返回:6fact(2)2*fact(1)-----------返回:2fact(1)1-----------返回:1键入三个整数,用函数求出其中最大的数。有10个有序数存放在一个数组中,输入一个数,用折半法找出该数是数组中第几个元素的值。如果该数不在数组中,则输出“无此数”。要求用函数查找!作业参数传递方式值传递(单个变量或数组元素作参数)方式:函数调用时,为形参分配单元,并将实参的值复制到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值。特点:1.形参与实参占用不同的内存单元。2.单向传递。只能由实参传给形参;不能由形参传给实参。§8.7数组作为函数的参数/*交换两个数*/#includestdio.hvoidswap(inta,intb){inttemp;temp=a;a=b;b=temp;}voidmain(){intx=7,y=11;printf(%d,%d\n,x,y);swap(x,y);printf(%d,%d\n,x,y);}调用前:x:7y:11调用:x:7y:11a:7b:11swap:x:7y:11a:11b:7temp调用后:x:7y:11117地址传递(数组名作参数)方式:如果形参是数组,通常实参应是数组名。因为数组名代表的是数组首元素的地址,所以此时实参向形参传递的是地址。特点:形参数组与实参数组占用相同的内存单元。双向传递。即能由实参传给形参;又能由形参传给实参。形参数组与实参数组类型应一致。在函数定义和函数声明时,数组长度可以省略。如:intaver(inta[],intsize);/*交换两个数*/#includestdio.hvoidswap(intxc[]){inttemp;temp=xc[0];xc[0]=xc[1];xc[1]=temp;}voidmain(){intsc[2]={7,11};printf(%d,%d\n,sc[0],sc[1]);swap(sc);printf(%d,%d\n,sc[0],sc[1]);}调用前:sc[0]:7sc[1]:11swap:sc[0]:11sc[1]:7xc[0]:xc[1]:temp调用后:sc[0]:11sc[1]:7调用:sc[0]:7sc[1]:11xc[0]:xc[1]:例1:输入10个学生的成绩,用函数求平均成绩。#includestdio.hfloataverage(intstu[10],intn);voidmain(){intscore[10],i;floatav;printf(Input10scores:\n);for(i=0;i10;i++)scanf(%d,&score[i]);av=average(score,10);printf(Averageis:%.2f,av);}floataverage(intstu[10],intn){inti;floatav,total=0;for(i=0;in;i++)total+=stu[i];av=total/n;returnav;}实参用数组名形参用数组定义,intstu[]..2109score568372….….88stu例2:用选择法对数组中10个数由小到大排序。#includestdio.hvoidsort(intarray[],intn){inti,j,k,t;for(i=0;in-1;i++){k=i;for(j=i+1;jn;j++)if(array[j]array[k])k=j;t=array[k];array[k]=array[i];array[i]=t;}}voidmain(){inta[10],i;for(i=0;i10;i++)scanf(%d,&a[i]);sort(a,10);for(i=0;i10;i++)printf(%d,a[i]);printf(\n);}0123456789a4968573299927137688arraykjjjkjkjjjjj949i=0例2:用选择法对数组中10个数由小到大排序。#includestdio.hvoidsort(intarray[],intn){inti,j,k,t;for(i=0;in-1;i++){k=i;for(j=i+1;jn;j++)if(array[j]array[k])k=j;t=array[k];array[k]=array[i];array[i]=t;}}voidmain(){inta[10],i;for(i=0;i10;i++)scanf(%d,&a[i]);sort(a,10);for(i=0;i10;