1第5章函数5.1程序设计的艺术5.2函数的定义和使用5.3数组作函数参数5.4变量的作用域5.5变量的存储类别5.6预处理指令2一、函数的概念函数是形式上独立、功能上完整的程序段(块)。在C程序设计中常将一些常用功能模块编写成函数。函数可以完成特定的计算或操作处理功能。C程序由函数组成;函数在形式上是平行的,不允许嵌套定义;C程序只执行主函数,子函数必须通过主函数或其他子函数的调用才能被执行;子函数不能调用主函数。实质上,设计程序就是设计函数。5.1程序设计的艺术(略)5.2函数的定义和使用3二、函数的分类(一)从用户的角度分1.标准函数,即库函数ANSIC预先定义的用户可直接使用的函数;使用库函数时,必须用#include把该函数所在的头文件包含进来。2.用户自定义函数是用户为了解决各种应用问题而自行设计的函数。用户自定义函数必须先定义后使用!(二)从形式上分1.无参函数:即无形式参数的函数。如:getchar()2.有参函数即带有形式参数的函数如:putchar(ch)、sqrt(x)…4三、函数的定义1、无参函数的定义函数返回值类型函数名(void){函数体}其中:函数返回值类型表示函数的返回结果值类型,函数只能有一个返回值,若函数无返回值即用void声明;返回函数值需使用:return变量|表达式;函数名由用户按标识符的命名规则自行给定,但不能与标准函数同名;圆括号中的关键字void表示函数无形式参数;函数体是由实现函数功能必需的语句组成。5例1:无参函数的定义。#includestdio.hvoidPrintMessage(void){printf(\t*******************\n);printf(\tProgrammingisfun.\n);printf(\t*******************\n);}intmain(void){PrintMessage();PrintMessage();PrintMessage();return0;}6函数返回值类型函数名(数据类型参数1,数据类型参数2,…){函数体}说明:•函数返回值类型、函数名、函数体的含义与无参函数相同;•形式参数的格式如:数据类型形式参数1形式参数(简称形参)必须单个独立定义,形参是用来接收函数被调用时对应实际参数传递的值或地址的,因此形参只能是变量,形参的存储空间是函数被调用时临时分配的动态空间、用完即释放(不能永久存储数据)。2、有参函数的定义7intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}函数首部函数体例2:定义有参函数计算两个整数的平均。8#includestdio.hintAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}intmain(void){inta1=12,b1=36,a2=24,b2=46,a3=5,b3=25;intave1,ave2,ave3;;ave1=Average(a1,b1);ave2=Average(a2,b2);ave3=Average(a3,b3);printf(Averageof%dand%dis%d.\n,a1,b1,ave1);printf(Averageof%dand%dis%d.\n,a2,b2,ave2);printf(Averageof%dand%dis%d.\n,a3,b3,ave3);return0;}形参为整形变量x和y变量a1和b1为实际参数91、函数调用的一般形式:函数名(实在参数表)其中:形参(形式参数)定义函数时在函数名后括号中声明的参数;实参(实际参数)在主调函数中调用函数时函数名后面括号中的参数(或表达式);调用函数时实参的个数、顺序、类型必须与形参一一对应(赋值相容);实参可是常量、变量、函数或表达式;函数调用时实参和形参是采用单向值传递形式即将实参的数值或地址单向传给对应的形参。四、函数的调用10有返回值时(即函数功能为某种计算功能)返回值=函数名(实参表列);例如:以赋值语句形式调用函数如c=max(a,b);例如:作为另一个函数的参数形式调用函数如c=max(max(a,b),c);printf(%d\n,max(a,b));无返回值时(即函数功能是完成某种操作或处理)例如:以表达式语句形式调用函数如display(a,b);函数名(实参表列);2、具体调用形式11理解函数的调用参数的传递intmain(void){inta=12;intb=24;intave;ave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);return0;}#includestdio.hintAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}12例3:定义求n!函数,然后调用该函数求sum=1!+2!+3!+…m!的值。#includestdio.hdoubleFac(intn){inti;doublep=1.0;for(i=1;in;i++){p*=i;}returnp;}13intmain(void){inti,m;doublesum=0;printf(“Pleaseinputmdata:”);scanf(“%d”,&m);for(i=1;i=m;i++){sum+=Fac(i);}printf(“Sum=%.0f\n”,sum);return0;}14#includestdio.hintmax(intx,inty){intz;if(xy){z=x;}else{z=y;}return(z);}intmain(void){inta=45,b=78,c=99,d,e;d=max(a,b);printf(max1=%d\n,d);printf(max2=%d\n,max(a,b));e=c-max(a,b);printf(e=%d\n,e);printf(max3=%d\n,max(max(a,b),c));return0;}例4:函数定义与调用max1=78max2=78e=21max3=99该程序的输出是什么?15例5:定义求素数的函数,然后调用该函数求100到200之间的所有素数。#includestdio.h#includemath.hintPrim(intx){inti,j,k;k=(int)sqrt(i);for(j=2;j=k;j++){if(i%j==0){break;}}16if(j=k+1){return1;}else{return0;}}intmain(void){inti;for(i=100;i=200;i++){if(Prim(i)){printf(“%d,”,i);}}return0;}17五、函数原型声明(prototype)1、为什么要声明函数原型?函数应该先定义,然后才能调用。但是,如果函数的调用出现在函数的定义之前,就必须对被向前调用的函数进行函数原型声明,否则就会出现函数调用错误。2、声明格式:函数类型函数名(类型名1形参数1,…);或函数类型函数名(类型名1,类型名2,…);注意:如果函数严格遵循先定义后调用原则就无需进行函数原型声明。18例6:函数原型声明(先调用后定义函数)#includestdio.hdoubleFac(intn);intmain(void){…f1=Fac(m);…}doubleFac(intn){….}函数Fac的原型声明先调用函数Fac函数Fac的定义出现在调用之后19#includestdio.hintAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}intmain(void){inta=12;intb=24;intave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);return0;}函数定义函数调用例7:以下函数为先定义后调用,不用声明原型20#includestdio.hintAverage(intx,inty);/*声明Average()函数*/intmain(void){inta=12;intb=24;intave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);return0;}intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}例8:函数的原型声明(先调用后定义)21intmain(){……a();…return0;}a函数{b();…return;}b函数{……return;}①③④⑤⑥⑦②六、函数的嵌套调用在调用一个函数的过程中,又调用其他的函数,称为函数的嵌套调用。以下为函数调用与调用返回过程:22例9:函数的嵌套调用#includestdio.hfloatb(floatm){floatn;n=m*10;return(n);}floatadd(floatx,floaty){floatz;z=b(x)+y;return(z);}intmain(void){floata=1.2,b=3.4,c;c=add(a,b);printf(“c=%f\n”,c);return0;}b函数main调用add函数调用b函数add函数结束23七、函数的递归调用在调用一个函数的过程中,出现直接或间接地调用该函数本身,称为函数的递归调用。intf(intx){inty,z;z=f(y);return(2*z);}f函数调用f函数f1函数调用f2函数f2函数调用f1函数24例10:函数的递归调用有3个人坐在一起,问第3个人多少岁?他说比第2个人大2岁。问第2个人多少岁?他说比第1个人大2岁。最后问第1个人,他说是10岁。请问第3个人多大?分析:age(3)=age(2)+2;age(2)=age(1)+2;age(1)=10;归纳:n=1age(n)=10n1age(n)=age(n-1)+225程序如下:#includestdio.hintage(intn){intc;if(n==1){c=10;}elseif(n1){c=age(n-1)+2;}returnc;}intmain(void){printf(“%d”,age(3));return0;}程序执行过程如下:intmain(void){printf(“%d”,age(3));}intage(3){intc;c=age(2)+2;returnc;}intage(2){intc;c=age(1)+2;returnc;}intage(1){intc;c=10;returnc;}26课堂习题#includestdio.hvoidfunc1(inti);voidfunc2(inti);charst[]=hello,friend!;voidfunc1(inti){printf(%c,st[i]);if(i3){i+=2;func2(i);}}voidfunc2(inti){printf(%c,st[i]);if(i3){i+=2;func1(i);}}intmain(void){inti=0;func1(i);return0;}A)helloB)helC)hloD)hlm1.下列程序执行后的输出结果是()272.有如下程序:#includestdio.hintfunc(inta,intb){return(a+b);}intmain(void){intx=2,y=5,z=8,r;r=func(func(x,y),z);printf(“%d\n”,r);return0;}该程序的输出的结果是()。A)12B)13C)14D)15283.下面程序的输出结果是()。#in