第六章函数教学目标:掌握函数的定义;理解并运用函数的调用;理解函数的声明。教学重点:函数的定义;函数的调用。教学难点:函数的定义。教学时数:4学时6.1概述printstar(){printf(“******************\n”);}main(){printstar();printmessage();printstar();}printmessage(){printf(“Howdoyoudo!\n”);}例:结果:******************Howdoyoudo!******************说明:1.一个源程序文件由一个或多个函数组成,但必须有且仅有一个main函数。2.C程序的执行从main函数开始,调用其他函数后,流程回到main函数,main函数结束整个函数的运行。3.由主函数调用其他函数,其他函数也可互相调用,但不能调用main函数。同一个函数可以被一个或多个函数调用任意多次。4.从用户角度看,函数分为两种:①标准函数:即库函数,由系统提供。②用户自定义函数:用户自己定义的。5.从函数形式看,函数分为两种:①无参函数。②有参函数。6.2函数定义的一般形式一函数定义的一般形式列表类型标识符函数名(类型1形参1,类型2形参2,…){声明部分语句}二说明:1.所有函数在定义时都是互相独立的,即不能嵌套定义;2.类型标识符:说明了函数返回值的类型,当返回值为int时,可省略不写;3.函数名:遵循标识符的命名规则;同一个函数中函数名必须唯一;4.形参:只能是变量,每个形参前要有类型名;当定义的函数没有形参时叫作“无参函数”;形式:类型标识符函数名(){声明部分语句}5.函数体:当声明部分和语句都没有时,称为“空函数”,空函数没有任何实际作用;形式:类型说明符函数名(){}例如:dummy(){}例如:intmax(intx,inty){intz;z=xy?x:y;return(z);}函数名返回值类型形参1形参2声明部分语句(执行部分)函数体6.3函数参数和函数的值一形式参数和实际参数实际参数:调用函数时,函数名后面括弧中的参数称为“实际参数”(简称实参)。形式参数:定义函数时,函数名后面括弧中的参数称为“形式参数”(简称形参)。例如:main(){inta,b,c;scanf(“%d,%d”,&a,&b);c=max(a,b);printf(“Maxis%d”,c);}max(intx,inty){intz;z=xy?x:y;return(z);}二关于形参与实参的说明:1.未出现函数调用时,形参变量不占内存中的存储单元。在发生函数调用时,形参才被分配内存单元。调用结束后,形参所占的内存单元被释放。2.实参可以是常量、变量或表达式,必须有确定的值。在调用时,将实参的值赋给形参变量。3.实参与形参的类型应相同或兼容。如果类型不一致,则将实参转换为和形参类型一致时再赋值。例如:main(){intc;c=max(3.5,5+2);printf(“Maxis%d”,c);}max(intx,inty){intz;z=xy?x:y;return(z);}4.实参变量对形参变量是单向的“值传递”。即只能实参传给形参,不能由形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。main(){inta=10,b=20;alter(a,b);printf(“a=%d,b=%d\n”,a,b);}alter(intx,inty){intt;t=x;x=y;y=t;}1020abxy10202010总结:形参的值发生改变,并不能影响实参。三函数的返回值1.函数通过return语句返回函数的值,若不需要返回函数值,可以不要return语句。形式:return(表达式);return(变量);return(常量);例如:returnz;或return0;或return(a+b);2.定义函数时,函数的返回值类型应与return语句中的表达式类型一致。如果不一致,则以函数类型为准。括号可省略3.若函数中没有return语句,函数也会带回一个不确定的值,为了明确表示“不带回值”,用关键字“void”定义“无类型”(或称“空类型”)。例:voidprintstar(){printf(“******************\n”);}main(){printstar();printmessage();printstar();}voidprintmessage(){printf(“Howdoyoudo!\n”);}这样,系统就保证使函数不带回任何值。6.4函数的调用一函数调用的一般形式函数名(实参表列);或函数名();说明:1.各实参间用逗号格开。2.实参与形参的个数应相同,类型应一致。3.被调用函数必须是已经存在的函数。有参函数的调用形式无参函数的调用形式二函数调用的方式按出现的位置分,有如下三种函数调用方式:1.函数语句。函数不带回值,只完成一定的操作。2.函数表达式。要求函数带回确定值,参加表达式运算。3.函数参数。要求函数带回确定值,作为一个参数。例main(){inta=10,b=20,c=30,d,e;fun();d=max(a,b);printf(“max=%d\n”,d);e=max(a,b)+c;printf(“max=%d\n”,e);printf(“max=%d\n”,max(a,c));}intmax(intx,inty){return(xy?x;y);}fun(){printf(“***********”);}三对被调用函数的声明函数声明的一般形式:函数类型函数名(参数类型1,参数类型2,…);例:intmax(int,int);或intmax(intx,inty);说明:1.使用用户定义函数时,要对函数进行声明。2.如果函数的返回值类型为int,可以不用声明。例:main(){floatadd(floatx,floaty);/*对被调函数声明*/floata,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);/*函数调用(函数表达式)*/printf(“Sumis%f”,c);}floatadd(floatx,floaty){floatz;z=x+y;return(z);}3.若被调用函数定义出现在主调函数之前,可以不必声明。例:floatadd(floatx,floaty){floatz;z=x+y;return(z);/*返回z的值*/}main(){floata,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);/*接受加法函数的返回值*/printf(“%f”,c);}4.若在函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必对所调用的函数再作声明。例:charletter(char,char);floatf(float,float);inti(float,float);main(){…}charletter(charc1,charc2){…}floatf(floatx,floaty){…}inti(floatj,floatk){…}四程序举例例1:用函数调用的方法求两个数的和。floatadd(floatx,floaty){return(x+y);}main(){floata,b,sum;scanf(“%f%f”,&a,&b);sum=add(a,b);printf(“sum=%f”,sum);}例2:通过函数调用的方式,求三个整数的最大值。intmaxnum(intx,inty,intz){intm;m=x;if(my)m=y;if(mz)m=z;returnm;}main(){inta,b,c,max;scanf(“%d%d%d”,&a,&b,&c);max=maxnum(a,b,c);printf(“max=%d”,max);}a函数调用b函数a函数结束main函数调用a函数结束b函数b函数结束6.5函数的嵌套调用C语言不能嵌套定义函数,但可以嵌套调用函数,即允许在调用一个函数的过程中,又调用另一个函数。例如:①②③⑤④⑥⑦⑧⑨main(){intx,y,sum;x=5;y=6;sum=add(x,y);printf(“%d”,sum);}运行结果:41fun(intt){returnt*t;}add(inta,intb){intz;z=a+fun(b);returnz;}汉诺塔问题(Hanoi)6.7数组作为函数参数数组元素作函数参数数组名作函数参数多维数组名作函数参数一.数组元素作函数实参———与变量作实参一样,是单向值传递例1:输入一行字符,分别统计出其中大写字母和小写字母的个数。#include“stdio.h”main(){chara[30];inti,k=0,p=0;gets(a);for(i=0;a[i]!=‘\0’;i++){if(fun(a[i])==1)k++;if(fun(a[i])==2)p++;}printf(“大写字母个数:%d”,k);printf(“小写字母个数:%d”,p);}intfun(charx){if(x=’A’&&x=‘Z’)return1;if(x=’a’&&x=‘z’)return2;}二.数组名作函数实参———传递的是数组的首地址(此时形参和实参指的是同一内存单元)1.用数组名作函数参数,应该在主调函数和被调函数分别定义数组。2.实参——数组名形参——数组名或指针变量3.实参数组与形参数组类型应一致。4.系统将实参数组的首地址传给形参数组5.用数组名作函数参数时,形参数组的改变也可以使实参数组随之改变。intfun(intb[]){∶}main(){inta[10];fun(a);∶}形参还可以写成intb[10]或intb[20]例2:有一个一维数组score,内放10个学生成绩,求平均成绩。floatfun(floata[10]);main(){floats[10],ave;inti;for(i=0;i10;i++)scanf(“%f”,&s[i]);ave=fun(s);printf(“ave=%.2f”,ave);}floatfun(floata[10]){inti;floatsum=0,aver;for(i=0;i10;i++)sum=sum+a[i];aver=sum/10;returnaver;}函数声明s[0]s[1]s[2]s[3]s[4]s[5]s[6]s[7]s[8]s[9]a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]s[n]和a[n]指的是同一单元。例3:编写函数,用选择排序对数组中的10个数按由小到大排序。main(){inta[10],i;for(i=0;i10;i++)scanf(“%d”,&a[i]);fun(a);for(i=0;i10;i++)printf(“%d”,a[i]);}voidfun(intb[]){inti,j,k,t;for(i=0;i9;i++){k=i;for(j=i+1;j10;j++)if(a[k]a[j])k=j;if(k!=i){t=a[i];a[i]=a[k];a[k]=t;}}}三.用多维数组名做函数参数intfun1(intb[][4]){……}intfun2(intc[3][4]){……}main(){inta[3][4];fun(a);fun(a);……}局部变量:在一个函数内部定义的变量。有效范围:只在本函数范围内有效。全局变量:在函数外部定义的变量(又叫外部变量)。有效范围:从定义变量的位置开始到本源文件结束,可以为本文件其他函数所共用。6.8局部变量和全局变量变量按其作用域分类可分为局部变量和全局变量。局部变量:floatf1(inta)/*函数f1*/{intb,c;……}charf2(intx,inty)/*函数f2*/{inti,j;……}main()/*主函数*/{intm,n;……}a,b,c有