1、第第9 9章章 函数函数C 语言程序设计进阶篇第1页C语言程序设计进阶篇内容概述函数定义、函数原型及申明。函数定义、函数原型及申明。函数调用及参数传递。函数调用及参数传递。函数嵌套概念及其定义和使用方法。函数嵌套概念及其定义和使用方法。函数递归概念及其定义和使用方法。函数递归概念及其定义和使用方法。局部变量、全局变量以及最惯用两种变局部变量、全局变量以及最惯用两种变量存放类型量存放类型autoauto和和staticstatic。第2页C语言程序设计进阶篇教学目标掌握自定义函数普通结构及定义函数方法;掌握自定义函数普通结构及定义函数方法;掌握自定义函数普通结构及定义函数方法;掌握自定义函数普通
2、结构及定义函数方法;掌握形参、实参、函数原型等主要概念。掌握函掌握形参、实参、函数原型等主要概念。掌握函掌握形参、实参、函数原型等主要概念。掌握函掌握形参、实参、函数原型等主要概念。掌握函数申明、函数调用普通方法;数申明、函数调用普通方法;数申明、函数调用普通方法;数申明、函数调用普通方法;熟悉函数嵌套概念,能定义和使用嵌套函数。熟悉函数嵌套概念,能定义和使用嵌套函数。熟悉函数嵌套概念,能定义和使用嵌套函数。熟悉函数嵌套概念,能定义和使用嵌套函数。了解局部变量、全局变量和变量存放类型概念,了解局部变量、全局变量和变量存放类型概念,了解局部变量、全局变量和变量存放类型概念,了解局部变量、全局变量
3、和变量存放类型概念,掌握掌握掌握掌握autoautoautoauto型和型和型和型和staticstaticstaticstatic型局部变量特点和使用方法。型局部变量特点和使用方法。型局部变量特点和使用方法。型局部变量特点和使用方法。了解了解了解了解mainmainmainmain函数参数及使用方法。函数参数及使用方法。函数参数及使用方法。函数参数及使用方法。第3页C语言程序设计进阶篇 在进行大型程序设计时,采取模块化在进行大型程序设计时,采取模块化程序设计是一个十分有效办法。程序设计是一个十分有效办法。C C语言在语言在支持模块化程序设计方面含有很强优势。支持模块化程序设计方面含有很强优势
4、。C C语言将函数作为程序设计基本单元,每语言将函数作为程序设计基本单元,每个函数用于描述一个相对独立基本操作,个函数用于描述一个相对独立基本操作,函数之间经过参数传递数据。采取模块函数之间经过参数传递数据。采取模块化程序设计思想可降低程序设计复杂度,化程序设计思想可降低程序设计复杂度,提升程序可维护性。提升程序可维护性。第4页C语言程序设计进阶篇 求解较小问题算法和程序称作求解较小问题算法和程序称作“功效模块功效模块”,”,各各功效模块能够先单独设计,然后将求解全部子问题模功效模块能够先单独设计,然后将求解全部子问题模块组合成求解原问题程序。块组合成求解原问题程序。由功效模块组成程序结构图由
5、功效模块组成程序结构图主控模块主控模块模块模块1_1模块模块1_n模块模块2_1模块模块2_n模块模块n_1模块模块n_n模块模块1模块模块2模块模块n第5页C语言程序设计进阶篇例例 输入两个数输出其中一个大数输入两个数输出其中一个大数main()main()int a,b,c;int a,b,c;int max(int x,int y);int max(int x,int y);printf(”a=b=“);printf(”a=b=“);scanf(“%d,%d”,&a,&b);scanf(“%d,%d”,&a,&b);c=max(a,bc=max(a,b););printf(“max=%d
6、”,c);printf(“max=%d”,c);int max(int x,int y)int z;if(xy)z=x;else z=y;return(z);第6页C语言程序设计进阶篇例例 输入年月日计算出该日为该年第几天。输入年月日计算出该日为该年第几天。分析:分析:(1 1)判断年份是否为闰年。判断年份是否为闰年。年份有闰年与平年之分,二年份有闰年与平年之分,二者区分在于闰年二月为者区分在于闰年二月为2929天,平年二月为天,平年二月为2828天。所以,给天。所以,给定一个年份,首先应确定其是否是闰年。定一个年份,首先应确定其是否是闰年。(2 2)求月份对应天数求月份对应天数。月份不一样,
7、其对应天数不一样,。月份不一样,其对应天数不一样,1 1、3 3、5 5、7 7、8 8、1010、1212月每个月为月每个月为3131天,天,4 4、6 6、9 9、1111月月每个月为每个月为3030天,天,2 2月依据所在年份是否为闰年来确定。月依据所在年份是否为闰年来确定。(3 3)求总天数求总天数。分为经历完整月份天数与经历不完整月。分为经历完整月份天数与经历不完整月份天数。份天数。(4 4)输出数据输出数据。输出年月日及对应天数。输出年月日及对应天数。第7页C语言程序设计进阶篇(1 1)判断闰年。)判断闰年。int leap(int year)int lp;lp=(year%4=0
8、&year%100!=0|year%400=0)?1:0;return lp;主控模块主控模块判断闰年判断闰年求某月天数求某月天数输输 出出输输 入入求总天数求总天数程序模块结构图程序模块结构图第8页C语言程序设计进阶篇(2 2)求某月天数。)求某月天数。/*/*函数函数month_daysmonth_days调用函数调用函数leapleap判断判断yearyear是否为闰年是否为闰年*/*/int month_days(int year,int month)int d;switch(month)case 1:case 3:case 5:case 7:case 8:case 10:case 1
9、2:d=31;break;case 2:d=leap(year)?29:28;break;/*/*若为闰年,若为闰年,d d赋值赋值2929,不然赋值,不然赋值28*/28*/default:d=30;return d;第9页C语言程序设计进阶篇(3 3)求天数和。)求天数和。/*/*函数函数daysdays调用函数调用函数month_daysmonth_days,求各月份对应天数,求各月份对应天数*/*/int days(int year,int month,int day)int i,ds=0;for(i=1;imonth;i+)ds=ds+month_days(year,i);ds=ds
10、+day;return ds;第10页C语言程序设计进阶篇注意注意:在完整程序中在完整程序中,前三个函数应放在前三个函数应放在main()main()函数之函数之前。前。(4)(4)主函数。主函数。主函数。主函数。void main()void main()int year,month,day,t_day;int year,month,day,t_day;printf(Input year-month-day:n);printf(Input year-month-day:n);scanf(%d-%d-%d,&year,&month,&day);scanf(%d-%d-%d,&year,&mon
11、th,&day);t_day=days(year,month,day);t_day=days(year,month,day);/*/*求天数和求天数和求天数和求天数和*/*/printf(%d-%d-%d is%dth day ofprintf(%d-%d-%d is%dth day of the year!n,year,month,day,t_day);the year!n,year,month,day,t_day);第11页C语言程序设计进阶篇 C C语言源程序是由函数组成,函数是语言源程序是由函数组成,函数是C C源程源程序基本模块,经过对函数模块调用实现特定序基本模块,经过对函数模块调
12、用实现特定功效。功效。C C语言中函数相当于其它高级语言子程语言中函数相当于其它高级语言子程序。序。C C语言不但提供了极为丰富库函数,还允语言不但提供了极为丰富库函数,还允许用户自己定义函数。许用户自己定义函数。9.1 9.1 函数概述函数概述第12页C语言程序设计进阶篇在在C C语言中可从不一样角度对函数分类:语言中可从不一样角度对函数分类:1 1从函数定义角度分类从函数定义角度分类库函数库函数由由C C系统提供,用户无须定义,也无须在程序中作类型系统提供,用户无须定义,也无须在程序中作类型说明,只需在程序前包含有该函数原型头文件即可在说明,只需在程序前包含有该函数原型头文件即可在程序中直
13、接调用。程序中直接调用。用户定义函数用户定义函数由用户按需要编写函数。对于用户自定义函数,不但由用户按需要编写函数。对于用户自定义函数,不但要在程序中定义函数本身,而且在主调函数模块中还要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。必须对该被调函数进行类型说明,然后才能使用。第13页C语言程序设计进阶篇有返回值函数有返回值函数有返回值函数有返回值函数 有返回值函数被调用执行完后将向调用者返回一个执有返回值函数被调用执行完后将向调用者返回一个执有返回值函数被调用执行完后将向调用者返回一个执有返回值函数被调用执行完后将向调用者返回一个执行结果,称为函数返
14、回值。行结果,称为函数返回值。行结果,称为函数返回值。行结果,称为函数返回值。无返回值函数无返回值函数无返回值函数无返回值函数 无返回值函数用于完成某项特定处理任务,执行完成无返回值函数用于完成某项特定处理任务,执行完成无返回值函数用于完成某项特定处理任务,执行完成无返回值函数用于完成某项特定处理任务,执行完成后不向调用者返回函数值。后不向调用者返回函数值。后不向调用者返回函数值。后不向调用者返回函数值。2 2从函数功效角度分类从函数功效角度分类:第14页C语言程序设计进阶篇3 3从主调函数和被调函数之间数据传送角度分类从主调函数和被调函数之间数据传送角度分类:无参函数无参函数 函数定义、函数
15、说明及函数调用中均不带参数。主函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。这类函数通惯调函数和被调函数之间不进行参数传送。这类函数通惯用来完成一组指定功效,能够返回或不返回函数值。用来完成一组指定功效,能够返回或不返回函数值。有参函数有参函数 有参函数也称为带参函数。在函数定义及函数说明有参函数也称为带参函数。在函数定义及函数说明时都有参数,称为形式参数(简称为形参)。在函数调时都有参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,称为实际参数(简称为实参)。用时也必须给出参数,称为实际参数(简称为实参)。第15页C语言程序设计进阶篇1.1.在在
16、C C语言中,全部函数都是平等语言中,全部函数都是平等,即函数不能嵌套即函数不能嵌套定义。不过函数之间允许相互调用,即允许嵌套调用。定义。不过函数之间允许相互调用,即允许嵌套调用。2.main()2.main()函数是程序执行起点函数是程序执行起点,也是程序执行终点。也是程序执行终点。3.3.一个一个C C源程序有且仅有一个主函数源程序有且仅有一个主函数main()main()。说明:说明:第16页C语言程序设计进阶篇 说明部分说明部分;执行部分执行部分;函数由函数由函数说明函数说明与与函数体函数体两部分组成。两部分组成。说明部分说明部分;执行部分执行部分;9.2 9.2 函数定义函数定义函数
17、说明函数说明函数体函数体函数说明函数说明函数体函数体1 1无参函数无参函数类型说明符类型说明符 函数名函数名()()2 2有参函数有参函数类型说明符类型说明符 函数名(形式参数表)函数名(形式参数表)第17页C语言程序设计进阶篇例例 调用函数在屏幕上打印一行调用函数在屏幕上打印一行“*”“*”#include stdio.h#include stdio.hvoid print()void print()/*/*无参函数无参函数无参函数无参函数*/*/printf(*);printf(*);main()main()print();print();程序运行结果:程序运行结果:*第18页C语言程序设
18、计进阶篇#include stdio.h#include stdio.hvoid print(int n)void print(int n)/*/*/*/*一个形参一个形参一个形参一个形参*/*/*/*/int i;int i;for(i=0;in;i+)for(i=0;in;i+)printf(*);printf(*);main()main()int n;int n;scanf(%d,&n);scanf(%d,&n);print(n);print(n);/*/*/*/*一个实参一个实参一个实参一个实参*/*/*/*/例 调用函数在屏幕上打印指定数目“*”程序运行结果:程序运行结果:10*第1
19、9页C语言程序设计进阶篇#include stdio.h#include stdio.hvoid print(int n,char ch)void print(int n,char ch)/*/*/*/*两个形参两个形参两个形参两个形参*/*/*/*/int i;int i;for(i=0;in;i+)for(i=0;in;i+)printf(%c,ch);printf(%c,ch);main()main()int n;int n;char ch;char ch;scanf(%d%c,&n,&ch);scanf(%d%c,&n,&ch);print(n,ch);print(n,ch);/*/*
20、/*/*两个实参两个实参两个实参两个实参*/*/*/*/例 调用函数在屏幕上打印指定数目任意符号程序运行结果:程序运行结果:10$第20页C语言程序设计进阶篇9.3.1 9.3.1 9.3.1 9.3.1 形式参数与实际参数形式参数与实际参数形式参数与实际参数形式参数与实际参数 函数参数分为形式参数和实际参数两种。在定义函数参数分为形式参数和实际参数两种。在定义函数时函数名后面括号中变量称为形式参数,简称形函数时函数名后面括号中变量称为形式参数,简称形参。在调用函数时,函数名后面括号中表示式称为实参。在调用函数时,函数名后面括号中表示式称为实际参数,简称实参。际参数,简称实参。形式参数形式参数
21、(简称形参简称形参)定义函数使用参数定义函数使用参数实际参数实际参数(简称实参简称实参)调用函数使用参数调用函数使用参数9.3 9.3 函数参数和返回值函数参数和返回值第21页C语言程序设计进阶篇【例【例9.19.1】求】求 1+2+3+n 1+2+3+n值。值。#include stdio.h#include stdio.hint s(int n)int s(int n)int i,s=0;int i,s=0;for(i=1;i=n;i+)for(i=1;i=1;i-)for(i=n-1;i=1;i-)n=n+i;n=n+i;printf(n=%dn,n);printf(n=%dn,n);v
22、oid main()void main()int n;int n;printf(input numbern);printf(input numbern);scanf(%d,&n);scanf(%d,&n);s(n);s(n);printf(n=%dn,n);printf(n=%dn,n);程序运行情况以下:程序运行情况以下:input number100n=5050n=100第23页C语言程序设计进阶篇函数函数mainmain函数函数s snn实参加形参数据传递实参加形参数据传递经过函数调用,将实参值传递给形参经过函数调用,将实参值传递给形参.函数调用时,系统对参数处理步骤为:函数调用时,系统
23、对参数处理步骤为:计算各实参值,将实参值压入形参栈中,然后执计算各实参值,将实参值压入形参栈中,然后执 行函数体。行函数体。当函数执行完返回时,形参从栈顶弹出(取走)。当函数执行完返回时,形参从栈顶弹出(取走)。第24页C语言程序设计进阶篇函数形参和实参含有以下特点:函数形参和实参含有以下特点:形参变量只有在被调用时才分配内存单元,在调用结形参变量只有在被调用时才分配内存单元,在调用结束时,马上释放所分配内存单元。束时,马上释放所分配内存单元。实参能够是常量、变量、表示式、函数等,不论实实参能够是常量、变量、表示式、函数等,不论实参是何种类型量,在进行函数调用时,它们都必须含有参是何种类型量,
24、在进行函数调用时,它们都必须含有确定值,方便把这些值传送给形参。确定值,方便把这些值传送给形参。实参和形参在数量上、类型上、次序上应严格一致,实参和形参在数量上、类型上、次序上应严格一致,不然会发生不然会发生“类型不匹配类型不匹配”错误。错误。函数调用中发生数据传送是单向。函数调用中发生数据传送是单向。第25页C语言程序设计进阶篇 C C函数计算结果经过函数计算结果经过 return return语句返回语句返回,return,return语语句表示形式以下:句表示形式以下:return return 表示式;表示式;或或 returnreturn(表示式);(表示式);9.3.2 9.3.2
25、 函数返回值函数返回值 函数返回值也就是函数值,是指函数被调用之后,函数返回值也就是函数值,是指函数被调用之后,执行函数体中程序段所取得并返回给主调函数值。执行函数体中程序段所取得并返回给主调函数值。第26页C语言程序设计进阶篇对函数值有以下一些说明:对函数值有以下一些说明:函数值只能经过函数值只能经过returnreturn语句返回给主调函数。语句返回给主调函数。函数值类型和函数定义中函数类型应保持一致。假如二函数值类型和函数定义中函数类型应保持一致。假如二者不一致,则以定义时函数类型为准,自动进行类型转换。者不一致,则以定义时函数类型为准,自动进行类型转换。如函数值为整型,在函数定义时能够
26、省去类型说明。如函数值为整型,在函数定义时能够省去类型说明。不返回函数值函数,能够明确定义为不返回函数值函数,能够明确定义为“空类型空类型”,类型,类型说明符为说明符为“void”“void”。第27页C语言程序设计进阶篇 一个函数一旦被定义,就可在程序其它函数中使用它,一个函数一旦被定义,就可在程序其它函数中使用它,这个过程称为这个过程称为函数调用函数调用。9.4.1 9.4.1 函数普通调用函数普通调用函数名函数名(实际参数列表)实际参数列表)函数调用形式:函数调用形式:9.4 9.4 函数调用函数调用 实际参数普通为表示式,能够是常量、变量实际参数普通为表示式,能够是常量、变量(调用时必
27、须有确定值或确定地址)。而形式参数(调用时必须有确定值或确定地址)。而形式参数必须为变量。必须为变量。第28页C语言程序设计进阶篇函数表示式函数表示式 函数作为表示式中一项出现在表示式中,以函数函数作为表示式中一项出现在表示式中,以函数返回值参加表示式运算。这种方式要求函数是有返回返回值参加表示式运算。这种方式要求函数是有返回值。值。如如 sum=s(n);函数语句函数语句 函数调用普通形式加上分号即组成函数语句。函数调用普通形式加上分号即组成函数语句。如如 printf();scanf();print();函数实参函数实参 函数作为另一个函数调用实际参数出现。函数作为另一个函数调用实际参数出
28、现。如如 printf(“sum=%d”,s(n);C C语言中,能够用以下几个方式调用函数:语言中,能够用以下几个方式调用函数:第29页C语言程序设计进阶篇9.4.2 9.4.2 实参到形参数据传递方式实参到形参数据传递方式传值方式传递数据传值方式传递数据 函数调用时,调用函数把实参值复制一份,传送给函数调用时,调用函数把实参值复制一份,传送给被调用函数形参,从而实现调用函数向被调用函数数据被调用函数形参,从而实现调用函数向被调用函数数据传送。实参对形参数据传送是单向。传送。实参对形参数据传送是单向。传址方式传递数据传址方式传递数据 函数调用时,将实参地址传给被调用函数,被调用函数调用时,将
29、实参地址传给被调用函数,被调用函数从传过来地址中取出实参所存数据进行操作。在传函数从传过来地址中取出实参所存数据进行操作。在传址方式中,实参和形参占用是同一段内存单元,所以形址方式中,实参和形参占用是同一段内存单元,所以形参值修改实际是就是对实参值修改。参值修改实际是就是对实参值修改。第30页C语言程序设计进阶篇9.4.3 9.4.3 函数申明和函数原型函数申明和函数原型 调用用户自定义函数时,普通调用函数和被调用调用用户自定义函数时,普通调用函数和被调用函数应在同一个文件中,在调用函数中对被调用函数函数应在同一个文件中,在调用函数中对被调用函数返回值类型、函数名称、函数形式参数类型进行说明,
30、返回值类型、函数名称、函数形式参数类型进行说明,这种说明称为这种说明称为函数申明函数申明。函数申明普通形式以下:函数申明普通形式以下:类型名类型名 函数名函数名(类型类型1 1 形参形参1 1,类型,类型n n 形参形参n);n);或或 类型名类型名 函数名(类型函数名(类型1 1,类型,类型2 2,类型,类型n n);或或 类型名类型名 函数名函数名();();函数申明是以语句形式出现,所以其后有语句结束函数申明是以语句形式出现,所以其后有语句结束标识标识“;”“;”。第31页C语言程序设计进阶篇 假如被调函数返回值是整型或字符型时,能够不对被假如被调函数返回值是整型或字符型时,能够不对被调
31、函数作说明而直接调用。这时系统将自对被调函数返调函数作说明而直接调用。这时系统将自对被调函数返回值按整型处理。回值按整型处理。当被调函数函数定义出现在主调函数之前时,在主调当被调函数函数定义出现在主调函数之前时,在主调函数中也能够不对被调函数再作说明而直接调用。函数中也能够不对被调函数再作说明而直接调用。如在全部函数定义之前,在函数外预先说明了各个函如在全部函数定义之前,在函数外预先说明了各个函数类型,则在以后各主调函数中,可不对被调函数作说数类型,则在以后各主调函数中,可不对被调函数作说明。明。对库函数调用不需要再作说明,但必须把该函数头文对库函数调用不需要再作说明,但必须把该函数头文件用件
32、用includeinclude命令包含在源文件前部。命令包含在源文件前部。C C语言要求存在以下几个情况时,能够省去主调函语言要求存在以下几个情况时,能够省去主调函数中对被调函数函数说明:数中对被调函数函数说明:第32页C语言程序设计进阶篇例例 编程求两个整数阶乘之和。编程求两个整数阶乘之和。#include void main()int m1,m2;long result;long fac(int);/*/*申明后面定义函数申明后面定义函数fac*/fac*/printf(请输入整数请输入整数m1,m2:);scanf(%d,%d,&m1,&m2);result=fac(m1)+fac(m2
33、);/*/*函数调用函数调用*/*/printf(%d!+%d!=%ld n,m1,m2,result);第33页C语言程序设计进阶篇long fac(int n)long fac(int n)/*/*/*/*定义函数定义函数定义函数定义函数facfacfacfac,其功效是求,其功效是求,其功效是求,其功效是求n!*/n!*/n!*/n!*/int i int i;long r=1 long r=1;for(i=1;i=n;i+)for(i=1;i=n;i+)r=r*i;r=r*i;return rreturn r;运行情况以下:运行情况以下:运行情况以下:运行情况以下:请输入整数请输入整数
34、请输入整数请输入整数m1,m2:3m1,m2:3,5 5 3 3!+5+5!=126=126第34页C语言程序设计进阶篇 所谓函数嵌套调用是指一个函数调用另一函数过程所谓函数嵌套调用是指一个函数调用另一函数过程中又出现对其它函数调用。中又出现对其它函数调用。这种嵌套调用层次标准上不限制。这种嵌套调用层次标准上不限制。函数函数1 1 函数函数2 2 函数函数3 3 .调用函数调用函数2 2 调用函数调用函数3 3 .9.59.5函数嵌套调用函数嵌套调用第35页C语言程序设计进阶篇【例【例9.29.2】计算】计算s=2s=22 2!+3!+32 2!程序分析:程序分析:本题可编写两个函数:一个是用
35、来计算平方值本题可编写两个函数:一个是用来计算平方值函数函数f1()f1();另一个是用来计算阶乘值函数;另一个是用来计算阶乘值函数f2()f2()。主。主函数先调函数先调f1()f1()函数计算出平方值,再在函数计算出平方值,再在f1()f1()函数中函数中以平方值为实参,调用以平方值为实参,调用f2()f2()函数计算其阶乘值,然函数计算其阶乘值,然后返回到后返回到f1()f1()函数,再返回主函数,在循环程序中函数,再返回主函数,在循环程序中计算累加和。计算累加和。第36页C语言程序设计进阶篇#include stdio.hlong f2(int q)long c=1;int i;for
36、(i=1;i=q;i+)c=c*i;return c;long f1(int p)int k;long r;k=p*p;r=f2(k);return r;程序代码以下:程序代码以下:void main()int i;long s=0;for(i=2;i=3;i+)s=s+f1(i);printf(ns=%ldn,s);第37页C语言程序设计进阶篇9.6 9.6 函数递归调用函数递归调用 一个函数在执行过程中又直接或间接调用本身一个函数在执行过程中又直接或间接调用本身一个函数在执行过程中又直接或间接调用本身一个函数在执行过程中又直接或间接调用本身过程称为递归调用,这种函数称为递归函数。在递过程称
37、为递归调用,这种函数称为递归函数。在递过程称为递归调用,这种函数称为递归函数。在递过程称为递归调用,这种函数称为递归函数。在递归调用中,主调函数又是被调函数,执行递归函数归调用中,主调函数又是被调函数,执行递归函数归调用中,主调函数又是被调函数,执行递归函数归调用中,主调函数又是被调函数,执行递归函数将重复调用其本身。将重复调用其本身。将重复调用其本身。将重复调用其本身。第38页C语言程序设计进阶篇递归递归不是不是一个数据结构,而是一个有效一个数据结构,而是一个有效算算法设计法设计注意:注意:注意:注意:递归算法必须是递归算法必须是递归算法必须是递归算法必须是逐步逐步逐步逐步有规律有规律有规律
38、有规律简化简化简化简化,最终,最终,最终,最终 要有一个非递归出口,要有一个非递归出口,要有一个非递归出口,要有一个非递归出口,不能出现无穷调用不能出现无穷调用不能出现无穷调用不能出现无穷调用情况。情况。情况。情况。第39页C语言程序设计进阶篇阶乘递归定义:阶乘递归定义:(1)5!=5 4!(2)4!=4 3!(3)3!=3 2!(4)2!=2 1!(5)1!=1 0!(6)0!=1【例【例9.39.3】用递归调使用方法计】用递归调使用方法计算算n!n!第40页C语言程序设计进阶篇long int fact(int n)int x;long int y;if(n=0)return 1;x=n-
39、1;y=fact(x);return(n*y);用递归求阶乘用递归求阶乘C C语言实当代码以下:语言实当代码以下:#include void main()long int fn;fn=fact(5);printf(”nfn=%ld”,fn);第41页C语言程序设计进阶篇求解阶乘求解阶乘 5!5!过程过程主程序主程序主程序主程序 main:fact(5)main:fact(5)参数参数 5 5 计算计算 5*fact(4)5*fact(4)返回返回 120 120参数参数 4 4 计算计算 4*fact(3)4*fact(3)返回返回 24 24参数参数 3 3 计算计算 3*fact(2)3*
40、fact(2)返回返回 6 6参数参数 2 2 计算计算 2*fact(1)2*fact(1)返回返回 2 2参数参数 1 1 计算计算 1*fact(0)1*fact(0)返回返回 1 1参参参参数数数数传传传传递递递递结结结结果果果果返返返返回回回回递递归归调调用用回回归归求求值值参数参数 0 0 直接定值直接定值=1 =1 返回返回 1 1第42页C语言程序设计进阶篇n=5 5!5*4!4*3!3*2!2*1!1 1 1*2 2*3 6*4 24*5120回推回推递推递推递归结束递归结束条件条件n!=1 (n=1)2n*(n-1)!(n1)第43页C语言程序设计进阶篇【例【例9.49.4
41、】用递归法将一个整数】用递归法将一个整数n n逆序输出。逆序输出。程序分析:程序分析:首先定义一个递归函数首先定义一个递归函数convert()convert()。在主函数。在主函数中调用中调用convert()convert()。convert()convert()函数执行过程是:程序函数执行过程是:程序首先将整数首先将整数n n最低位数字转换为字符后并输出;假如最低位数字转换为字符后并输出;假如n10n10将结束函数执行,不然就递归调用将结束函数执行,不然就递归调用convert()convert()函函数本身。因为每次递归调用实参为数本身。因为每次递归调用实参为n/10n/10,即把,即
42、把n/10n/10值值赋予形参赋予形参n n,最终当,最终当n n值小于值小于1010时不再作递归调用,形时不再作递归调用,形参参n n值也小于值也小于1010,即,即i=0i=0,将使递归终止,然后逐层退,将使递归终止,然后逐层退回。回。第44页C语言程序设计进阶篇#include stdio.h void convert(int n)int i;putchar(n%10+0);if(i=n/10)!=0)convert(i);void main()int number;printf(Input an integer:);scanf(%d,&number);if(number0)putcha
43、r(-);number=-number;convert(number);putchar(n);程序代码以下:程序代码以下:第45页C语言程序设计进阶篇补充:补充:HanoiHanoi塔问题塔问题 假设有三根木桩分别为假设有三根木桩分别为A A、B B和和C C。在木桩。在木桩A A上安置了上安置了N N个圆个圆盘,由上到下编号为盘,由上到下编号为1 1,2 2,NN,编号越大圆盘直径也越大。,编号越大圆盘直径也越大。现需要将现需要将A A木桩上木桩上N N个圆盘借助个圆盘借助B B木桩移到木桩移到C C木桩上,且必须木桩上,且必须按照下述移动规则:按照下述移动规则:1.1.直径较小圆盘永远置于
44、直径比较大圆盘上直径较小圆盘永远置于直径比较大圆盘上;2.2.圆盘可任意地由任何一个木桩移到其它木桩上圆盘可任意地由任何一个木桩移到其它木桩上;3.3.一次只能移动一个盘子。一次只能移动一个盘子。第46页C语言程序设计进阶篇第47页C语言程序设计进阶篇 汉诺塔汉诺塔汉诺塔汉诺塔(Tower of Hanoi)(Tower of Hanoi)(Tower of Hanoi)(Tower of Hanoi)问题解题思绪:问题解题思绪:问题解题思绪:问题解题思绪:假如假如假如假如 n=1 n=1 n=1 n=1,则将这一个盘子直接从,则将这一个盘子直接从,则将这一个盘子直接从,则将这一个盘子直接从A
45、 A A A柱移到柱移到柱移到柱移到C C C C柱上。否柱上。否柱上。否柱上。否则,执行以下三步:则,执行以下三步:则,执行以下三步:则,执行以下三步:1.1.1.1.用用用用C C C C柱做过渡,将柱做过渡,将柱做过渡,将柱做过渡,将A A A A柱上柱上柱上柱上(n-1)(n-1)(n-1)(n-1)个盘子移到个盘子移到个盘子移到个盘子移到B B B B柱上;柱上;柱上;柱上;2.2.2.2.将将将将A A A A柱上最终一个盘子直接移到柱上最终一个盘子直接移到柱上最终一个盘子直接移到柱上最终一个盘子直接移到C C C C柱上;柱上;柱上;柱上;3.3.3.3.用用用用A A A A柱
46、做过渡,将柱做过渡,将柱做过渡,将柱做过渡,将B B B B柱上柱上柱上柱上(n-1)(n-1)(n-1)(n-1)个盘子移到个盘子移到个盘子移到个盘子移到C C C C柱上。柱上。柱上。柱上。第48页C语言程序设计进阶篇#include void Hanoi(int n,char x,char y,char z)if(n=1)printf(Move disk%d from%c to%cn,n,x,z);else Hanoi(n-1,x,z,y);printf(Move disk%d from%c to%cn,n,x,z);Hanoi(n-1,y,x,z);void main()int num
47、;char one,two,three;scanf(%d,&num);scanf(%c%c%c,&one,&two,&three);Hanoi(num,one,two,three);第49页C语言程序设计进阶篇变量数据类型变量数据类型变量应占用内存空间大小变量应占用内存空间大小变量在存放空间分配时所限定边界条件变量在存放空间分配时所限定边界条件变量性质变量性质变量数据类型变量数据类型变量存放类型变量存放类型变量作用域变量作用域变量生存期变量生存期共同决定共同决定9.79.7变量作用域及存放特征变量作用域及存放特征第50页C语言程序设计进阶篇1.1.变量按作用域:分为全局变量和局部变量变量按作用
48、域:分为全局变量和局部变量2.2.区分:见下表区分:见下表全局变量全局变量全局变量全局变量(外部变量外部变量外部变量外部变量)局部变量局部变量局部变量局部变量(内部变量内部变量内部变量内部变量)定义位置定义位置定义位置定义位置函数体外函数体外函数体外函数体外函数体内函数体内函数体内函数体内作用域作用域作用域作用域从定义处到文件结束从定义处到文件结束从定义处到文件结束从定义处到文件结束 从定义处到本函数结束从定义处到本函数结束从定义处到本函数结束从定义处到本函数结束举例举例举例举例n n全部在函数体外全部在函数体外全部在函数体外全部在函数体外定义变量定义变量定义变量定义变量n n(1)(1)全部
49、在函数全部在函数全部在函数全部在函数体内定义变量体内定义变量体内定义变量体内定义变量n n(2)(2)形式参数形式参数形式参数形式参数注意注意注意注意n n与局部变量同名与局部变量同名与局部变量同名与局部变量同名处理处理处理处理n n不一样函数中同不一样函数中同不一样函数中同不一样函数中同名局部变量互不名局部变量互不名局部变量互不名局部变量互不干扰干扰干扰干扰9.7.1.9.7.1.变量作用域变量作用域 第51页C语言程序设计进阶篇课堂练习课堂练习1 1:分析下面程序运行结果。:分析下面程序运行结果。void f1()int t=2;a*=t;b/=t;void main()int a,b;p
50、rintf(”Enter a,b:”);scanf(”%d,%d”,&a,&b);f1();/*调用函数调用函数f1()*/printf(”a=%d,b=%d”,a,b);编译程序会提醒犯错编译程序会提醒犯错:undefined symbol a 和和 undefined symbol b。为何为何?第52页C语言程序设计进阶篇课堂练习课堂练习2 2:分析下面程序运行结果:分析下面程序运行结果#include int a=2,b=4;/*a,b/*a,b为全局变量为全局变量*/*/void f1()int t1,t2;t1=a*2;t2=b*3;b=100;printf(”t1=%d,t2=%