《(1.2)--第7章 C语言程序设计函数.ppt》由会员分享,可在线阅读,更多相关《(1.2)--第7章 C语言程序设计函数.ppt(86页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第7章章 函数函数7.1引例引例7.2函数概述函数概述7.3函数定义函数定义7.4函数调用函数调用7.5递归函数递归函数21:3917.6数组作函数的参数数组作函数的参数7.7局部变量与全局变量局部变量与全局变量7.8变量生命期与存储类型变量生命期与存储类型7.9内部函数与外部函数内部函数与外部函数7.10函数程序设计示例函数程序设计示例21:3927.1引例引例【例例7.1】有有5个整数,输出其中的最大值。个整数,输出其中的最大值。#includeintmain()inta,b,c,d,e,maxa=10;b=12;c=9;d=13;e=5;max=a;/*a的值作为最大值的值作为最大值*
2、/if(bmax)max=b;if(cmax)max=c;if(dmax)max=d;if(emax)max=e;printf(max=%d,max);/*输出最大值输出最大值*/return0;21:393【例例7.2】使用函数的方法完成例使用函数的方法完成例7.1#includeintmain()inta,b,c,d,e,m;intmax(intx,inty);/*函数声明函数声明*/a=10;b=12;c=9;d=13;e=5;/*为变量赋初值为变量赋初值*/m=max(a,max(b,max(c,max(d,e);printf(max=%d,m);/*输出最大值输出最大值*/retur
3、n0;intmax(intx,inty)/*函数首部函数首部,x和和y为形参为形参*/intz;/*定义中间变量定义中间变量z*/if(xy)z=x;elsez=y;returnz;/*返回变量中的最大值返回变量中的最大值z*/21:3947.2 函数概述函数概述 n 所有所有C语言程序都是由一个或多个函数构成的。当语言程序都是由一个或多个函数构成的。当一个一个C语言程序的规模很小时,可以用一个源文件语言程序的规模很小时,可以用一个源文件来实现。当一个来实现。当一个C语言程序的规模较大时,可以由语言程序的规模较大时,可以由多个源文件组成,但其中只有一个源文件含有主函多个源文件组成,但其中只有一
4、个源文件含有主函数数main(),而其他源文件不能含有主函数。,而其他源文件不能含有主函数。n 程序由多个函数构成时,只能由主函数调用其他程序由多个函数构成时,只能由主函数调用其他函数,反之则不行。其他函数之间可以互相调用,函数,反之则不行。其他函数之间可以互相调用,同一个函数可以被一个或多个函数调用任意多次。同一个函数可以被一个或多个函数调用任意多次。一个函数调用另一个函数,前者称为一个函数调用另一个函数,前者称为调用函数调用函数;后;后者称为者称为被调函数被调函数。21:395 从用户使用的角度来看从用户使用的角度来看:(1)标准函数标准函数(2)用户自定义函数用户自定义函数从函数的形式上
5、看从函数的形式上看(1)无参函数无参函数(2)有参函数有参函数从函数的作用范围来看从函数的作用范围来看(1)外部函数外部函数(2)内部函数内部函数21:3967.3 函数的定义函数的定义 n C语言的库函数是由编译系统事先定义好的,语言的库函数是由编译系统事先定义好的,用户在使用时无须自己定义,只需用用户在使用时无须自己定义,只需用#include命令将有关的头文件包含到文件中即可。命令将有关的头文件包含到文件中即可。n所有的用户自定义函数均要所有的用户自定义函数均要“先定义,后使用先定义,后使用”。定义的目的是通知编译系统函数返回值的。定义的目的是通知编译系统函数返回值的类型、函数的名字、函
6、数的参数个数与类型以类型、函数的名字、函数的参数个数与类型以及函数实现什么功能等。及函数实现什么功能等。21:3977.3.1 无参函数的定义无参函数的定义 无参函数的定义形式如下:无参函数的定义形式如下:类型名类型名 函数名函数名()/*函数首部函数首部*/函数体函数体或或类型名类型名 函数名函数名(void)/*函数首部函数首部*/函数体函数体 21:398【例例7.3】定义一个无参且无返回值的函数定义一个无参且无返回值的函数prtstar()。#includevoidprtstar(void)/*函数首部,无形参与返回值函数首部,无形参与返回值*/printf(*n);intmain()
7、prtstar();/*调用函数调用函数*/printf(WelcometoClanguageworld!n);prtstar();/*调用函数调用函数*/return0;运行结果:运行结果:*WelcometoClanguageworld!*21:3997.3.2 有参函数的定义有参函数的定义 有参函数的定义形式如下:有参函数的定义形式如下:类型名类型名 函数名函数名(形式参数表列形式参数表列)/*/*函数首部函数首部*/函数体函数体 说明:说明:(1)有参函数比无参函数多了一项内容,即)有参函数比无参函数多了一项内容,即形式形式参数表列参数表列。在其中给出的参数称为形式参数(简称。在其中给
8、出的参数称为形式参数(简称形参),格式为:形参),格式为:类型类型1形参形参1,类型,类型2形参形参2,类型,类型n形参形参nn每个形参前面的类型必须分别写明每个形参前面的类型必须分别写明。21:3910 n【例例】以下函数定义中以下函数定义中正确正确的是的是。nAdouble fun(double x,y)nBdouble fun(double x;double y)nCdouble fun(double x,double y);nDdouble fun(double x,double y)21:3911(2)函数体)函数体由由一对大括号内的若干条语句一对大括号内的若干条语句组组成成,这些语
9、句实现了函数的功能,并用,这些语句实现了函数的功能,并用return语句返回运算的结果。语句返回运算的结果。return语句逻辑上是函语句逻辑上是函数的最后一条语句。它的一般形式是:数的最后一条语句。它的一般形式是:return表达式表达式;表达式的类型(函数返回值)应与函数名的类表达式的类型(函数返回值)应与函数名的类型一致。型一致。一条一条return语句只能返回一个值。语句只能返回一个值。21:3912(3)编译系统不检查函数名与形参变量)编译系统不检查函数名与形参变量名是否相同,例如下面的函数定义是正名是否相同,例如下面的函数定义是正确的。确的。intf(intf)(4)函数头部省略类
10、型名时,默认函数)函数头部省略类型名时,默认函数的返回值的类型为的返回值的类型为int。21:3913 n【例【例7.4】输入一个实数】输入一个实数x,计算并输出下式的,计算并输出下式的值,直到最后一项的绝对值小于值,直到最后一项的绝对值小于10-5(保留两(保留两位小数)。要求定义和调用函数位小数)。要求定义和调用函数fact(n),计算,计算n的阶乘,可以调用的阶乘,可以调用pow()函数求幂。函数求幂。#include#includedoublefact(intn);/*函数声明函数声明*/intmain()inti=1;doublex,item,s=0;printf(输入输入x的值的值
11、:)scanf(%lf,&x);item=x;while(fabs(item)=0.00001)s=s+item;i+;item=pow(x,i)/fact(i);printf(和是:和是:%lfn,s);return0;21:3914doublefact(intn)inti;doublejc=1;for(i=1;i=n;i+)jc=jc*i;returnjc;输入输入x的值:的值:2和是:和是:6.38904621:39157.3.3 空函数的定义空函数的定义 空函数的定义形式如下:空函数的定义形式如下:类型名类型名 函数名函数名()()例如:例如:intfun()说明:说明:n函数体是空的
12、,调用此函数函数体是空的,调用此函数时,什么工作也不做。时,什么工作也不做。n在调用程序中写上在调用程序中写上fun(),表明这里要调用一个表明这里要调用一个fun函函数,而这个函数还没有完成,数,而这个函数还没有完成,等待以后完善。等待以后完善。21:39167.4 函数的调用函数的调用 n 定义函数的目的就是为了重复使用,定义函数的目的就是为了重复使用,因此只有在程序中调用函数时才能实现函数因此只有在程序中调用函数时才能实现函数的功能。的功能。C语言程序从语言程序从main函数开始执行,函数开始执行,而自定义函数的执行是通过对自定义函数的而自定义函数的执行是通过对自定义函数的调用来执行的。
13、调用来执行的。当自定义函数结束时,从自当自定义函数结束时,从自定义函数结束的位置返回到主函数中继续执定义函数结束的位置返回到主函数中继续执行,直到主函数结束。行,直到主函数结束。21:39177.4.1 函数调用的形式和过程函数调用的形式和过程 1 1函数调用的一般形式函数调用的一般形式函数名函数名(实际参数列表实际参数列表);实际参数列表中的参数称为实际参数,简称实参,实际参数列表中的参数称为实际参数,简称实参,可以是常数、变量和表达式。可以是常数、变量和表达式。2 2函数调用的方式函数调用的方式(1)函数语句)函数语句函数名函数名(实参列表实参列表);(2)函数表达式)函数表达式函数作为表
14、达式中的一部分出现在表达式中,例如:函数作为表达式中的一部分出现在表达式中,例如:a=abs(x);21:3918(3)(3)函数嵌套调用函数嵌套调用C语言的函数定义是互相平行、独立的,也就语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能再定义另一是说,在定义函数时,一个函数内不能再定义另一个函数,也就是不能嵌套定义,但可以嵌套调用函个函数,也就是不能嵌套定义,但可以嵌套调用函数。数。例如:例如:putchar(getchar();21:3919函数嵌套调用图示:函数嵌套调用图示:21:3920【例例】设某自定义函数已有返回值,则以下设某自定义函数已有返回值,则以下关于
15、该函数调用的叙述中错误的是关于该函数调用的叙述中错误的是_。A函数调用可以作为独立的语句存在函数调用可以作为独立的语句存在B函数调用可以作为一个函数的实参函数调用可以作为一个函数的实参C函数调用可以出现在表达式中函数调用可以出现在表达式中D函数调用可以作为一个函数的形参函数调用可以作为一个函数的形参21:3921 3 3函数调用的过程函数调用的过程被调函数的所有形参分配内存,再计算实参的被调函数的所有形参分配内存,再计算实参的值,并一一对应地赋予相应的形参。值,并一一对应地赋予相应的形参。为函数说明部分中定义的变量分配存储空间,为函数说明部分中定义的变量分配存储空间,再依次执行函数的可执行语句
16、。当执行到再依次执行函数的可执行语句。当执行到“return(表达式表达式);”语句时,计算返回值。语句时,计算返回值。释放在本函数中定义的变量所占用的存储空间释放在本函数中定义的变量所占用的存储空间(对于(对于static类型的变量,其空间不会释放),返类型的变量,其空间不会释放),返回主调函数继续执行。回主调函数继续执行。21:3922【例例7.5】求两个正整数求两个正整数m和和n的最大公约数的最大公约数#includeintmain()inta,b,cintgcd(intm,intn);printf(请输入两个整数:请输入两个整数:);scanf(%d%d,&a,&b);c=gcd(a,
17、b);/*调用调用gcd()函数,返回值赋值给函数,返回值赋值给c*/printf(整数整数%d和和%d的最大公约数是:的最大公约数是:%dn,a,b,c);21:3923 intgcd(intm,intn)/*函数首部函数首部,m和和n为形参为形参*/intr;/*定义中间变量定义中间变量r*/r=m%n;/*计算计算m除以除以n的余数的余数*/while(r!=0)m=n;n=r;r=m%n;returnn;/*返回最大公约数返回最大公约数n*/运行结果:运行结果:请输入两个整数:请输入两个整数:3972整数整数39和和72的最大公约数是:的最大公约数是:321:39247.4.2 参数传
18、递参数传递 n调用函数向被调用函数传递数据主要是通过函数的调用函数向被调用函数传递数据主要是通过函数的参数进行的,而被调用函数向调用函数传递数据一参数进行的,而被调用函数向调用函数传递数据一般是通过般是通过return语句实现的。语句实现的。n形参形参是函数定义时函数名后括号中的变量;是函数定义时函数名后括号中的变量;实参实参是是指调用函数时函数名后括号中的常量、变量或表达指调用函数时函数名后括号中的常量、变量或表达式。在调用函数时,式。在调用函数时,将实参的值传递给形参,使形将实参的值传递给形参,使形参在数值上和实参相同参在数值上和实参相同。nC语言提供了两种参数传递数据方式:语言提供了两种
19、参数传递数据方式:按值传递按值传递和和按地址传递按地址传递。21:3925(1)按值传递)按值传递函数调用时,调用函数把实参的值传递给函数调用时,调用函数把实参的值传递给被调用函数的形参,被调用函数的形参,形参值的变化不会影响实形参值的变化不会影响实参的值参的值。这是一种单向的数据传送方式。这是一种单向的数据传送方式。当实参是常量、变量、表达式或数组元素,当实参是常量、变量、表达式或数组元素,形参是变量名时,函数传递数据采用的是按值形参是变量名时,函数传递数据采用的是按值传递。传递。21:3926【例例7.6】阅读下列程序阅读下列程序#includevoidswap(intx,inty)/*函
20、数首部函数首部,x和和y为形参为形参*/intt;/*定义中间变量定义中间变量t*/t=x;/*交换形参交换形参x和和y的值的值*/x=y;y=t;printf(x=%d,y=%dn,x,y);/*输出交换后的形参输出交换后的形参*/intmain()inta,b;scanf(%d,%d,&a,&b);swap(a,b);printf(a=%d,b=%dn,a,b);return0;运行结果:运行结果:12,28 X=28,y=12A=12,b=2821:3927 注意:注意:实参的个数应与形参一致,否则将会出现编译实参的个数应与形参一致,否则将会出现编译错误。错误。定义函数时,系统并不给形参
21、分配存储单元,定义函数时,系统并不给形参分配存储单元,只有函数被调用时系统才给形参分配存储单元。只有函数被调用时系统才给形参分配存储单元。在调用结束后,形参所占用的存储单元被释放。在调用结束后,形参所占用的存储单元被释放。实参与形参即使同名,也会分配不同的分配存实参与形参即使同名,也会分配不同的分配存储单元。储单元。C语言规定语言规定,函数间的参数传递是函数间的参数传递是“值传递值传递”,即单向传递,实参可以把值传给形参,但形参的即单向传递,实参可以把值传给形参,但形参的值不能传给实参,也就是说值不能传给实参,也就是说对形参的修改不会影对形参的修改不会影响对应的实参响对应的实参。这是由于在内存
22、中,实参与形参。这是由于在内存中,实参与形参是不同的存储单元,函数执行结束后,形参的存是不同的存储单元,函数执行结束后,形参的存储单元被释放。储单元被释放。21:3928【例例】若函数调用时的实参为变量,则以下若函数调用时的实参为变量,则以下关于函数形参和实参的叙述中正确的是关于函数形参和实参的叙述中正确的是。A实参和其对应的形参占用同一存储单元实参和其对应的形参占用同一存储单元B形参不占用存储单元形参不占用存储单元C形参和实参占用不同的存储单元形参和实参占用不同的存储单元D同名的实参和形参占用同一存储单元同名的实参和形参占用同一存储单元21:3929 (2)按地址传递)按地址传递当函数的形参
23、为数组(当函数的形参为数组(见见7.6.2【】【】)或)或指针(指针(见见8.3)类型时,)类型时,函数调用的参数传递称函数调用的参数传递称为按地址传递为按地址传递。由于传递的是地址,使形参与实参共享同由于传递的是地址,使形参与实参共享同一存储单元,这样通过形参可以直接引用或处一存储单元,这样通过形参可以直接引用或处理该地址中的数据,达到改变实参值的目的。理该地址中的数据,达到改变实参值的目的。21:39307.4.3 函数的返回值函数的返回值(1)函数的值只能通过)函数的值只能通过return语句返回给调用函数。语句返回给调用函数。return语句的一般形式为:语句的一般形式为:return
24、 表达式表达式;return (表达式表达式);(2)如果不需要从被调用函数返回函数值,可以省略)如果不需要从被调用函数返回函数值,可以省略return语句。省略时,返回的值不确定。语句。省略时,返回的值不确定。(3)return语句中表达式值的类型应与函数定义中函数语句中表达式值的类型应与函数定义中函数的类型保持一致。的类型保持一致。(4)对不需要返回函数值的函数,可以将其函数类型定)对不需要返回函数值的函数,可以将其函数类型定义为义为“void”(即(即“空类型空类型”)。)。21:3931【例例】关于函数返回值,以下叙述中正确的是关于函数返回值,以下叙述中正确的是。A函数返回值的类型由函
25、数体内函数返回值的类型由函数体内return语句包语句包含的表达式的类型决定含的表达式的类型决定B函数返回值的类型由函数头部定义的函数类函数返回值的类型由函数头部定义的函数类型决定型决定C若函数体中有多个若函数体中有多个return语句,则函数的返语句,则函数的返回值是排列在最后面的回值是排列在最后面的return语句中表达式的值语句中表达式的值D若函数体内没有若函数体内没有return语句,则函数没有返语句,则函数没有返回值回值21:39327.4.4 函数声明函数声明 同变量一样,函数的调用也遵循同变量一样,函数的调用也遵循“先声明,先声明,后使用后使用”的原则。的原则。函数声明的格式为:
26、函数声明的格式为:类型名类型名 函数名函数名(参数类型参数类型1,参数类型,参数类型2,);类型名类型名 函数名函数名(参数类型参数类型1 形参形参1,参数类型,参数类型2 形参形参2,);21:3933 当满足下面两个情况之一时,在主调函当满足下面两个情况之一时,在主调函数中可以不对被调函数进行声明。数中可以不对被调函数进行声明。被调函数定义在主调函数之前时,对被调被调函数定义在主调函数之前时,对被调用函数的声明可以省去。用函数的声明可以省去。被调函数的返回值类型是被调函数的返回值类型是整型整型或或字符型字符型时,时,对被调用函数的声明可以省去。对被调用函数的声明可以省去。21:39347.
27、4.5 函数的嵌套调用函数的嵌套调用 n C语言的函数定义都是互相平行、独立的。语言的函数定义都是互相平行、独立的。也就是说,也就是说,在定义函数时,一个函数内不能包在定义函数时,一个函数内不能包含另一个函数的定义。含另一个函数的定义。如果在一个函数中再调如果在一个函数中再调用其他的函数,则称为函数的嵌套调用。也就用其他的函数,则称为函数的嵌套调用。也就是说,在被调用函数的过程中,又可以调用另是说,在被调用函数的过程中,又可以调用另一个函数。一个函数。21:3935【例例7.7】输入输入n正整数,将它们从小到大排序后输出正整数,将它们从小到大排序后输出。#includevoidinput(in
28、ta,intn);voidchoose(inta,intn);voidprint(inta,intn);intmain(void)intn,a10;printf(输入变量输入变量n的值:的值:(n=10):);scanf(%d,&n);printf(输入输入%d个数组元素:个数组元素:,n);input(a,n);choose(a,n);printf(排序之后:排序之后:,n);print(a,n);printf(n);return0;21:3936void input(int a,int n)int i;for(i=0;in;i+)scanf(%d,&ai);voidchoose(inta,
29、intn)inti,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;jn;j+)if(ajak)k=j;t=ai,ai=ak,ak=t;voidprint(inta,intn)inti;for(i=0;in;i+)printf(%3d,ai);运行结果:运行结果:输入变量输入变量n的值:的值:(n=10):6输入输入6个数组元素:个数组元素:846231排序之后:排序之后:12346821:393721:3938【例例7.8】以下程序中包括以下程序中包括1个个main()函数和函数和3个自定义函数个自定义函数prtadd()、prtstarline()和和prtstar
30、s(),在自定义函数在自定义函数add()中调用中调用prtstarline()函数函数,在在prtstarline函数中调用函数中调用prtstars()函数。函数。#includevoidprtstars(int);voidprtstarline();voidprtadd(intx,inty)prtstarline();printf(sum=%dn,x+y);prtstarline();voidprtstars(intn)inti;for(i=0;in;i+)printf(*);nvoidprtstarline()prtstars(10);printf(n);intmain()inta=4
31、2,b=16;prtadd(a,b);return0;运行结果:运行结果:*sum=58*21:3939【例例7.97.9】分析下面程序的调用关系。分析下面程序的调用关系。#includeintfun2()intk=10;printf(%dn,k);return(10*k);intfun1()intb;b=fun2();printf(%dn,b);return(10*b);intmain()inta;a=fun1();printf(%dn,a);return0;运行结果:运行结果:10100100021:39407.5 递归函数递归函数 n在在C语言中一个函数可以直接或间接调用自语言中一个函数
32、可以直接或间接调用自己,这种己,这种函数自己调用自己的形式称为函数的递函数自己调用自己的形式称为函数的递归调用,归调用,带有递归调用的函数也称为递归函数。带有递归调用的函数也称为递归函数。递归调用的方法是一种重要的程序设计方法,许递归调用的方法是一种重要的程序设计方法,许多复杂问题可以很容易地使用递归方法得到解决。多复杂问题可以很容易地使用递归方法得到解决。21:39417.5.1 引例引例【例例7.10】用递归调用的方法求用递归调用的方法求n!。!。分析:由于分析:由于n!=n(n-1)!,所以要计算,所以要计算n!,就必须,就必须先计算先计算(n-1)!,要计算,要计算(n-1)!,必须先
33、计算,必须先计算(n-2)!,依,依此类推。要求此类推。要求2!,必须先知道,必须先知道1!,而,而1!是是1,0!也是也是1。以上关系可用如下式子表示:。以上关系可用如下式子表示:21:3942#includelongfac(intn)longi;if(n=0|n=1)i=1;elsei=n*fac(n-1);returni;运行结果为运行结果为:4 4!=24intmain()intn;scanf(%d,&n);if(n0)printf(Dataerror!n);elseprintf(%d!=%dn,n,fac(n);return0;21:39437.5.2 递归函数的概念递归函数的概念
34、构造递归函数的关键是寻找递归算法和递归的构造递归函数的关键是寻找递归算法和递归的终止条件。要采用递归方法来解决时,必须符合以下终止条件。要采用递归方法来解决时,必须符合以下2个条件:个条件:n(1)要解决的问题能简化为一个新问题,而这个)要解决的问题能简化为一个新问题,而这个新问题的解决方法仍与原来的解决方法相同,只是新问题的解决方法仍与原来的解决方法相同,只是所处理的问题进一步简化。归结为:所处理的问题进一步简化。归结为:寻找递归表达寻找递归表达式式。n(2)必定要有一个明确的结束递归的条件,一定)必定要有一个明确的结束递归的条件,一定要能够在适当的时候结束递归调用。归结为:要能够在适当的时
35、候结束递归调用。归结为:寻找寻找递归的出口递归的出口。21:3944 n下面分析下面分析例例7.10的执行过程。的执行过程。fac()副本副本1n=44*fac(3)返回值返回值24调用调用fac(4)fac()副本副本2n=33*fac(2)返回值返回值6fac()副本副本3n=22*fac(1)返回值返回值2fac()副本副本4n=1返回值返回值1例例7.10函数函数fac的执行过程的执行过程21:3945 fac(4)的执行过程用下面的展开和收缩过程表示:的执行过程用下面的展开和收缩过程表示:fac(4)4*fac(3)4*(3*fac(2)4*(3*(2*fac(1)开始满足出口条件:
36、开始满足出口条件:fac(1)返回值返回值14*(3*(2*1)4*(3*2)4*624n递归函数的结构清晰,可读性强,并且容易用数学递归函数的结构清晰,可读性强,并且容易用数学归纳法证明算法的正确性。但是,递归函数的运行归纳法证明算法的正确性。但是,递归函数的运行效率比较低,时间效率和空间效率都不高。效率比较低,时间效率和空间效率都不高。21:3946【例例7.11】分析如下程序。分析如下程序。intf(intx)inty;y=f(x);returny;n分析:分析:这是一个递归函数。但是该函数运行时将无这是一个递归函数。但是该函数运行时将无休止地调用其自身,这当然是不正确的。为了防止休止地
37、调用其自身,这当然是不正确的。为了防止递归调用无休止地进行,递归调用无休止地进行,必须在函数内有终止递归必须在函数内有终止递归调用的手段。调用的手段。常用的办法是加条件判断,满足某种常用的办法是加条件判断,满足某种条件后就不再递归调用,然后逐层返回。条件后就不再递归调用,然后逐层返回。21:3947【例例】分析下面程序的运行结果分析下面程序的运行结果#include/递归调用示例递归调用示例intf(inta,intn)if(n1)returna0+f(a+1,n-1);elsereturna0;main()intaa10=1,2,3,4,5,6,7,8,9,10,s;s=f(aa+2,4);
38、printf(%dn,s);答案:答案:1821:39487.5.3 递归函数程序设计递归函数程序设计 n【例例7.12】输出斐波拉契数列的第输出斐波拉契数列的第n项。斐波拉契项。斐波拉契数列的递推公式如下:数列的递推公式如下:分析:分析:递归表达式递归表达式f=f(n-l)+f(n-2);递归结束的条件,即递归结束的条件,即n=1或或n=2时,有确定的值时,有确定的值1。21:3949#includelongfibo(int);intmain()longf;intn;scanf(%d,&n);f=fibo(n);printf(%ldn,f);return0;运行时结果是:运行时结果是:10
39、55longfibo(intn)longf;if(n=1|n=2)f=1L;elsef=fibo(n-1)+fibo(n-2);returnf;21:3950#includeintmain()voidprintn(intx);intn;scanf(%d,&n);if(n=0&x=9)printf(%d,x);elseprintf(%d,x%10);printn(x/10);运行结果:运行结果:12345 54321【例例】分析如下程序的结果:分析如下程序的结果:21:3951#includeintfun(intx)intp;if(x=0|x=1)return2;elsep=x-fun(x-2)
40、;returnp;intmain()printf(%dn,fun(10);return0;【7.14】分析下面程序的输出结果。分析下面程序的输出结果。展开与收缩过程展开与收缩过程10-fun(8)10-(8-fun(6)10-(8-(6-fun(4)10-(8-(6-(4-fun(2)10-(8-(6-(4(2-fun(0)10-(8-(6-(4-(2-2)10-(8-(6-4)10-(8-2)10-645221:397.6 数组作函数的参数数组作函数的参数 n数组可以作为函数的参数使用数组可以作为函数的参数使用,完成函数间的数,完成函数间的数据传送。数组用作函数参数有两种形式,一种是据传送。
41、数组用作函数参数有两种形式,一种是把数组元素作为实参使用;另一种是把数组名作把数组元素作为实参使用;另一种是把数组名作为函数的形参和实参使用。为函数的形参和实参使用。n数组元素就是下标变量,它与普通变量并无区别。数组元素就是下标变量,它与普通变量并无区别。因此将数组元素作为函数实参使用与普通变量是因此将数组元素作为函数实参使用与普通变量是完全相同的。在发生函数调用时,把作为实参的完全相同的。在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。数组元素的值传送给形参,实现单向的值传送。7.6.1 数组元素作函数实参数组元素作函数实参5321:39【例例7.15】判别一个由判别
42、一个由3位整数组成的数组中位整数组成的数组中的升序数。输出这些升序数。的升序数。输出这些升序数。#includeintsx(intx)inta,b,c;a=x/100;b=x/10%10;c=x%10;if(ab&bc)return1;elsereturn0;intmain()inta10=213,345,224,258,67,412,736,379,423,456,i;for(i=0;i10;i+)if(sx(ai)printf(%d,ai);printf(n);return0;运行结果:运行结果:3452583673794565421:39数组名作为函数参数调用函数的格式为:数组名作为函数
43、参数调用函数的格式为:函数名函数名(数组名数组名)注意数组名后面不能有注意数组名后面不能有。用数组名作函数参数与用数组元素作实参有几点不同:用数组名作函数参数与用数组元素作实参有几点不同:(1)用数组元素作实参时,对数组元素的处理是按简单变用数组元素作实参时,对数组元素的处理是按简单变量对待的。用数组名作函数参数时,则要求形参和相对应的量对待的。用数组名作函数参数时,则要求形参和相对应的实参都必须是相同类型的数组。实参都必须是相同类型的数组。形参和实参二者类型不一致时,则会出错。形参和实参二者类型不一致时,则会出错。7.6.2 数组作函数数组作函数参数参数5521:39 n(2)用数组名作函数
44、参数时,并不是把实参数组用数组名作函数参数时,并不是把实参数组的每一个元素的值都赋予形参数组的各个元素。的每一个元素的值都赋予形参数组的各个元素。n因为实际上形参数组并不存在,因为实际上形参数组并不存在,编译系统不为编译系统不为形参数组分配内存。形参数组分配内存。n事实上,数组名就是数组的首地址。因此在数组事实上,数组名就是数组的首地址。因此在数组名作函数参数时所进行的传送只是地址值的传送,名作函数参数时所进行的传送只是地址值的传送,也就是说把实参数组的首地址赋予形参数组名。也就是说把实参数组的首地址赋予形参数组名。形参数组名取得该首地址之后,也就指向了实参形参数组名取得该首地址之后,也就指向
45、了实参的数组。实际上是形参数组和实参数组为同一数的数组。实际上是形参数组和实参数组为同一数组,共享相同的内存空间。组,共享相同的内存空间。5621:39【例例7.16】数组数组a中存放了中存放了10个正整数,要求调个正整数,要求调用函数将数组用函数将数组a中的数重新排列。排列的方法是中的数重新排列。排列的方法是将偶数放在数组的左部,奇数放在数组的右部。将偶数放在数组的左部,奇数放在数组的右部。例如:例如:原数组为:原数组为:213422425367417363742456重排后为:重排后为:3422473642456374136725215721:39 说明:说明:函数函数judge()的第一
46、个形参的第一个形参为整型数组为整型数组a,第二个形参,第二个形参n为为数组的长度。函数的功能是对数组的长度。函数的功能是对数组的元素重新排列。数组的元素重新排列。主函数主函数main中,数组中,数组a及及长度长度10作为实参传递给作为实参传递给judge()函数,数组传递后的内存单元函数,数组传递后的内存单元映像如右图所示。映像如右图所示。a 内存 ba021b0a134b1a2224b2a325b3a4367b4a541b5a6736b6a737b7a842b8a9456b9图图7.8数组传递后的内存映像数组传递后的内存映像5821:39 对数组名作为函数参数再强调以下几点:对数组名作为函数
47、参数再强调以下几点:n 形参数组和实参数组的名称不要求相同但类型形参数组和实参数组的名称不要求相同但类型必须一致,否则将会出错。必须一致,否则将会出错。n 形参数组和实参数组的长度可以不相同,因为形参数组和实参数组的长度可以不相同,因为在调用时,只传送形参数组的首地址而不检查其在调用时,只传送形参数组的首地址而不检查其长度。当形参数组的长度与实参数组不一致时,长度。当形参数组的长度与实参数组不一致时,虽然不会出现语法错误(编译能通过),但不提虽然不会出现语法错误(编译能通过),但不提倡这样使用。倡这样使用。n 在函数形参表中,允许不给出形参数组的长度,在函数形参表中,允许不给出形参数组的长度,
48、或增加一个变量形参来表示数组元素的个数。或增加一个变量形参来表示数组元素的个数。例如,例例如,例7.16的函数头部为:的函数头部为:voidjudge(intb,intn)5921:39 n二维数组也可以作为函数的参数。在函数定义二维数组也可以作为函数的参数。在函数定义时形参数组第一维的长度可以省略,但第二维的长时形参数组第一维的长度可以省略,但第二维的长度不能省略。因此,以下写法都是合法的。度不能省略。因此,以下写法都是合法的。intmax(inta310)或或intmax(inta10)实参实参形参形参传递方式传递方式说明说明常量、表达式、变常量、表达式、变量、数组元素量、数组元素变量变量
49、传值传值形参值的改变不影响实参形参值的改变不影响实参数组数组数组数组传地址传地址形参与实参数组共享内存形参与实参数组共享内存函数调用中形参与实参的取值与传递关系函数调用中形参与实参的取值与传递关系:6021:39【例例】已知函数已知函数abc的定义如下:的定义如下:voidabc(inta,intb)intc;for(c=0;cb;c+)ac+=b;若若main函数中有声明函数中有声明intx5=5及调用及调用abc函数的函数的语句,则正确的调用语句,则正确的调用abc函数的形式是函数的形式是。Aabc(x,x0);Babc(x0,x0);Cabc(&x0,x0);Dabc(x0,&x0);2
50、1:39615.5 变量与函数变量与函数 n 在函数定义的声明部分可以定义变量,在函数定义的声明部分可以定义变量,那么变量的定义是不是只能在函数中进行?那么变量的定义是不是只能在函数中进行?当然不是。这就引出了一个新的概念:当然不是。这就引出了一个新的概念:变量变量的作用域的作用域,也就是说变量在不同的地方定义,也就是说变量在不同的地方定义其作用域是不一样的。变量的作用域就是变其作用域是不一样的。变量的作用域就是变量的有效范围。下面就来讨论这一问题。量的有效范围。下面就来讨论这一问题。21:3962 C语言只允许在语言只允许在3个地方定义变量。个地方定义变量。n函数内部的声明部分。函数内部的声