第8章函数本章要点熟练掌握函数的定义和调用方式理解和掌握函数参数的传递方式掌握变量的作用域和存储类型本章难点函数的参数调用对变量作用域和生存期的理解我们先看一个C程序:intmul(intx,inty){intresult;result=x*y;returnresult;}main(){inta,b,c,d,e;printf(“inputa,b,c:”);scanf(“%d%d%d”,&a,&b,&c);d=mul(a,b);/*计算ab的积*/e=mul(b,c);/*计算bc的积*/printf(“\n”);printf(“a*b=%d\n”,d);printf(“b*c=%d\n”,e);}说明:⑴程序由2个函数模块构成,它们是mul函数和main主函数。由此可见一个C程序可以由一个main函数组成,也可以由一个main函数和多个其他函数组成。⑵main函数调用了mul()函数。由此可见,在C程序中,main函数能调用其他一切函数,反之不行。(3)函数有两类:①标准函数,即库函数。这是由系统提供的,如printf()和scanf()函数,可以直接使用它们。②用户自己定义的函数。用以解决用户的专门需要⑷从函数的形式看,参数分两类:①形式参数,mul函数所带的参数x,y称为形式参数。②实在参数,main函数的调用语句中出现的a,b等都叫实在参数。8.1函数概念的引入一、C函数的概念将一个C程序分为若干模块,每个模块实现一个特定的功能,在C语言中用函数来实现模块的功能。函数:具有某种功能的独立程序段。⑴从程序设计方法看C函数:它是实现模块化程序设计的语法元素。⑵从C语言中程序的组成方式看C函数:它是程序的基本组成单位。二、C函数与C程序结构⑴C程序由主函数(main函数)和若干个子函数构成;⑵主函数调用子函数;⑶子函数在定义时是并列的;⑷子函数可相互调用,也可被多次调用。mainabcdefghhiegmain()/*主函数*/{print_star();/*调用print_star函数画****/print_message();/*调用print_message函数写字*/print_star();/*调用print_star函数画****/}print_star()/*定义print_star函数*/{prinf(“\n**********”);}print_message()/*定义print_message函数*/{prinf(“\nHello!”);}函数调用例:运行结果:**********Hello!**********三、C函数的特点⑴一个源文件由一个或多个函数组成,它是一个独立编译单元。⑵一个C程序由一个或多个源文件组成;⑶C程序执行总是从main函数开始,调用其他函数后流程回到main函数,在main函数中结束整个程序的运行。⑷函数不能嵌套定义,但可以互相调用。注意不能调用main函数。四、函数的分类1.从函数的参数形式看,函数可分为两类:①无参函数;②有参函数有参函数例:(输出两数中大者)#includestdio.hintmax(intx,inty);main(){intnum1,num2,a;scnaf(%d,%d,&num1,&num2);a=max(num1,num2);printf(max=%d,a);}intmax(intx,inty){intz;if(xy)z=x;elsez=y;}2.从用户使用的角度看,函数有两种:①标准函数(库函数);②用户自己定义的函数库函数:是由编译系统提供的已设计好的函数,用户只需调用而无需要去实现它。前几章用过的scanf,printf,getchar,putchar等都是库函数。用户自定义函数:由程序员自己定义和设计的函数。需要程序员自己来编写函数功能实现代码。8.2库函数调用库函数要用include命令,其后要包括头文件名,其一般形式:#include“文件名”例如:#includemath.h{intx=10;abs(x);}库函数调用的一般形式为;库函数名(参数表);函数名含义用法abs求整数的绝对值intabs(inti);cos求余弦函数doublecos(doublex);exp求指数函数doubleexp(doublex);labs取长整型绝对值longlasb(longn);log求对数函数longdouble(x)pow指数函数(x的y次方)doublepow(doublex,doubley);sin求正弦值doublesin(doublex);sqr计算平方根doublesqrt(doublex);tan求正切值doubletan(doublex);itoa把整型转换为字符型char*itoa(intvalue,char*string,intradix);tolower把字符转换为小写字母inttolower(intc);toupper把字符转换为大写字母inttoupper(intc);rand随机发生器voidrand(void);gettime取得当前系统时间voidgettime(structtimetimep);表8.1常用标准库函数8.3函数的定义1.无参函数的定义形式类型标识符函数名(){声明部分执行部分}例如:print_message(){printf(“\nHello!”);}无参数传递2.有参函数的定义形式类型标识符函数名(形式参数表列){声明部分执行部分}有参数传递8.3.1函数的定义形式例如:intmax(intx,inty)/*求x和y二者中大者,x,y为形参*/{intz;/*函数体中变量的说明*/z=xy?x:y;return(z);/*将z的值作为函数返回值*/}3.空函数的定义形式类型标识符函数名(){}例如:dummy(){}功能:调用后什么也不做。用处:建立程序结构,在需要时补充功能。main()/*主函数*/{intm;printf(“pleaseinputnumber:\n”);scanf(“%d”,&m);sum(m);/*调用求和函数*/printf(“m=%d\n’,m}intsum(intn)/*求和函数*/{inti,result=0;for(i=1;i=n;i++)result=result+i;printf(“result=%d\n”,result);return0;}8.3.2函数的简单引用运行结果:pleaseinputnumber:10result=55m=108.4函数间的参数传递1.形式参数和实际参数的概念形式参数:在定义函数时函数名后面括弧中的变量名,简称形参。实际参数:在调用函数时函数名后面括弧中的表达式,简称实参。main(){inta,b,c,m;scanf(“%d,%d,&a,&b);m=max(a,b,c);printf(“Maxis%d”,m);}intmax(intx,inty,intz){intm;m=xy?x:y;m=mz?m:z;return(m);}形参表实参表8.4.1形式参数和实际参数上例中形参与实参、函数名与返回值之间的关系:c=max(a,b);-----------------------实参:在运行时把函数的max(intx,inty)把值传给函数。结果赋给{………函数名returu(z);形参:通知系统}要预留内存位置。上面讲的形式参数表的说明形式是新版C语言表示形式(现代方式),即形式参数说明是类型和参数在一起说明。传统的形式参数说明是类型和参数分别说明。如:按传统方式说明形参intmax(x,y)intx,y;{……}按现代方式说明形参intmax(intx,inty){……}这两种方式都可以使用,但推荐使用现代方式。注意这里是逗号⑷实参可以是常量、变量或表达式,并且必须有确定的值;⑶对每个形参必须指明其名字和数据类型;⑸实参个数、类型必须与对应的形参一致;⑵形参是函数的内部变量,只在函数内部才有意义;⑹实参对形参的数据传递是值传递,即单向传递,只由实参传递给形参,反之不可。调用结束后,只有形参单元被释放,实参单元中的值不变。⑴形参调用前不占内存单元,调用时占用,调用后释放;关于参数的几点说明:2.参数的传递调用一个函数时,调用函数和被调用函数之间会发生数据传递,有两种数据传递方式。一种是传值,另一种是传地址。如:按传值方式intf(intx,inty){……}main(){inta=3;intb=10;……f(a,b);}按地址方式voidsort(intx[],intn){……}main(){inta[5]={0,1,2,5,6};sort(a,5);}1.传值2.传地址1.定义:通过函数调用使主调函数得到一个确定的值,称为函数的返回值。例如:c=max(3,5);此时函数的返回值是5,因此c=52.函数的返回值语句return函数的返回值是通过return语句获得的。return语句将被调函数的一个确定的值带回主调函数中去。return语句的一般形式:return(函数返回值);return函数返回值;“函数返回值”是有确定值的常量、变量或表达式。8.4.2函数的返回值说明:⑵一个函数中可以有多个return语句,但是一次函数执行只能执行其中的一个。当执行到某个return语句时,则终止函数执行,并带回函数值。⑶若函数体内没有return语句,就一直将函数执行完,再返回调用函数,有一个不确定的值带回。⑴return后面的值可以是一个表达式,例如:z=xy?x:y;return(z);return(xy?x:y);⑷return后面可以无“返回值”(即return;),则该return语句只起到终止函数执行,返回主调函数的作用。3.函数值的类型函数定义时应该指定函数的类型(即函数值的类型),应该与return语句的类型一致。说明:⑴凡不加类型说明的函数,一律自动按整型处理。⑵如果函数类型和return语句的类型不一致,以函数类型为准。对数值型数据,可以自动进行类型转换。既函数类型决定返回值的类型。⑶如果函数不返回值,可以将函数定义为“无类型”void(或称“空类型”)。例如:voidprint_star(){……}8.5函数的调用8.5.1函数调用的一般形式函数名(实际参数表)有参数函数:无参数函数:函数名()说明:⑵实际参数表中的参数可以是常量、变量或表达式;⑶实参与形参个数相等,类型应一致;⑴多个实参间用逗号隔开;⑷实参与形参按顺序对应,一一传递数据;⑸实参表求值的顺序与系统有关。8.5.2函数调用方式1.以独立的函数语句调用一般形式:函数名(实际参数表);这种方式常用于调用一个可以忽略返回值或没有返回值的函数。使用情况:如:我们程序中对scanf函数和printf函数的调用。2.函数调用出现在表达式(函数表达式)中。一般形式:变量名=函数表达式使用情况:这种方式用于调用带返回值的函数,函数的返回值将参加表达式的运算。如:a=3+max(num1,num2);注意:无返回值函数的调用,不能出现在表达式中。3.函数参数函数调用作为函数的参数,实质上是函数表达式形式调用的一种,因为函数的参数本来就要求是表达式形式。说明:如:m=min(a,min(b,c));函数调用的含义:函数作为一个函数的实际参数(1)对实际参数列表中的每一个表达式求值。(2)将表达式的值依次对应地赋给在被调用函数头部定义的形式参数变量。(3)执行被调用函数的函数体。(4)如果有return语句被执行,那么控制返回到主调函数中,如果return语句中包含表达式,将return语句中表达式的值返回到主调函数。(5)如果缺少return语句,那么在运行到函数体末尾时控制自动返回到主调函数。8.5.3调用函数的声明⒈对被调用函数说明的前提条件被调用函数必须是已存在的函数,如用户自定义函数或库函数。2.被调用函数是用户自定义函数的函数说明同变量一样,函数的调用也应该遵循“先说明,后使用”的原则。如果使用用户自定义函数