C语言函数的嵌套调用和递归调用.pptx
5.4.2 函数的递归调用(函数的递归调用(嵌套调用的特例)概念:函数直接或间接地自我调用称为递归函数。int fun1(int x)z=fun1(y);int fun1(int x)int fun2(int t)z=fun2(y);c=fun1(a);直接引用自身间接引用自身递归在没有控制条件的情况下是无穷的递归。#includevoid main(void)printf(*n);main();只有通过控制条件,使递归调用终止,才能应用。#includevoid main(void)char ch;printf(*n);ch=getchar();if(ch!=9)main();第1页/共21页递归举例:求递归举例:求 n!n!=1 n=0或n=1n(n-1)!n1f(n)=1 n=0或n=1nf(n-1)n1#include long lfac(long);void main(void)long i,x;scanf(%ld,&i);x=lfac(i);printf(n%ld,x);long lfac(long n)if(n=0|n=1)return 1;else return(n*lfac(n-1);lfac(4)4*lfac(3)3*lfac(2)2*flac(1)2*13*2*14*3*2*1递推回归=n(n-1)(n-2)321=n(n-1)!第2页/共21页 变量的作用域和存储类型变量的作用域和存储类型变量生存期:变量占用内存单元(活着)的时间。内存中供用户使用的存储空间:程序区:存放程序代码。数据区:存放数据,分为动态存储区和静态存储区。变量的生存期和作用域 C语言中,定义变量应包含三个内容:数据类型:变量占用内存空间的大小。如:int,float,char。作用域:变量在程序中的有效区域。存储类型:变量在内存中的存储方式。存储方式不同,变量占用内存时间不同。静态存储区:静态存储区:定义变量定义变量(程序编译程序编译)时就分配内存单元,时就分配内存单元,直到程序结束。生存期为整个程序运行期。直到程序结束。生存期为整个程序运行期。动态存储区:使用时才分配内存单元,使用完毕,立即释放。生存期为函数调用期。第3页/共21页变量的作用域:变量在程序中的可使用范围(有效性)。1.局部变量 定义在函数内部的变量。也称为内部变量。放在动态区中,只有调用它的函数才能使用它。调用时才分配内存单元,调用结束,内存即刻被释放,作用域:仅限于函数内部或复合语句内。生存期:函数调用期间。作用域可以是一个函数或一个复合语句,取决于定义变量的位置,可分为局部变量和全局变量。注意:不同的函数或复合语句中可以使用相同的变量名。因为它们作用域不同,所以它们互不干预。即:同名,不同作用域的变量是不同的变量。第4页/共21页例:(见p137 例)#include void func();main()int y=10;printf(“1:y=%dn”,y);func();printf(“2:y=%dn”,y);void func()int x=5;int x=3;int x=1;printf(“x=%dn”,x);printf(“x=%dn”,x);printf(“x=%dn”,x);运行结果:1:y=10 x=1 x=3 x=52:y=10第5页/共21页2.全局变量全局变量 定义在函数之外的变量。也称为外部变量。放在静态区中。作用域:从定义直到文件结束。生存期:在程序的整个执行过程中。#include void add(void);int a,b,c;void main(void)scanf(“%d,%d”,&a,&b);add();printf(“%d”,c);void add(void)c=a+b;外部变量作用域注意:1.任何函数对外部变量的修改都会影响其他函数对它的引用。2.当函数中出现和全局变量同名的局部变量时,局部变量优先。第6页/共21页 变量的存储类型变量的存储类型 变量的存储类型有四种:自动类型 auto 寄存器类型 register 静态类型 static 外部类型 extern完整的变量说明格式:存储类型 数据类型 变量名表;确定变量在内存中的表示方法。确定变量的生存期和作用域。该项省略表示auto存储类型。变量的作用域不同,本质上是变量的存储类型不同:静态存储:程序编译时就分配内存单元,直到程序结束。动态存储:使用时才分配内存单元,使用完毕,立即释放。动态存储方式 静态存储方式 第7页/共21页1、自动类型自动类型 auto(C 默认的存储方式)定义在复合语句的开始处。块内生存块内有效。#include void main(void)auto int a,b;scanf(“%d,%d”,&a,&b);if(ba)int T;T=a;a=b;b=T;printf(“Max=%d”,a);ab的作用域T的作用域生存期:执行到复合语句时建立内存变量。执行出复合语句后变量消亡。T2、寄存器类型 register 作用域和生存期与auto相同,差别:如果CPU内部寄存器空闲,则使用寄存器作为变量的存储单元,以提高速度。主要用于循环变量。(见p140 例5.16)第8页/共21页3、静态类型静态类型 static(局部全局)(局部全局)作用域:在定义的复合语句内引用,出了复合语句不可见。生存期:从定义直到程序结束。执行出 时,原值并不消失,下次调用时变量中仍保留上次调用结束时的值。void row(void);void main(void)int b;for(b=1;b=9;b+)row();void row(void)int a=1;int b;for(b=1;b=9;b+)printf(%3d,a*b);printf(n);a+;static说明a为静态局部变量生存期从第一次调用到程序结束。a的作用域 静态局部变量特点:1.系统自动为静态局部变量赋初值 0。2.作用域与局部变量相同。3.生存期与局部变量不同。第9页/共21页 静态全局变量静态全局变量全局变量和静态全局变量都是静态存储方式,区别:全局变量的作用域为整个源程序,静态全局变量的作用域为定义该变量的源文件;1.若一个程序由多个“.c”文件组成,全局变量在各个源文件中都有效,静态全局变量则仅在定义它的源文件中有效。全局变量前加上存储类型说明static,即构成静态全局变量。static a=3;void main(void)注意static位置:静态局部变量改变了局部变量的存储方式(生存期),使其生存期与作用域不同。静态全局变量改变了全局变量的作用域,限制了全局变量的使用范围。第10页/共21页4、外部类型外部类型(全局变量全局变量)extern文件 文件 int xx ;extern int xx;void main()fun()文件1定义的外部变量b1通过说明使用a1的外部变量如果只希望在本文件中使用,可以加static说明。static 定义在所有函数(任何花括号)之外的全局变量。外部和全局是从不同角度对同一类变量的提法,外部是从生存期(时间)角度提出的;全局是从作用域(空间)角度提出的。主要用于在多个文件间传递数据。特点:1.系统自动为外部变量赋初值0。2.作用域从定义开始直到文件结束。3.外部变量可被不同的文件共享。格式:extern 数据类型 变量名;第11页/共21页外部变量的副作用外部变量的副作用#include int i;void prt(void);void main(void)for(i=0;i5;i+)prt();void prt(void)for(i=0;i5;i+)printf(“%c”,$);printf(“n”);函数的作用:打印五个$。i=0i=0i=0i=0i=0i=1i=2i=3i=4i=5i=5i=5i=5i=5?模块设计的原则:内聚性强,耦合性弱。外部变量的使用占用内存且增加模块的耦合性,使函数的通用性降低,使程序的模块化、结构化变差因此,应尽量不使用外部变量。几次调用函数?外部变量应用见p143 例 第12页/共21页综合举例:#includeint i=1;void other(void);void main()static int a;int b=-10,c=0;printf(“i=%d,a=%d,b=%d,c=%dn”,i,a,b,c);c=c+8;other();printf(“i=%d,a=%d,b=%d,c=%dn”,i,a,b,c);i=i+10;other();void other()static int a=2;static int b;int c=10;a=a+2;i=i+32;c=c+5;printf(“i=%d,a=%d,b=%d,c=%dn”,i,a,b,c);b=a;运行结果:i=1,a=0,b=-10,c=0i=33,a=4,b=0,c=15i=33,a=0,b=-10,c=8i=75,a=6,b=4,c=15 课堂作业:编写函数求二维方阵的主对角线上的最大值及其位置。要求:在主函数中输入a33,通过该函数求a33主对角线的最大元素和位置。第13页/共21页5.6 编译预处理编译预处理 C语言除了说明语句、执行语句及控制语句外,还有一类以#号开头的编译预处理语句。如:#include、#define。该类语句的作用是在编译前对程序作一些处理,满足特定的处理要求。编译预处理是C的重要特征,它优化了C程序设计环境。编译预处理不用;作为结束标志!以区别其他C语句。5.7.1 宏定义1、不带参数的宏定义作用:定义常量名为一字符串。提高程序的可读性,便于修改。格式:#define 宏名 字符串void main(void)flaot r;scanf(“%f”,&r)printf(“%fn”,PI*r*r);编译时用字符串替代宏名(宏代换)第14页/共21页说明:宏名一般用大写(区别变量);预处理程序用字符串无条件替代宏名,编译时检查语法。;PI*r*r;*r*r 宏名的定义域:从定义到程序结束。可以通过#undef修改定义范围。void main(void)#undef GG的范围 宏定义允许嵌套(在字符串中使用已定义的宏名)。宏定义可定义运算符、表达式和提示信息(见P146 例5.20)。#define R#define PI#define S PI*R*Rprintf(“S=%f”,S);不替换第15页/共21页2、带参数的宏定义带参数的宏定义格式:#define 宏名(形参表)含参数的字符串#define S(a,b)a*barea=S(4,3);替换过程:用实参替换宏定义的形参。替换字符串中的参数。替换整个宏。4*3带参的宏与函数的区别:带参宏不分配内存单元,没有值的传递,不返回值,只是在预处理时按规则进行字符串代换。注意:要严格按格式书写,否则会造成错误。#define S (a,b)a*b 则:S(3,4)被替换成:(a,b)a*b(3,4)实参有可能是表达式时,定义形参字符串要加()。#define S(r)PI*r*r则:S(a+b)替换为:PI*a+b*a+b#define S(r)PI*(r)*(r)S(a+b)替换为:PI*(a+b)*(a+b)第16页/共21页5.6.2 文件包含文件包含格式1:#include 格式2:#include “被包含的文件名”表示编译系统定义路径;“”表示用户当前路径。作用:将指定的文件内容和当前源文件一起编译,联成一个源文件。一个#include 只能包含一个文件。文件包含可以嵌套。一般将宏定义及函数的声明放在包含文件中。被包含的文件一般扩展名为.h,称为头文件。#include AB Bfile2.cBA预处理编译预处理前编译预处理后被包含文件file1.cfile1.c 第17页/共21页例:求半径为例:求半径为r的园面积、园周长。的园面积、园周长。#include “my.h”void main(void)float r,fArea,fLen;scanf(“%f”,&r);fArea=S(r);fLen=L(r);printf(“Area=%f,Len=%f”,fArea,fLen);float S(float r)return PI*r*r;float L(float r)return 2*PI*r;#include float S(float);float L(float);如果找不到“”文件,程序将会出现什么问题?第18页/共21页课堂练习#include“init.txt”void main()int a=1,b=2,c=3,d=4,k;k=HDY(a+c,b+d);PRINT(k);init.txt 的文件内容如下:的文件内容如下:#define HDY(A,B)A/B#define PRINT(Y)printf(“y=%dn”,Y);写出程序的运行结果:第19页/共21页 思考题:作业题:p151 细读典型例题精解 p157 习题5 一、选择题 1420。二、填空题 37。三、程序运行题 46。四、完善程序题 3。五、程序设计题 6。编译预处理命令不属于C语言的语句部分,它在C程序中起什么作用?第20页/共21页感谢您的观看!第21页/共21页