第五章函数★内容提要:函数的定义形式函数的参数传递函数的返回值与类型函数间的数据联系函数的递归调用变量的存储类别与作用域函数的定义函数的参数传递返回值与类型函数间的数据联系函数的递归调用存储类别与作用域C程序由一个主函数main()和若干个其它函数构成,执行时由主函数调用其它函数,其它函数可以互相调用,同一个函数也可以被一个或多个函数调用任意多次。第五章函数有序5.2函数的参数传递形参可以是:简单变量特点:一旦结合,即数据数据传递完毕,实参与形参不再有实际联系,即形参在函数中的值的变化不会改变主调函数的实参的原有值。1.传值方式(单向传递)实参可以是:常量、变量、表达式、数组元素形参可以是:数组名、指针变量特点:通过传递数组或某一存储单元的起始地址,使被调函数可利用此地址来访问(存取)相应存储单元的数据,实质上为通过存储单元共享,达到数据双向传递的目的。2.传地址方式(双向传递)实参可以是:数组名、指针变量、字符串常量、指定单元的起始地址等注意:函数调用时要求实参与形参在个数、顺序、类型上必须匹配一致.5.2函数的参数传递5.3函数的返回值与函数类型说明函数的类型应与return中的表达式类型一致,函数类型决定返回值的类型若return后面括号中的表达式为非整型,则必须在函数名前冠以函数的类型说明。函数类型决定返回值的类型。三点说明:若不返回值,则用void类型定义函数。voidprintmessage(){……}5.3函数的返回值与函数类型说明函数的类型应与return中的表达式类型一致,函数类型决定返回值的类型三点说明:一个函数可以有多个return语句。可采用形式:return(表达式);//带值返回return;//不带值返回5.3函数的返回值与函数类型说明函数的类型应与return中的表达式类型一致,函数类型决定返回值的类型三点说明:5.4应遵守先定义后使用的调用规则类型标识符函数名(形参表);若函数定义在后,调用在先,则应在主调函数的定义说明部分给出被调函数的原型说明:正确区分函数定义和函数原型说明:定义:是对函数功能的确立。说明:是对已定义函数的函数名、函数类型,形参的个数、顺序和类型等信息的说明。5.5函数间的数据联系通过return语句返回一个值一个地址或一个数值通过return语句返回一个值一个地址或一个数值通过外部(全局)变量进行数据传递。形实参数传递结合)传地址方式(双向传递或传值方式(单向传递)形实参数传递结合)传地址方式(双向传递或传值方式(单向传递)5.6函数的递归调用递归的概念:通俗地讲,用自身的结构来描述自身就称为“递归”。这里指函数直接或间接的自己调用自己。C语言的函数除了main()函数,都可以递归调用,但不能递归定义,即不能在函数内部定义另一个函数,但可以直接或间接地调用自己。具有递归特性的问题,用递归调用描述它们就非常方便。C语言的函数除了main()函数,都可以递归调用,但不能递归定义,即不能在函数内部定义另一个函数,但可以直接或间接地调用自己。构成递归的条件:(1)递归结束条件及结束时的值;(2)能用递归表达式形式表示,并且递归向结束条件发展例[5-1]:,递推公式不等于当,递归结束条件当求0)!1(*01!nnnnnC语言的函数除了main()函数,都可以递归调用,但不能递归定义,即不能在函数内部定义另一个函数,但可以直接或间接地调用自己。①递归调用点,此时整个表达式的运算还没有完成,必须返回一个值参与运算后,求出整个表达式的值,然后再返回上一层递归调用点。递归调用点也是返回点。②保护现场:保存数据,以便返回时再使用;保存返回地址等…elsereturn(n*fac(n-1));fac(n)fac(3)fac(2)fac(1)fac(0)…return(n*fac(n-1));…return(n*fac(n-1));…return(n*fac(n-1));…return(1);44312栈:先进后出。保存数据intfac(intn){if(n==0)return(1);elsereturn(n*fac(n-1));}4312栈:先进后出。保存数据12*1=21*1=14*6=2412624…elsereturn(n*fac(n-1));fac(n)fac(3)fac(2)fac(1)fac(0)…return(n*fac(n-1));…return(n*fac(n-1));…return(n*fac(n-1));…return(1);4…elsereturn(n*fac(n-1));fac(n)fac(3)fac(2)fac(1)fac(0)…return(n*fac(n-1));…return(n*fac(n-1));…return(n*fac(n-1));…return(1);43*2=2递推方向intfac(intn){if(n==0)return(1);elsereturn(n*fac(n-1));}运行结果:输入:4输出:24print(n){inti;printf(n=%-5d\n,n);if(n0){putchar('-');n=-n;}if((i=n/10)!=0)print(i);putchar(n%10+'0');}voidmain(){print(123);putchar('\n');}例[5-2]:把整数n用十进制字符串的形式打印出来。在执行过程中,每递归调用一次,就引用一组全新的自动变量,完全独立于上层调用的变量,即各层递归调用的变量各自独立。可插入一个打印语句给以证明。运行结果:n=123n=12n=1123C程序中每一个变量和函数都有两个属性:数据类型和存储类别。5.7变量的存储类型及其作用域数据类型charshortintintlongintunsignedfloatdouble……数据类型确定数据的存放形式、值域及允许的运算等。数据类型charshortintintlongintunsignedfloatdouble……数据类型确定数据的存放形式、值域及允许的运算等。存储类别(确定存储区域)存储类别auto限定说明每次进入函数时自动分配存储单元,退出调函数时系统自动收回存储单元的局部变量;register限定说明寄存器变量;extern限定说明外部(全局)变量;static限定说明静态的局部静态变量、局部静态数组、静态外部变量等。存储类别auto限定说明每次进入函数时自动分配存储单元,退出调函数时系统自动收回存储单元的局部变量;register限定说明寄存器变量;extern限定说明外部(全局)变量;static限定说明静态的局部静态变量、局部静态数组、静态外部变量等。内存中的用户区用户程序区:静态存储区:数据的生存周期同程序运行期,即变量能保持到程序运行结束动态存储区:数据(存储单元)随函数的调用而存在,随函数的返回而消失(存储单元回收)内存中的用户区用户程序区:静态存储区:数据的生存周期同程序运行期,即变量能保持到程序运行结束动态存储区:数据(存储单元)随函数的调用而存在,随函数的返回而消失(存储单元回收)完整的变量定义形式:说明:函数内定义的变量,若不指定存储类别,则作auto变量处理。函数外定义的变量为全局变量。存储类别数据类型变量名表列;main(){staticfloata,b,c;autodoublex,y,z;//相当于doublex,y,z;……}完整的函数定义形式:说明:函数的存储类别只能使用extern,static这两个限定词,以限制函数的调用范围。省略存储类别隐指外部函数,可供其它文件中的函数调用;静态函数只能被本程序文件的函数调用。存储类别数据类型函数名(形参表){……}staticintmax(intx,inty){return(xy?x:y);}提示:在定义和说明变量时,应按照变量的作用范围以及它们在存储单元中保持值的时间长短的需要,对它们的存储类别进行说明限定。(1)局部变量及其作用域函数内部定义的变量统称为局部变量,包括形参变量,由于存放在动态区,故也称为动态变量。作用域:本函数内有效floatfa(inta){intb,c;……}voidmain(){inta,b,c;……{intc;c=a+b;……}……}a,b,c作用域局部变量C有效在复合语句内定义的C有效局部变量C有效b,c的作用域a,b,c作用域局部变量C有效在复合语句内定义的C有效局部变量C有效b,c的作用域说明:函数内定义的变量只限本函数内有效,main()函数中定义的变量也只有主函数内有效。不同函数中定义的变量可以同名,各自代表不同的对象,互不干扰。形参也是局部变量。没有指定类别作auto处理。内层定义的局部变量优先。局部动态变量的初值不定。floatfa(inta){intb,c;……}voidmain(){inta,b,c;……{intc;c=a+b;……}……}a,b,c作用域局部变量C有效在复合语句内定义的C有效局部变量C有效b,c的作用域a,b,c作用域局部变量C有效在复合语句内定义的C有效局部变量C有效b,c的作用域(2)寄存器变量及其作用域为了提高执行效率,允许将局部变量的值放在运算器的寄存器中,需要时直接从寄存器取出参加运算。说明:只有局部自动变量和函数的形参可以作为寄存器变量,并且类型只限于int、char和指针类型。intfac(intn){registerinti,f=1;for(i=1;i=n;i++)f=f*i;return(f);}voidmain(){inti;for(i=1;i=5;i++)printf(%d!=%3d\n,i,fac(i));}例[8-3]:求1!∼5!的阶乘.运行结果:1!=12!=23!=64!=245!=120(3)外部变量及其作用域在函数外定义的变量称为外部变量,即全局变量,可以为本文件中其它函数所共用。其有效作用域:从定义变量的位置开始到本源文件结束.外部变量提供了不同函数间进行数据共享(传递)的另一途径。floatmax=0,min=0;//定义外部变量max,minfloataverage(floatarray[],intn){inti;floataver,sum=array[0];max=min=array[0];for(i=1;in;i++){if(array[i]max)max=array[i];if(array[i]min)min=array[i];sum=sum+array[i];}aver=sum/n;return(aver);}例[5-4]:用一维数组内存放10个学生成绩,写一个函数,求出平均分、最高分和最低分。voidmain(){floatave,score[10];inti;for(i=0;i10;i++)scanf(%f,&score[i]);ave=average(score,10);printf(max=%f\nmin=%f\naverge=%6.2f\n,max,min,ave);}输入:9945789710067.589926643输出:max=100.00min=43.00averge=77.65floatmax=0,min=0;//定义外部变量max,minfloataverage(floatarray[],intn){inti;floataver,sum=array[0];max=min=array[0];for(i=1;in;i++){if(array[i]max)max=array[i];if(array[i]min)min=array[i];sum=sum+array[i];}aver=sum/n;return(aver);}voidmain(){floatave,score[10];inti;for(i=0;i10;i++)scanf(%f,&score[i]);ave=average(score