《C++函数、递推、递归.ppt》由会员分享,可在线阅读,更多相关《C++函数、递推、递归.ppt(77页珍藏版)》请在三一办公上搜索。
1、C+语言程序设计,第九讲函数、递推、递归,大连理工大学 盘锦校区基础教学部,2,第九讲函数、递推、递归递推递推是计算机数值计算中的一个重要算法。,思路:通过数学推导,将复杂的运算化解为若干重复的简单运算,以充分发挥计算机长于重复运算的特点;递推法特点:从一个已知的事实出发,按一定规律推 出下一个事实,再从这个新的已知事实出发,再向下 推出一个新的事实。,大连理工大学 盘锦校区基础教学部,3,第九讲函数、递推、递归,递推举例(1),例:(猴子吃桃问题)猴子第1天摘下若干桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一 半
2、另加一个。到第10天早上想再吃时,就只剩下一个 桃子了。问第1天猴子共摘了多少桃子?,大连理工大学 盘锦校区基础教学部,4,第九讲函数、递推、递归,解题思路:,假设用 S(i)表示第 i天没吃之前的桃子数目;则S(1)即为第 1天所摘的桃子数;,S(10)=S(9)*1/2 1第10 天没吃之前的桃子数,大连理工大学 盘锦校区基础教学部,5,第九讲函数、递推、递归,一般形式:S(i)=S(i-1)*1/2 1,i=2,3,10;这个公式可用于知第 1 天没吃之前的桃子数推算第 2 天 没吃之前的,再推算第 3天没吃之前的,.。现在要求的是 第 1 天没吃之前的。能否倒过来,先知 第 10 天没
3、吃之前的 的再反推第 9天没吃之的,直到第 1 天没吃之前的。为 此将上式改写为:S(i-1)=2*(S(i)+1),i=10,9,8,2,第九讲函数、递推、递归,程序:,大连理工大学 盘锦校区基础教学部 6,大连理工大学 盘锦校区基础教学部,7,第九讲函数、递推、递归分析:一般形式:S(i-1)=2*(S(i)+1),i=10,9,8,2;初始:s2=1;/S(10)=1,i=9,s1=2*(s2+1);s2=s1;s1=2*(s2+1);s2=s1;s1=2*(s2+1);s2=s1;,/S(9)=2*(S(10)+1)/s2=s1=S(9)/S(8)=2*(S(9)+1)/s2=s1=S
4、(8)/S(7)=2*(S(8)+1)/s2=s1=S(7),i=8,i=7,i=6,s1=2*(s2+1);s2=s1;,/S(6)=2*(S(7)+1)/s2=s1=S(6),大连理工大学 盘锦校区基础教学部,8,第九讲函数、递推、递归,i=5,s1=2*(s2+1);s2=s1;,/S(5)=2*(S(6)+1)/s2=s1=S(5)/S(4)=2*(S(5)+1)/s2=s1=S(4)/S(3)=2*(S(4)+1)/s2=s1=S(3)/S(2)=2*(S(3)+1)/s2=s1=S(2)/S(1)=2*(S(2)+1)/s2=s1=S(1),i=4,s1=2*(s2+1);s2=s
5、1;s1=2*(s2+1);s2=s1;s1=2*(s2+1);s2=s1;s1=2*(s2+1);s2=s1;,i=3,i=2,i=1,大连理工大学 盘锦校区基础教学部,9,第九讲函数、递推、递归,递推举例(2),递推数列 一个数列从某一项起,它的任何一项都可以用它前面的若干项 来确定,这样的数列称为递推数列,表示某项与其前面的若干 项的关系就称为递推公式。例如自然数 1,2,,n 的阶乘就可 以形成如下数列:1!,2!,3!,,(n-1)!,n!另fact(n)为 n 阶乘,依据后项与前项的关系可以写出递推公式:fact(n)=n*fact(n-1)(通项公式)fact(1)=1(边界条件
6、),大连理工大学 盘锦校区基础教学部,10,第九讲函数、递推、递归,递推算例(3),递推算法程序实现:有了通项公式和边界条件后,采用循环结构,从边界条件出 发,利用通项公式通过若干步递推过程就可以求出结果;例:王小二自称刀工不错,有人放一张大的煎饼在砧板上,问他:“饼不许离开砧板,切 100 刀最多能分成多少块?”,大连理工大学 盘锦校区基础教学部,11,第九讲函数、递推、递归,分析:,切一刀,切二刀,切三刀切四刀,令 q(n)表示切 n刀能分成的块数,由上图可知q(1)=1+1=2q(2)=1+1+2=4q(3)=1+1+2+3=7q(4)=1+1+2+3+4=11,大连理工大学 盘锦校区基
7、础教学部,12,第九讲函数、递推、递归,分析:,切一刀,切二刀,切三刀切四刀,在切法上是让每两条线都有交点。用归纳法可得出q(n)=q(n-1)+nq(0)=1(边界条件),大连理工大学 盘锦校区基础教学部,13,第九讲函数、递推、递归,递推算例(3,),参考程序:,大连理工大学 盘锦校区基础教学部,14,第九讲函数、递推、递归递归递归算法在可计算理论中占有重要地位,它是算法设计的有力工具,对于拓展编程思路非常有用。就递归算法而言不涉及高深数学知识,只不过初学者建立起递 归概念不太容易。看一个简单的例子:,大连理工大学 盘锦校区基础教学部,15,第九讲函数、递推、递归递归有5 个人坐在一起,问
8、第 5 个人多少岁?他说比第 4个人大两岁。问第4 个人岁数,他说比第 3 个人大两岁。问第 3个人,又说比第 2个人大两岁。问第 2个人,说比第 1个人大两岁。最后问第 1个人,他说是 10岁。请问第 5 个人多大?解题思路:假设用 age(i)表示第 i个人的岁数,则,借助循环结构采用递推方法求解!,大连理工大学 盘锦校区基础教学部,16,第九讲函数、递推、递归,一般形式:,age(n)=10age(n)=age(n-1)+2,(n=1)(n 2),大连理工大学 盘锦校区基础教学部,17,第九讲函数、递推、递归,分析:上述求解是从求解目标出发,即将第 n 个人的年龄表示第(n-1)个人的年
9、龄,再回溯到第(n-2)个人的年龄 直 到第 1 个人的年龄;(回溯阶段)然后,采用递推方法,从第 1 个人的已知年龄推算第 2 个人的年龄,在推算第 3个人的年龄,直到推算出第 5个人的 年龄;(递推阶段)这是一个递归问题,对它的求解可以分成 回溯 和 递推 两 个阶段;显而易见,如果不希望递归过程无限制的进行下去,必须有一个结束递归过程的条件;如:age(1)=10,大连理工大学 盘锦校区基础教学部,18,第九讲函数、递推、递归,计算年龄函数:int age(int n),int c;if(n=1)c=10;else c=age(n-1)+2;return c;,大连理工大学 盘锦校区基础
10、教学部,19,第九讲函数、递推、递归,递归调用,在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归(recursive)调用;C+允许函数的递归调用;例:int f(int x)int y,z;z=f(y);return 2*z;,大连理工大学 盘锦校区基础教学部,20,第九讲函数、递推、递归,递归调用,直接调用,间接调用,注意:上述两种情况都是无终止的自身调用;显然,程序中不应该出现这种无终止的调用,而只应出现 有限次的,有终止的递归调用;可以用if语句控制,实现递归调用结束;,大连理工大学 盘锦校区基础教学部,21,第九讲函数、递推、递归,递归函数,包含递归调用的函数,
11、称为递归函数;计算年龄函数:int age(int n)int c;,if(n=1)c=10;,else c=age(n-1)+2;return c;,大连理工大学 盘锦校区基础教学部,22,第九讲函数、递推、递归,递归函数,计算年龄递归函数执行过程:,大连理工大学 盘锦校区基础教学部,23,第九讲函数、递推、递归,计算年龄程序,大连理工大学 盘锦校区基础教学部,24,第九讲函数、递推、递归,递归算例(2),用递归方法计算 n!算法思路:若 n=10,则 n!=10*9!定义函数 fact(n)表示计算 n!的函数,则有,大连理工大学 盘锦校区基础教学部,25,第九讲函数、递推、递归,递归算例
12、(2),阶乘计算递归函数:iinntt ffaacctt(iinntt nn)int c;if(cn=n=*0 f|anct=(n=-11);c=1;reelstuern c;,c=n*fact(n-1);return c;,结束递归条件,大连理工大学 盘锦校区基础教学部,26,第九讲函数、递推、递归,递归算例(3),用递归函数计算组合数:C(m,n),即从 m 个数中取 n 个数的组合数;C(m,n)=C(m-1,n)+C(m-1,n-1);C(m,n)=0,m 0,n 0;C(m,n)=1,m=n;C(m,n)=m,n=1;,大连理工大学 盘锦校区基础教学部,27,第九讲函数、递推、递归,
13、递归算例(3),大连理工大学 盘锦校区基础教学部,28,第九讲函数、递推、递归,递归算例(4),例:(猴子吃桃问题)猴子第1天摘下若干桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一 半另加一个。到第10天早上想再吃时,就只剩下一个 桃子了。问第1天猴子共摘了多少桃子?,大连理工大学 盘锦校区基础教学部,29,第九讲函数、递推、递归,解题思路:,假设用 S(i)表示第 i天没吃之前的桃子数目;则S(1)即为第 1天所摘的桃子数;,S(10)=S(9)*1/2 1第10 天没吃之前的桃子数,大连理工大学 盘锦校区基础教学
14、部,30,第九讲函数、递推、递归,一般形式:S(i)=S(i-1)*1/2 1,i=2,3,10;这个公式可用于知第 1 天没吃之前的桃子数推算第 2 天 没吃之前的,再推算第 3天没吃之前的,.。现在要求的是 第 1 天没吃之前的。能否倒过来,先知 第 10 天没吃之前的 的再反推第 9天没吃之的,直到第 1 天没吃之前的。为 此将上式改写为:,大连理工大学 盘锦校区基础教学部,31,第九讲函数、递推、递归,一般形式:,S(i-1)=2*(S(i)+1),i=2,3,4,10,则S(1)即为第 1天所摘的桃子数;S(1)=2*(S(2)+1)S(2)=2*(S(3)+1)S(8)=2*(S(
15、9)+1)S(10)=1,大连理工大学 盘锦校区基础教学部,32,第九讲函数、递推、递归,递归函数:int count(int n),int c;if(n=10)c=1;elsec=2*(count(n+1)+1);return c;,这样可以吗?有没有问题?,如果出现调用语句:count(11)?,大连理工大学 盘锦校区基础教学部,33,第九讲函数、递推、递归,递归函数:int count(int n),int c;if(n 10)return-1;if(n=10)c=1;elsec=2*(count(n+1)+1);return c;,大连理工大学 盘锦校区基础教学部,34,第九讲函数、递
16、推、递归,递归方法,递归实现:在时间和空间上的开销比较大;但符合人们的思路,程序容易理解;递归函数:只须写出递归公式和递归结束条件(即边 界条件),即可很容易写出递归函数;,大连理工大学 盘锦校区基础教学部,35,第九讲函数、递推、递归,局部变量和全局变量,一个程序可以包括若干个源程序文件(文件模块);每个源程序文件又包括若干个函数;在每个函数中和函数外都可以定义变量。这些在不同地方定义的变量是否都在程序的全部范围 内有效?如果不是,他们的有效范围是什么呢?,大连理工大学 盘锦校区基础教学部,36,第九讲函数、递推、递归,局部变量和全局变量,局部变量在一个函数内部定义的变量是内部变量,它只在
17、本函数范围内有效,换句话说只有在本函数内才能使 用它们,在此函数之外是不能使用这些变量的。同样 的,在复合语句中定义的变量只在复合语句内范围内 有效。,大连理工大学 盘锦校区基础教学部,37,第九讲函数、递推、递归,float f1(int a),/函数f1,int b,c;char f2(intint i,j;int main()int m,n;int p,q;,b、c有效,a有效,x,int y)i、j有效,/函数f2,x、y有效,/主函数,p、q在复合语句中有效,m、n有效,38,第九讲函数、递推、递归,a也只在f1函数中有效。其他函数不能调用。大连理工大学 盘锦校区基础教学部,说明:,
18、(1)主函数main中定义的变量(m,n)也只在主函数 中有效,不会因为在主函数中定义而在整个文件或 程序中有效。主函数也不能使用其他函数中定义的 变量。(2)不同函数中可以使用同名的变量,它们代表不 同的对象,互不干扰。例如,在f1函数中定义了变量 b和c,倘若在f2函数中也定义变量b和c,它们在内存 中占不同的单元,不会混淆。(3)可以在一个函数内的复合语句中定义变量,这 些变量只在本复合语句中有效,这种复合语句也称 为分程序或程序块。(4)形式参数也是局部变量。例如f1函数中的形参,大连理工大学 盘锦校区基础教学部,39,第九讲函数、递推、递归,(5)在函数声明中出现的参数名,其作用范围
19、只在本 行的括号内。实际上,编译系统对函数声明中的变量 名是忽略的,即使在调用函数时也没有为它们分配存,储单元。例如,int max(int a,int b);int max(int x,inty)coutxyendl;coutabendl;,/函数声明中出现a、b,/函数定义,形参是x、y/合法,x、y在函数体中有效/非法,a、b在函数体中无效,编译时认为max函数体中的a和b未经定义。,大连理工大学 盘锦校区基础教学部,40,第九讲函数、递推、递归,全局变量,程序的编译单位是源程序文件(.cpp),一个源文 件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定 义的变量
20、是外部变量,称为全局变量(global variable,也称全程变量)。全局变量的有效范围为从定义变量的位置开始到 本源文件结束。如,大连理工大学 盘锦校区基础教学部,41,第九讲函数、递推、递归,int p=1,q=5;/全局变量,float f/定义函数f1,1(a),int a;,围,全局变量c1、c2的作用范围,(int a),大连理工大学 盘锦校区基础教学部,42,第九讲函数、递推、递归,p、q、c1、c2都是全局变量,但它们的作用范围不 同,在main函数和f2函数中可以使用全局变量p、q、c1、c2,但在函数f1中只能使用全局变量p、q,而 不能使用c1和c2。,在一个函数中既
21、可以使用本函数中的局部变量,又 可以使用有效的全局变量。说明:(1)设全局变量的作用是增加函数间数据联系的渠 道。(2)建议不在必要时不要使用全局变量,因为:全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。,大连理工大学 盘锦校区基础教学部,43,第九讲函数、递推、递归,在程序设计中,在划分模块时要求模块的内聚,性强、与其他模块的耦合性弱。即模块的功能要单 一(不要把许多互不相干的功能放到一个模块中),与其他模块的相互影响要尽量少,而用全局变量是 不符合这个原则的。一般要求把程序中的函数做成一个封闭体,除 了可以通过“实参形参”的渠道与外界发生联 系外,没有其他渠道。
22、这样的程序移植性好,可读性强。,第九讲函数、递推、递归,大连理工大学 盘锦校区基础教学部 44,使用全局变量过多,会降低程序的清晰性。在各个函数执行时都可能改变全局变量的值,程序容易 出错。因此,要限制使用全局变量。,(3)如果在同一个源文件中,全局变量与局部变量 同名,则在局部变量的作用范围内,全局变量被屏 蔽,即它不起作用。变量的有效范围称为变量的作用域(scope)。归纳起 来,变量有4种不同的作用域:文件作用域(file scope)、函数作用域(function scope)、块作用域(block scope)和函数原型作用域(functionprototype scope)。文件作
23、用域是全局的,其他三,者是局部的。,大连理工大学 盘锦校区基础教学部,45,第九讲函数、递推、递归,变量的存储类别,已介绍了变量的一种属性作用域,作用域是从 空间的角度来分析的,分为全局变量和局部变量。变量还有另一种属性存储期(storage duration,也称生命期)。存储期是指变量在内存中 的存在时间。这是从变量值存在的时间角度来分析 的。存储期可以分为静态存储期(static storage duration)和动态存储期(dynamic storage duration)。这是由变量的静态存储方式和动态存储 方式决定的。,大连理工大学 盘锦校区基础教学部,46,第九讲函数、递推、递
24、归,存储方式,静态存储方式是指在程序运行期间,系统对变量分配固定的存储空间。动态存储方式则是在程序运行期间,系统对变量动 态地分配存储空间。,大连理工大学 盘锦校区基础教学部,47,第九讲函数、递推、递归,存储方式,先看一下内存中的供用户使用的存储空间的情况。这个存储空间可以分为三部分,即:(1)程序区(2)静态存储区(3)动态存储区,大连理工大学 盘锦校区基础教学部,48,第九讲函数、递推、递归,静态存储区,数据分别存放在静态存储区和动态存储区中。全局变量全部存放在静态存储区中,在程序开始执行 时给全局变量分配存储单元,程序执行完毕就释放这 些空间。在程序执行过程中它们占据固定的存储单元,而
25、不是 动态地进行分配和释放。,大连理工大学 盘锦校区基础教学部,49,第九讲函数、递推、递归,动态存储区,在动态存储区中存放以下数据:函数形式参数。在调用函数时给形参分配存储空间。函数中的自动变量(未加static声明的局部变量,详见后面的介绍)。函数调用时的现场保护和返回地址等。对以上这些数据,在函数调用开始时分配动态存储空 间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的,如果在一个程序中两次调用同一函数,则要进行两次分配和释放,而两次分配给此函数中局部变量的存储空间地址可能是不相同的。,第九讲函数、递推、递归,50,大连理工大学 盘锦校区基础教学部,如果在一个程序中包
26、含若干个函数,每个函数中的 局部变量的存储期并不等于整个程序的执行周期,它 只是整个程序执行周期的一部分。根据函数调用的情况,系统对局部变量动态地分配和释放存储空间。,在C+中变量除了有数据类型的属性之外,还有存 储类别(storage class)的属性。存储类别指的是数 据在内存中存储的方法。存储方法分为静态存储和动 态存储两大类。具体包含4种:自动的(auto)、静态的(static)、寄存器的(register)和外部的(extern)。根据变量的存储类别,可以知道变量的作用域和存储,期。,大连理工大学 盘锦校区基础教学部,51,第九讲函数、递推、递归,自动变量,函数中的局部变量,如果
27、不用关键字static加以声明,编译系统对它们是动态地分配存储空间的。函数的形参和在函数中定义的变量(包括在复合语 句中定义的变量)都属此类。在调用该函数时,系统给形参和函数中定义的变量 分配存储空间,数据存储在动态存储区中。在函数调 用结束时就自动释放这些空间。如果是在复合语句中 定义的变量,则在变量定义时分配存储空间,在复合 语句结束时自动释放空间。因此这类局部变量称为自 动变量(auto variable)。,大连理工大学 盘锦校区基础教学部,52,第九讲函数、递推、递归,用register声明寄存器变量一般情况下,变量的值是存放在内存中的。当程序,中用到哪一个变量的值时,由控制器发出指
28、令将内存中 该变量的值送到CPU中的运算器。经过运算器进行运算,如果需要存数,再从运算器将数据送到内存存放。如图 所示。为提高执行效率,C+允许将局部变量的 放在CPU中的寄存器中,需要用时直接从寄 存器取出参加运算,不必再到内存中去存 取。这种变量叫做寄存器变量,用关键字register作声明。但是,是建议性的;,值,大连理工大学 盘锦校区基础教学部,53,第九讲函数、递推、递归,用static声明静态局部变量,有时希望函数中的局部变量的值在函数调用结束后不 消失而保留原值,即其占用的存储单元不释放,在下 一次该函数调用时,该变量保留上一次函数调用结束 时的值。这时就应该指定该局部变量为静态
29、局部变量(static local variable)。,大连理工大学 盘锦校区基础教学部,54,第九讲函数、递推、递归,大连理工大学 盘锦校区基础教学部,55,第九讲函数、递推、递归,先后3次调用f函数时,b和c的值如书中表所示。,第九讲函数、递推、递归,静态局部变量说明,(1)静态局部变量在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动 态局部变量)属于动态存储类别,存储在动态存储 区空间(而不是静态存储区空间),函数调用结束后 即释放。(2)为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。以后 每次调用函数时不再重新赋初值而只是保留
30、上次函 数调用结束时的值。而为自动变量赋初值,不是在 编译时进行的,而是在函数调用时进行,每调用一 次函数重新给一次初值大连,理工相大学当盘锦校于区基执础教行学部一次赋值语句。56,大连理工大学 盘锦校区基础教学部,57,第九讲函数、递推、递归,(3)如果在定义局部变量时不赋初值的话,对静态 局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)。而对自动变量来说,如 果不赋初值,则它的值是一个不确定的值。这是由 于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值 是不确定的。,(4)虽然静态局部变量在函数调用结束后仍然存在,但其他函数是
31、不能引用它的,也就是说,在其他函数中它是“不可见”的。,大连理工大学 盘锦校区基础教学部,58,第九讲函数、递推、递归,静态局部变量使用,在什么情况下需要用局部静态变量呢?1.需要保留函数上一次调用结束时的值。例如可以用下例中的方法求!。如:int fac(int n),static int f=1;,/f为静态局部变量,函数结束/时f的值不释放/在f原值基础上乘以n,f=f*n;return f;,大连理工大学 盘锦校区基础教学部,59,第九讲函数、递推、递归,静态局部变量使用,2.如果初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。,大连理工大学
32、盘锦校区基础教学部,60,第九讲函数、递推、递归,用extern声明外部变量,全局变量(外部变量)是在函数的外部定义的,它 的作用域为从变量的定义处开始,到本程序文件的末 尾。在此作用域内,全局变量可以为本文件中各个函 数所引用。编译时将全局变量分配在静态存储区。有时需要用extern来声明全局变量,以扩展全局变量的作用域。,61,第九讲函数、递推、递归,在一个文件内声明全局变量,提前引用声明,大连理工大学 盘锦校区基础教学部,大连理工大学 盘锦校区基础教学部,62,第九讲函数、递推、递归,在多文件程序中声明外部变量,外部变量声明分析下例:file1.cpp extern inta,b;int
33、 main()couta,bendl;return0;注意:,file2.cpp inta=3,b=4;,extern 是用作变量声明,而不是变量定义。它只是对一 个已定义的外部变量作声明,以扩展其作用域。,大连理工大学 盘锦校区基础教学部,63,第九讲函数、递推、递归,用extern扩展全局变量的作用域,虽然能为程序设 计带来方便,但应十分慎重,因为在执行一个文件中的,函数时,可能会改变了该全局变量的值,从而会影响到另一文件中的函数执行结果。,大连理工大学 盘锦校区基础教学部,64,第九讲函数、递推、递归,用static声明静态外部变量,有时在程序设计中希望某些外部变量只限于被本文 件引用,
34、而不能被其他文件引用。这时可以在定义 外部变量时加一个static声明。例如:,file1.cpp static int a=3;int main(),file2.cpp,extern int a;,int fun(int n)a=a*n;,大连理工大学 盘锦校区基础教学部,65,第九讲函数、递推、递归,这种加上static声明、只能用于本文件的外部变量(全局变量)称为静态外部变量。这就为程序的模块化、通用性提供了方便。如果已知道其他文件不需要引用本 文件的全局变量,可以对本文件中的全局变量都加上static,成为静态外部变量,以免被其他文件误用。,需要指出,不要误认为用static声明的外部
35、变量才采 用静态存储方式(存放在静态存储区中),而不加 static的是动态存储(存放在动态存储区)。实际上,两种形式的外部变量都用静态存储方式,只是作用范围不同而已,都是在编译时分配内存的。,大连理工大学 盘锦校区基础教学部,66,第九讲函数、递推、递归,存储期和作用域,大连理工大学 盘锦校区基础教学部,67,第九讲函数、递推、递归,变量的声明和定义,关于声明和定义:针对函数而言,函数的声明是函数的原型,而函数的定义是函数功能的建立;在声明部分出现的变量有两种情况:一种是需要建立 存储空间的(如 int a);另一种是不需要建立存储 空间的(extern int a);前者称为定义性声明,或
36、简称定义;后者称为引用性声明;,大连理工大学 盘锦校区基础教学部,68,第九讲函数、递推、递归,为叙述方便,把建立存储空间的声明称为定义;,如:int a;,而把不需要建立存储空间的声明称为声明;如:extern int a;,大连理工大学 盘锦校区基础教学部,69,第九讲函数、递推、递归,外部变量定义和外部变量声明的含义是不同的。外,部变量的定义只能有一次,它的位置在所有函数之外,而同一文件中的外部变量的声明可以有多次,它的位置 可以在函数之内,也可以在函数之外。系统根据外部变 量的定义分配存储单元。对外部变量的初始化只能在定 义时进行,而不能在声明中进行。所谓声明,其作用是 向编译系统发出
37、一个信息,声明该变量是一个在后面定 义的外部变量,仅仅是为了提前引用该变量而作的声明。extern只用作声明,而不用于定义。,大连理工大学 盘锦校区基础教学部,70,第九讲函数、递推、递归,用static来声明一个变量的作用有二:,(1)对局部变量用static声明,使该变量在本函数调用结 束后不释放,整个程序执行期间始终存在,使其存储 期为程序的全过程。(2)全局变量用static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)。,大连理工大学 盘锦校区基础教学部,71,第九讲函数、递推、递归,内部函数和外部函数,函数本质上是全局的,因为一个函数要被另外的函 数调用,但是,也可以指
38、定函数只能被本文件调用,而不能被其他文件调用。根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。,大连理工大学 盘锦校区基础教学部,72,第九讲函数、递推、递归,内部函数,如果一个函数只能被本文件中其他函数所调用,它称为 内部函数。在定义内部函数时,在函数名和函数类型的 前面加static。函数首部的一般格式为static 类型标识符 函数名(形参表)如static intfun(inta,int b)内部函数又称静态(static)函数。使用内部函数,可以 使函数只局限于所在文件。如果在不同的文件中有同 名的内部函数,互不干扰。通常把只能由同一文件使 用的函数和外部变量放在一个文
39、件中,在它们前面都冠 以static使之局部化,其他文件不能引用。,大连理工大学 盘锦校区基础教学部,73,第九讲函数、递推、递归,外部函数,(1)在定义函数时,如果在函数首部的最左端冠以关 键字extern,则表示此函数是外部函数,可供其他文 件调用。如函数首部可以写为extern int fun(int a,int b)这样,函数fun就可以为其他文件调用。如果在定义 函数时省略extern,则默认为外部函数。本书前面所 用的函数都是外部函数。(2)在需要调用此函数的文件中,用extern声明所用的函数是外部函数。,大连理工大学 盘锦校区基础教学部,74,第九讲函数、递推、递归,例4.15
40、 输入两个整数,要求输出其中的大者。用 外部函数实现。,file1.cpp(文件)#include using namespace std;int main()extern int max(int,int);int a,b;cinab;couty?x:y;return z;,/声明在本函数中将要调用在其他文/件中定义的max函数,大连理工大学 盘锦校区基础教学部,75,第九讲函数、递推、递归,通过此例可知:使用extern声明就能够在一个文件中 调用其他文件中定义的函数,或者说把该函数的作用 域扩展到本文件。extern声明的形式就是在函数原型 基础上加关键字extern。由于函数在本质上是外部的,在程序中经常要调用其他文件中的外部函数,为方便 编程,C+允许在声明函数时省写extern。例子程序main函数中的函数声明可写成,int max(int,int);注意:用函数原型能够把函数的作用域扩展到定义该函数的文件之外(不必使用extern),大连理工大学 盘锦校区基础教学部,76,第九讲函数、递推、递归,头文件:利用函数原型扩展作用域最常见的例子是,#include 命令的应用;,大连理工大学 盘锦校区基础教学部,77,第九讲函数、递推、递归,The end,