第6章 函数与编译预处理.ppt
第第6章章 函数与编译预处函数与编译预处理理C语言程序设计教程2022/11/52C语言程序设计教程第6章 函数与编译预处理教学目的和基本要求:教学目的和基本要求:要求学生了解模块化程序设计的思想,掌握函数的定义及调用,理解变量的作用域与存储方式的概念,理解编译预处理的概念。教学重点:教学重点:函数的定义及调用、递归调用、变量的作用域。2 2C语言程序设计教程2022/11/53C语言程序设计教程第6章 函数与编译预处理6.1 模块化程序设计与函数模块化程序设计与函数 在在在在解解解解决决决决较较较较复复复复杂杂杂杂的的的的问问问问题题题题时时时时,我我我我们们们们一一一一般般般般采采采采用用用用的的的的方方方方法法法法是是是是:把把把把问问问问题题题题分分分分成成成成几几几几个个个个部部部部分分分分,每每每每部部部部分分分分又又又又可可可可分分分分成成成成更更更更细细细细的的的的若若若若干干干干小小小小部部部部分分分分,逐逐逐逐步步步步细细细细化化化化,直直直直至至至至把把把把复复复复杂杂杂杂的的的的问问问问题题题题分分分分解解解解成成成成为为为为很很很很容容容容易易易易求求求求解解解解的的的的一一一一些些些些小小小小问问问问题题题题。这这这这样样样样,原原原原来来来来问问问问题题题题的的的的解解解解就就就就可可可可以以以以由由由由这这这这些些些些小小小小问问问问题的解来表示了。题的解来表示了。题的解来表示了。题的解来表示了。求解较小问题的程序模块称为求解较小问题的程序模块称为“功能模块功能模块”。一个。一个较大的程序一般都应分为若干个功能模块,每个模块用较大的程序一般都应分为若干个功能模块,每个模块用来实现一个特定的功能,这也就是模块化程序设计的思来实现一个特定的功能,这也就是模块化程序设计的思想。想。3 3C语言程序设计教程2022/11/54C语言程序设计教程第6章 函数与编译预处理一、模块与函数 在在在在C C C C语语语语言言言言中中中中是是是是用用用用函函函函数数数数来来来来实实实实现现现现模模模模块块块块功功功功能能能能的的的的,故故故故一一一一个个个个C C C C程程程程序序序序可可可可以以以以由由由由一一一一个个个个主主主主函函函函数数数数和和和和若若若若干干干干个个个个其其其其它它它它函函函函数数数数构构构构成成成成。由由由由主主主主函函函函数数数数调调调调用用用用其其其其它它它它函函函函数数数数,其其其其它它它它函函函函数数数数也也也也可可可可以以以以互互互互相相相相调调调调用用用用,同同同同一一一一个函数可以被一个或多个函数调用任意多次。个函数可以被一个或多个函数调用任意多次。个函数可以被一个或多个函数调用任意多次。个函数可以被一个或多个函数调用任意多次。C C C C语语语语言言言言就就就就是是是是通通通通过过过过函函函函数数数数的的的的调调调调用用用用来来来来实实实实现现现现完完完完成成成成较较较较大大大大程程程程序序序序的全部功能。的全部功能。的全部功能。的全部功能。模模模模块块块块化化化化的的的的程程程程序序序序设设设设计计计计就就就就是是是是靠靠靠靠设设设设计计计计函函函函数数数数和和和和调调调调用用用用函函函函数数数数实实实实现的。现的。现的。现的。4 4C语言程序设计教程2022/11/55C语言程序设计教程第6章 函数与编译预处理任务模块模块模块函数函数函数函数函数函数任务、任务、模块与函数的关系模块与函数的关系:5 5C语言程序设计教程2022/11/56C语言程序设计教程第6章 函数与编译预处理例例例例6_1:6_1:从键盘输入两个数,求这两个数的较大值从键盘输入两个数,求这两个数的较大值从键盘输入两个数,求这两个数的较大值从键盘输入两个数,求这两个数的较大值main()main()inta,b,maxv;inta,b,maxv;scanf(%d%d,&a,&b);scanf(%d%d,&a,&b);maxv=maxv=max(a,b)max(a,b);star();star();printf(“themax_value=%dn,maxv);printf(“themax_value=%dn,maxv);star()star();intmax(intxintmax(intx,inty)inty)intz;intz;if(xy)z=x;if(xy)z=x;elsez=y;elsez=y;returnz;returnz;voidstar()voidstar()printf(“*n”);printf(“*n”);6 6C语言程序设计教程2022/11/57C语言程序设计教程第6章 函数与编译预处理二、模块设计的原则二、模块设计的原则1 1、模块独立:、模块独立:独立性原则表现在模块完成独立的功能独立性原则表现在模块完成独立的功能,模块间的模块间的关系尽量简单关系尽量简单,各模块可以单独调试。修改某一模块各模块可以单独调试。修改某一模块,不不会造成整个程序的混乱。会造成整个程序的混乱。2 2、模块规模适当:、模块规模适当:模块不能太大模块不能太大,但也不能太小。模块太大,功能复杂但也不能太小。模块太大,功能复杂,可读性就不好。但如果模块太小,各个模块间反复调用,可读性就不好。但如果模块太小,各个模块间反复调用,也会增加程序的复杂度,可读性也会降低。这点需要在也会增加程序的复杂度,可读性也会降低。这点需要在不断的实践中慢慢积累经验。不断的实践中慢慢积累经验。7 7C语言程序设计教程2022/11/58C语言程序设计教程第6章 函数与编译预处理6.2 函数的定义与调用函数的定义与调用 在在在在C C语语语语言言言言中中中中,函函函函数数数数是是是是一一一一个个个个处处处处理理理理过过过过程程程程,可可可可以以以以进进进进行行行行数数数数值值值值运运运运算算算算、信信信信息息息息处处处处理理理理、控控控控制制制制决决决决策策策策等等等等,即即即即一一一一段段段段完完完完成成成成某某某某个个个个功功功功能能能能的的的的程程程程序序序序放放放放在在在在函函函函数数数数中中中中进进进进行行行行,函函函函数数数数结结结结束束束束时时时时可可可可以以以以携携携携带带带带或或或或不不不不携携携携带带带带处理结果。处理结果。处理结果。处理结果。C C语语语语言言言言程程程程序序序序全全全全部部部部是是是是以以以以函函函函数数数数的的的的形形形形式式式式出出出出现现现现,最最最最简简简简单单单单的的的的C C程序也至少要有一个程序也至少要有一个程序也至少要有一个程序也至少要有一个mainmain函数。函数。函数。函数。函数必须先定义和声明后才能调用函数必须先定义和声明后才能调用函数必须先定义和声明后才能调用函数必须先定义和声明后才能调用。从用户使用函数的角度来看,函数有两种:从用户使用函数的角度来看,函数有两种:库函数库函数(标准函数标准函数):系统提供的:系统提供的 用户自定义函数用户自定义函数:用户自己编写的:用户自己编写的8 8C语言程序设计教程2022/11/59C语言程序设计教程第6章 函数与编译预处理一、标准库函数一、标准库函数 C C C C语言有丰富的库函数,这些函数的说明在不语言有丰富的库函数,这些函数的说明在不语言有丰富的库函数,这些函数的说明在不语言有丰富的库函数,这些函数的说明在不同的头文件同的头文件同的头文件同的头文件(*.(*.(*.(*.h)h)h)h)中。中。中。中。想要调用标准的库函数,就必须用编译预处理想要调用标准的库函数,就必须用编译预处理想要调用标准的库函数,就必须用编译预处理想要调用标准的库函数,就必须用编译预处理命令命令命令命令includeincludeincludeinclude把程序中所用到的头文件包含进来。把程序中所用到的头文件包含进来。把程序中所用到的头文件包含进来。把程序中所用到的头文件包含进来。例如:例如:例如:例如:include“stdio.h”#includemain()printf(“%f”,sqrt(2*3);调用调用sqrt函数函数(求根号求根号)时,时,必须有必须有include9 9C语言程序设计教程2022/11/510C语言程序设计教程第6章 函数与编译预处理函数定义的一般形式:函数定义的一般形式:函数定义的一般形式:函数定义的一般形式:函数类型名函数类型名函数类型名函数类型名 函数名函数名函数名函数名(形式参数类型说明列表形式参数类型说明列表形式参数类型说明列表形式参数类型说明列表)局部变量说明部分局部变量说明部分局部变量说明部分局部变量说明部分 可执行语句序列可执行语句序列可执行语句序列可执行语句序列 二、函数的定义二、函数的定义例如:求两个数中的较大者的函数例如:求两个数中的较大者的函数例如:求两个数中的较大者的函数例如:求两个数中的较大者的函数intmax(intxintmax(intx,inty)/*inty)/*有两个整型的形式参数有两个整型的形式参数有两个整型的形式参数有两个整型的形式参数*/intz;/*intz;/*局部变量局部变量局部变量局部变量 z z定义定义定义定义*/if(xy)z=x;if(xy)z=x;elsez=y;elsez=y;returnz;/*returnz;/*返回语句,函数携带整型返回值返回语句,函数携带整型返回值返回语句,函数携带整型返回值返回语句,函数携带整型返回值*/1010C语言程序设计教程2022/11/511C语言程序设计教程第6章 函数与编译预处理函数定义分为两大部分:函数定义分为两大部分:函数定义分为两大部分:函数定义分为两大部分:函数的说明函数的说明函数的说明函数的说明部分和部分和部分和部分和函数体函数体函数体函数体部分。部分。部分。部分。1.1.1.1.函数说明部分(函数首部)函数说明部分(函数首部)函数说明部分(函数首部)函数说明部分(函数首部)(1 1 1 1)函数类型)函数类型)函数类型)函数类型:即函数返回值的类型。:即函数返回值的类型。:即函数返回值的类型。:即函数返回值的类型。如如如如上上上上例例例例中中中中函函函函数数数数的的的的类类类类型型型型是是是是intintintint,即即即即函函函函数数数数的的的的返返返返回回回回值值值值z z z z是是是是intintintint类类类类型型型型。如如如如果果果果函函函函数数数数有有有有返返返返回回回回值值值值,要要要要用用用用返返返返回回回回语语语语句句句句returnreturnreturnreturn。returnreturnreturnreturn语句的一般形式是:语句的一般形式是:语句的一般形式是:语句的一般形式是:returnreturnreturnreturn(表达式);(表达式);(表达式);(表达式);或或或或 return return return return 表达式;表达式;表达式;表达式;(2 2)函数名)函数名 函数名是用户定义函数时自己命名的,其命名遵循函数名是用户定义函数时自己命名的,其命名遵循函数名是用户定义函数时自己命名的,其命名遵循函数名是用户定义函数时自己命名的,其命名遵循C C C C 语言标识符命名规则。语言标识符命名规则。语言标识符命名规则。语言标识符命名规则。如果函数不需要提供返回值,可定义函数类型为空如果函数不需要提供返回值,可定义函数类型为空如果函数不需要提供返回值,可定义函数类型为空如果函数不需要提供返回值,可定义函数类型为空类型。类型。类型。类型。空类型空类型的标识符为的标识符为的标识符为的标识符为voidvoidvoidvoid,例如:,例如:,例如:,例如:void starvoid starvoid starvoid star()()()()printf(“*n”);printf(“*n”);printf(“*n”);printf(“*n”);1111C语言程序设计教程2022/11/512C语言程序设计教程第6章 函数与编译预处理(3 3 3 3)参数列表)参数列表)参数列表)参数列表 函数名后的()内是参数列表,由一个或多个函数名后的()内是参数列表,由一个或多个函数名后的()内是参数列表,由一个或多个函数名后的()内是参数列表,由一个或多个类型标识类型标识类型标识类型标识符符符符 变量名变量名变量名变量名组成。参数列表中的变量称为组成。参数列表中的变量称为组成。参数列表中的变量称为组成。参数列表中的变量称为形式参数形式参数形式参数形式参数,简称形,简称形,简称形,简称形参。如参。如参。如参。如int max(int xint max(int xint max(int xint max(int x,int yint yint yint y)根据函数是否需要参数,可将函数分为根据函数是否需要参数,可将函数分为根据函数是否需要参数,可将函数分为根据函数是否需要参数,可将函数分为无参函数无参函数无参函数无参函数和和和和有参有参有参有参函数函数函数函数两种。(注意:无参函数的函数名后的两种。(注意:无参函数的函数名后的两种。(注意:无参函数的函数名后的两种。(注意:无参函数的函数名后的()()()()也不能省也不能省也不能省也不能省!)!)!)!)例如:打印一排例如:打印一排例如:打印一排例如:打印一排*的函数的函数的函数的函数 void star()void star()/*/*函数无形式参数,无返回值函数无形式参数,无返回值函数无形式参数,无返回值函数无形式参数,无返回值*/printf(“n*n”);printf(“n*n”);2.2.2.2.函数体函数体函数体函数体 内内内内的的的的部部部部分分分分是是是是函函函函数数数数体体体体,包包包包含含含含局局局局部部部部变变变变量量量量定定定定义义义义部部部部分分分分和和和和执执执执行语句序列。行语句序列。行语句序列。行语句序列。1212C语言程序设计教程2022/11/513C语言程序设计教程第6章 函数与编译预处理 说明:说明:函数定义不允许嵌套函数定义不允许嵌套。在语言中,所有函数(包括主函数在语言中,所有函数(包括主函数main()main())都是平级的。一个函数的定义,可以放)都是平级的。一个函数的定义,可以放在程序中的任意位置,主函数在程序中的任意位置,主函数main()main()之前或之之前或之后。后。但在任意一个函数(包括主函数)的函数体内但在任意一个函数(包括主函数)的函数体内(即即 内),不能再定义另一个函数,即函数不内),不能再定义另一个函数,即函数不能嵌套定义。能嵌套定义。1313C语言程序设计教程2022/11/514C语言程序设计教程第6章 函数与编译预处理函数定义举例函数定义举例1.编写求编写求x的的n次方的函数,要求返回计算结果。次方的函数,要求返回计算结果。intpower(intx,intn)intj;inty=1;for(j=1;j=n;j+)y=y*x;returny;main()intm,n;m=power(2,3);n=power(3,2);1414C语言程序设计教程2022/11/515C语言程序设计教程第6章 函数与编译预处理2.2.求求求求200,1000200,1000的双胞胎数的对数。双胞胎数:两素数差为的双胞胎数的对数。双胞胎数:两素数差为的双胞胎数的对数。双胞胎数:两素数差为的双胞胎数的对数。双胞胎数:两素数差为2 2称称称称为双胞胎数。下面是我们用现在所学的知识编的程序。为双胞胎数。下面是我们用现在所学的知识编的程序。为双胞胎数。下面是我们用现在所学的知识编的程序。为双胞胎数。下面是我们用现在所学的知识编的程序。main()inta,b,n=0,I;for(a=200;a=998;a+)for(I=2;Ia;I+)if(a%I=0)break;if(a=i)b=a+2;for(I=2;Ib;I+)if(b%I=0)break;if(b=i)n+;printf(“n%d”,n);我们注意到,程序中我们注意到,程序中用用筐住的部分是筐住的部分是完成了相同的功能,完成了相同的功能,即判断一个数即判断一个数(a或或b)是否是素数。是否是素数。我们可以考虑用一个我们可以考虑用一个独立的函数来完成判独立的函数来完成判断素数的功能,在主断素数的功能,在主函数中调用此函数即函数中调用此函数即可。如下:可。如下:1515C语言程序设计教程2022/11/516C语言程序设计教程第6章 函数与编译预处理main()inta,b,n=0;intf(intx);for(a=200;a=998;a+)if(f(a)=1)b=a+2;if(f(b)=1)n+;printf(“n%d”,n);intf(intx)intI;for(I=2;Ix;I+)if(x%I=0)break;if(x=I)return1;elsereturn0;下面我们详细介绍函数调用的格式和语法规定。下面我们详细介绍函数调用的格式和语法规定。1616C语言程序设计教程2022/11/517C语言程序设计教程第6章 函数与编译预处理1 1、函数调用的一般形式:函数调用的一般形式:调用有参函数调用有参函数:函数名(实参列表);:函数名(实参列表);调用无参函数调用无参函数:函数名(:函数名(););如如果果实实参参表表列列包包括括多多个个实实参参,则则实实参参间间用用逗逗号号隔隔开开(注注意意:实实参参与与形形参参的的个个数数必必须须相相等等,类类型型应应一一致致或或赋赋值值兼兼容容),实参与形参是按照对应位置一一传递数据的。如:实参与形参是按照对应位置一一传递数据的。如:三、函数的调用三、函数的调用intpower(intx,intn)intj;inty=1;for(j=1;jb)?a:b;y=(ab)?a:b;returny;returny;调用时调用时:m=max(3,6);m=max(a,b);括号里是形式参数括号里是形式参数括号里是形式参数括号里是形式参数返回值返回值返回值返回值括号里是实参括号里是实参括号里是实参括号里是实参在这一句调用时,在这一句调用时,在这一句调用时,在这一句调用时,形参的值是形参的值是形参的值是形参的值是3 3和和和和6 6其返回值其返回值其返回值其返回值y y将被赋给将被赋给将被赋给将被赋给调用语句中的调用语句中的调用语句中的调用语句中的mm1818C语言程序设计教程2022/11/519C语言程序设计教程第6章 函数与编译预处理2 2、函数调用的方式函数调用的方式(1)(1)函数语句调用:函数语句调用:printf(“%d”,3);printf(“%d”,3);(2)(2)函数表达式函数表达式 y=power(2,3)y=power(2,3)1;1;(3)(3)函数参数函数参数 函数调用作为一个函数的实参如:函数调用作为一个函数的实参如:maxval=max(power(2,3),power(3,2);maxval=max(power(2,3),power(3,2);3 3、对被调用函数的声明和函数原型对被调用函数的声明和函数原型在一个函数中调用另一函数需要具备的条件:在一个函数中调用另一函数需要具备的条件:a.a.调用的函数必须是已经存在的函数(是库函数或自己调用的函数必须是已经存在的函数(是库函数或自己定义的函数)定义的函数)1919C语言程序设计教程2022/11/520C语言程序设计教程第6章 函数与编译预处理 b.b.对被调用函数进行如下说明:对被调用函数进行如下说明:如如果果是是自自己己定定义义的的函函数数(下下面面标标号号为为的的情情况况除除外外)则则应应在在主主调调函函数数中中进进行行声声明明,其其声声明明的的一一般般形形式式为为:函数的首部;函数的首部;/*/*;分号一定不可少;分号一定不可少*/如:如:intpower(intx,intn);在在C C语言中,以上的语言中,以上的函数声明函数声明称为称为函数原型函数原型。下面几种情况,函数声明可以省略:下面几种情况,函数声明可以省略:a.a.被被调调函函数数的的定定义义在在主主调调函函数数之之前前,即即先先定定义义后后使使用。用。b.b.当函数的类型为当函数的类型为intint型、型、charchar型或型或voidvoid型时。型时。2020C语言程序设计教程2022/11/521C语言程序设计教程第6章 函数与编译预处理例如例如例如例如:计算计算计算计算1!+2!+3!+10!1!+2!+3!+10!的值的值的值的值voidmain()voidmain()longmm(intn);longmm(intn);inti;inti;longs=0;longs=0;printf(“n%ld”,s);printf(“n%ld”,s);longmm(intn)/*求求n!*/longt=1;inti;for(i=1;i=n;i+)t*=i;returnt;函数调用举例函数调用举例for(i=1;i=10;i+)s+=mm(i);2121C语言程序设计教程2022/11/522C语言程序设计教程第6章 函数与编译预处理4.函数的嵌套调用函数的嵌套调用C语语言言不不允允许许嵌嵌套套定定义义函函数数,但但可可以以嵌嵌套套调调用用函函数数,也也就就是说,在执行被调用函数时,被调用函数又调用了其它函数。是说,在执行被调用函数时,被调用函数又调用了其它函数。main()f1();f1()f2();f2()2222C语言程序设计教程2022/11/523C语言程序设计教程第6章 函数与编译预处理例如例如例如例如:计算计算计算计算1!+2!+3!+10!1!+2!+3!+10!的值的值的值的值voidmain()voidmain()longsum();longsum();printf(“n%ld”,sum();printf(“n%ld”,sum();longmm(intn)/*求求n!*/longt=1;inti;for(i=1;i=n;i+)t*=i;returnt;函数嵌套调用举例函数嵌套调用举例longsum()/*求求n!之和!之和*/longmm(intn);intI;longs=0;for(i=1;iy)z=x;if(xy)z=x;elsez=y;elsez=y;returnz;returnz;main()main()Inta,b,m;Inta,b,m;scanf(“%d%d”,&a,&b);scanf(“%d%d”,&a,&b);m=m=max(a,b)max(a,b);printf(“%d,%d”,a,b);printf(“%d,%d”,a,b);2525C语言程序设计教程2022/11/526C语言程序设计教程第6章 函数与编译预处理6.3函数的递归调用函数的递归调用一、递归的定义一、递归的定义函数调用它本身,称为函数调用它本身,称为递归递归。直接在函数内调用自己为。直接在函数内调用自己为直接递归直接递归,通过别的函数调用自己为,通过别的函数调用自己为间接递归间接递归。voida().a();.voida().b();.voidb().a();.注意:注意:为了防止递归调用无终止地为了防止递归调用无终止地进行,在函数体内必须有使递归调进行,在函数体内必须有使递归调用终止的条件。用终止的条件。常用的办法是常用的办法是:加条件判断,满足加条件判断,满足某种条件后就不再作递归调用,然某种条件后就不再作递归调用,然后逐层返回。后逐层返回。2626C语言程序设计教程2022/11/527C语言程序设计教程第6章 函数与编译预处理 例例6_56_5:有:有5 5个人坐在一起,问第个人坐在一起,问第5 5个人多少岁?他说个人多少岁?他说比第比第4 4个人大个人大2 2岁。问第岁。问第4 4个人岁数,他说比第个人岁数,他说比第3 3个人大个人大2 2岁。问岁。问第第3 3个人,又说比第个人,又说比第2 2个人大个人大2 2岁。问第岁。问第2 2个人,说比第个人,说比第1 1个人大个人大2 2岁。最后问第岁。最后问第1 1个人,他说是个人,他说是1010岁。请问第岁。请问第5 5个人多大?个人多大?显然,根据题意我们可以得出以下等式:显然,根据题意我们可以得出以下等式:age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10 二、简单的递归程序举例二、简单的递归程序举例 可可以以看看到到,当当nlnl时时,求求第第n n个个人人的的年年龄龄的的公公式式是是相相同同的,因此可以用一个函数表示上述关系。的,因此可以用一个函数表示上述关系。age(1)=l0 (递归调用结束条件)递归调用结束条件)age(n)=age(n-1)十十2(n1)(递归操作)递归操作)2727C语言程序设计教程2022/11/528C语言程序设计教程第6章 函数与编译预处理根据上述分析,可得求第根据上述分析,可得求第n n个人的年龄的程序如下:个人的年龄的程序如下:intage(intn)/*求第求第n个人年龄的函数个人年龄的函数*/intc;if(n=1)c=10;elsec=age(n-1)+2;return(c);main()printf(%d,age(5);2828C语言程序设计教程2022/11/529C语言程序设计教程第6章 函数与编译预处理下图表示求第下图表示求第下图表示求第下图表示求第5 5 5 5个人年龄的递归调用过程。个人年龄的递归调用过程。个人年龄的递归调用过程。个人年龄的递归调用过程。2929C语言程序设计教程2022/11/530C语言程序设计教程第6章 函数与编译预处理例例例例6_66_6递归方法求递归方法求递归方法求递归方法求n!n!由于由于n!=n*(n-1)!是递归定义,所以也可以用函数递是递归定义,所以也可以用函数递归调用来实现。归调用来实现。若要求若要求n!只要求出只要求出(n-1)!)!即可即可(n-1)!(n-2)!)!(n2)!(n-3)!)!1!而已知而已知0!=1,1!=1。再反过来就可以依次求出再反过来就可以依次求出2!直到最后求出直到最后求出n!。!。3030C语言程序设计教程2022/11/531C语言程序设计教程第6章 函数与编译预处理#include“stdlib.h”longf(intn)longy;if(nC,AB,CB,AC,BA,BC,AC 共经历7步,由此可以推出:移动n个盘子要经历2n 1步。步。3636C语言程序设计教程2022/11/537C语言程序设计教程第6章 函数与编译预处理1 1、将、将A A上上n-1n-1个盘借助个盘借助C C座先移到座先移到B B座上。座上。2 2、把、把A A座上剩下的一个盘移到座上剩下的一个盘移到C C座上。座上。3、将将n-1个盘从个盘从B座借助于座借助于A座移到座移到C座上。座上。将将n n个盘子从个盘子从A A座移到座移到C C座可以分解为以下座可以分解为以下3 3个步骤:个步骤:3737C语言程序设计教程2022/11/538C语言程序设计教程第6章 函数与编译预处理递归方法解汉诺塔递归方法解汉诺塔voidhanoi(intn,charA,charB,charC)if(n=1)printf(“n“n%c-%c”,A,C);elsehanoi(n-1,A,C,B);printf(“n“n%c-%c”,A,C);hanoi(n-1,B,A,C);n=1时时,直接将盘子直接将盘子从从A座移动到座移动到C座座将将n-1个盘子从个盘子从A座经座经过过C座移动到座移动到B座座将第将第n个盘子个盘子从从A座移动到座移动到C座座再将再将n-1个盘子从个盘子从B座经过座经过A座移动到座移动到C座座main()intn;printf(“n“ninputn:”);scanf(“%d”,&n);hanoi(n,A,B,C);将将n个盘子从个盘子从A座经座经过过B座移动到座移动到C座座3838C语言程序设计教程2022/11/539C语言程序设计教程第6章 函数与编译预处理1.1.局部变量局部变量 在在一一个个函函数数内内部部定定义义的的变变量量是是内内部部变变量量,它它只只在在本本函函数数范范围围内内有有效效,也也就就是是说说只只有有在在本本函函数数内内才才能能使使用用它它们们,在在此此函函数数以以外外是是不不能能使使用用这这些些变变量量的的。这这样样的的变变量量我们称之为我们称之为局部变量。局部变量。6.6.4 4 变量的作用域与存储方式变量的作用域与存储方式 一一.变量的作用域变量的作用域:即变量的有效范围即变量的有效范围 变量按作用域分为变量按作用域分为局部变量局部变量和和全局变量全局变量3939C语言程序设计教程2022/11/540C语言程序设计教程第6章 函数与编译预处理intf1(intx)inta,b;main()intm,n;m=f1();a,b,x的有效范围的有效范围m,n的有效范围的有效范围4040C语言程序设计教程2022/11/541C语言程序设计教程第6章 函数与编译预处理 (1)(1)主函数主函数mainmain中定义的变量中定义的变量(m,n)m,n)也只在主函数中有效也只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效而不因为在主函数中定义而在整个文件或程序中有效,主函主函数也不能使用其他函数中定义的变量。数也不能使用其他函数中定义的变量。(2)(2)不同函数中可以定义相同名字的变量不同函数中可以定义相同名字的变量,它们代表不同它们代表不同的对象的对象,在内存中占不同的单元在内存中占不同的单元,互不混淆互不混淆,互不干扰。互不干扰。(3)(3)形式参数也是局部变量形式参数也是局部变量,只在本函数中有效只在本函数中有效,其他函数其他函数不能使用。不能使用。(4)4)在函数体内的复合语句中也可以定义局部变量,它们在函数体内的复合语句中也可以定义局部变量,它们的作用范围只在复合语句内。的作用范围只在复合语句内。2 2、局部变量的说明、局部变量的说明4141C语言程序设计教程2022/11/542C语言程序设计教程第6章 函数与编译预处理main()intm,n;.intc;c=m*n;m m、n n在此范围内有效在此范围内有效 .c c在此范围内有效在此范围内有效 .4242C语言程序设计教程2022/11/543C语言程序设计教程第6章 函数与编译预处理 在在函函数数之之外外定定义义的的变变量量叫叫作作全全局局变变量量,其其有有效效范范围围为为从定义变量的位置开始到本源文件结束。如:从定义变量的位置开始到本源文件结束。如:3 3.全局变量全局变量intp=1,q=5;floatf1(inta)charc1,c2;charf2(intx,chary)main()全局变量全局变量p、q的作用范围的作用范围全局变量全局变量c1、c2的作用范围的作用范围4343C语言程序设计教程2022/11/544C语言程序设计教程第6章 函数与编译预处理(1)在在一一个个函函数数中中既既可可以以使使用用本本函函数数中中的的局局部部变变量量,又可以使用有效的全局变量。又可以使用有效的全局变量。(2)(2)如果在同一个文件中,外部变量与局部变量同名,如果在同一个文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被则在局部变量的作用范围内,外部变量被“屏蔽屏蔽”,即,即它不起作用。它不起作用。注:注:建议不在必要时不要使用全局变量,因为全局变量建议不在必要时不要使用全局变量,因为全局变量过多,会降低程序的清晰性,往往难以清楚地判断出每过多,会降低程序的清晰性,往往难以清楚地判断出每个瞬时各个外部变量的值。个瞬时各个外部变量的值。4 4.全局变量的说明全局变量的说明4444C语言程序设计教程2022/11/545C语言程序设计教程第6章 函数与编译预处理#include include include include int a,b;/*aint a,b;/*aint a,b;/*aint a,b;/*a,b b b b为全局变量为全局变量为全局变量为全局变量*/*/*/*/void f1(int x void f1(int x void f1(int x void f1(int x,int y)int y)int y)int y)int a,b;/*int a,b;/*int a,b;/*int a,b;/*此此此此a,ba,ba,ba,b是局部变量是局部变量是局部变量是局部变量*/*/*/*/a=x*y;a=x*y;a=x*y;a=x*y;b=10 b=10 b=10 b=10;printf(“f1:a=%d,b=%dn”,a,b);printf(“f1:a=%d,b=%dn”,a,b);printf(“f1:a=%d,b=%dn”,a,b);printf(“f1:a=%d,b=%dn”,a,b);main()main()main()main()a=2;b=4;/*a=2;b=4;/*a=2;b=4;/*a=2;b=4;/*此此此此a,ba,ba,ba,b是全局变量,赋值是全局变量,赋值是全局变量,赋值是全局变量,赋值*/*/*/*/f1(af1(af1(af1(a,b);/*b);/*b);/*b);/*调用函数调用函数调用函数调用函数f1()*/f1()*/f1()*/f1()*/printf(“main:a=%d,b=%d”,a,b);printf(“main:a=%d,b=%d”,a,b);printf(“main:a=%d,b=%d”,a,b);printf(“main:a=%d,b=%d”,a,b);程序输出结果为程序输出结果为程序输出结果为程序输出结果为:f1:a=8,b=10f1:a=8,b=10main:a=2,b=10main:a=2,b=10全局变量全局变量a,b的作用范围的作用范围局部变量局部变量a,b的作用范围的作用范围4545C语言程序设计教程2022/11/546C语言程序设计教程第6章 函数与编译预处理二二.变量的存储特性变量的存储特性 静态存储静态存储类型的变量的类型的变量的生存期为程序运行的整个过程生存期为程序运行的整个过程,在该过程中它们一直占有固定的存储空间,通常称它们为在该过程中它们一直占有固定的存储空间,通常称它们为永久永久存储存储的变量。如:的变量。如:全局变量、静态的局部变量全局变量、静态的局部变量;动态存储动态存储类型变量类型变量只存在某一段时间内只存在某一段时间内。例如,。例如,函数的函数的形参和函数体内定义的局部变量形参和函数体内定义的局部变量,它们只有当程序调用该函它们只有当程序调用该函数时才能得到存储空间,当该函数执行完后,数时才能得到存储空间,当该函数执行完后,变量的存储空变量的存储空间又被撤销了。间又被撤销了。1.1.1.1.变量按存在时间可分为变量按存在时间可分为变量按存在时间可分为变量按存在时间可分为 静态存储类型的变量静态存储类型的变量静态存储类型的变量静态存储类型的变量 动态存储类型的变量动态存储类型的变量动态存储类型的变量动态存储类型的变量4646C语言程序设计教程2022/11/547C语言程序设计教程第6章 函数与编译预处理 存存存存储储储储特特特特性性性性是是是是指指指指数数数数据据据据在在在在内内内内存存存存中中中中存存存存储储储储的的的的方方方方式式式式,存存存存储储储储方方方方式式式式分分分分为为为为静静静静态态态态存存存存储储储储类类类类和和和和动动动动态态态态存存存存储储储储类类类类,具具具具体体体体包包包包含含含含四四四四种种种种:autoautoautoauto(自自自自动动动动型型型型)、staticstaticstaticstatic(静静静静态态态态型型型型)、externexternexternextern(外外外外部部部部型型型型)、registerregisterregisterregister(寄寄寄寄存存存存器型)器型)