函数和编译预处理2_第1页
函数和编译预处理2_第2页
函数和编译预处理2_第3页
函数和编译预处理2_第4页
函数和编译预处理2_第5页
已阅读5页,还剩88页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、函数和编译预处理2main( )func1()func2()func3()func5()func4()主调函数、调用被调函数子函数、被调用参数返回值主调函数 和 被调函数 的关系: 上下级 关系请问:main( ) 被 谁调用?一个程序中 函数 调用 的示意图:#include void main( ) int n; cinn; if (n1) cout“the sum is: sum( n )endl; /调用 sum()函数 int sum( int n) 例3.1 编写函数求前 n 个自然数之和,n 的值从键盘输入。函数首部、函数头函数首部/函数头函数体 int k,s=0; for (

2、k=1;ky)? x : y ; return z; void main (void ) int a,b,c; cinab; c=max (a , b) ; cout“The max is cy)? x : y ; return z; void main (void ) int a,b,c; cinab; c=max (a , b) ; cout“The max is cendl; ab23调用处表达式中3xy23zc=3不要将函数名做变量用!不能写成 max=z;2自定义函数的声明函数类型关键字 函数名( 参数1 类型 , 参数1名称 ,参数2 类型 , 参数2名称 ); 什么时候需要声明?

3、 声明的含义、作用? 声明的格式、位置?1库函数的声明 对库函数的声明已经写在有关 包含文件头文件 中了,因此只要在程序文件首部用 include 指令将这些 包含文件 包含到本程序中来,就完成了对库函数的声明。 #include 3.2.2 函数的声明补述函数的声明形式也叫做函数原型function prototype) 。 它说明了函数的类型、函数名、函数各形式参数类型。函数类型关键字 函数名( 参数1 类型 ,参数2 类型 );?修改p68?名称任意,可省略【例3.2】输入圆柱体的底面半径和高,求底面圆面积和体积。设函数 area()和 volum()分别求圆面积和圆柱体体积。#incl

4、ude using namespace std;void main() double volum(float, float); /声明 double area(float r); /声明 float r,h; double s,v; coutrh; s= area(r); /调用 v= volum(r,h); /调用 couts=s,v=vab; c=add (a , 3.5) ; cout“The sum is cendl; 2实参 与 形参的类型应一样或赋值兼容。 值传递: 调用函数时,计算机将函数调用处的实参值传给被调函数的形参,在被调函数执行过程中,形参可以被改变,但不影响函数调用处的

5、实参值。换一句话说,这种参数传递机制是单向影响。3.3.1 参数的 值传递 (前面已介绍) 除了小节介绍的值传递参数方式外,函数调用还有一种特殊的值传递形式,即传递的值不是一般的数值,而是一些内存单元地址编号即地址,这时,一般称之为参数的地址传递。在这种参数传递形式中,无论在函数的定义中出现的形参还是在调用语句中出现的实参,都是代表一些内存单元地址编号即地址数值,而不是一般的数值。 C+中的参数地址传递情况一般有如下几种:实参可以是一个有确定值的普通变量的地址,或者是一个已经初始化的指针变量;或者是一个初始化的数组名;或者是一个具体的函数名。而形参可以是一个任意普通变量的地址,或是一个任意指针

6、变量,或是一个任意的数组名,或是一个指向函数的指针变量对应于实参是具体函数名。 3.3.2 参数的 地址传递4章 实际上,这种参数传递机制就是在函数调用时把一个内存单元地址传递给形参,使形参也具有实参的内存单元地址即两者对应同一个内存单元,称作形参和实参地址结合,两者合二为一。这样一来,任何时候形参的值等于实参的值;而实参的值也等于形参的值。因此,形参在函数中发生变化后,也会引起实参跟着变化因为它们是捆绑在一起的,一体化的。这就意味着按地址传递的方式,在调用刚开场时实参的值影响了形参;而在被调函数执行过程中形参值假设发生了变化,它也会影响实参的值变化。即机制是双向影响,这与普通值传递方式的单向

7、影响机制形成比照。【例3.5】 延迟函数的使用。#include void delay(int loop); /声明void main( ) coutbeginendl; delay( 1000 ); /调用 coutendendl;void delay(int loop) /定义 if (loop=0) return; for(int i=0;iloop;i+) coutiendl; 3.3.3 带 默认值 的参数 C+ C+语言中,允许在函数定义或声明时给一个或多个形参指定默认值。这样,后面的函数调用中,可以不给具有默认值的形参设定相应的实参。void delay(int loop=100

8、0); void delay(int x=1000); delay( ); /调用 对于教材【例3.2】的求圆柱体体积的函数volume( ),如下声明:float volumefloat r, float h); /只对形参h指定默认值这时函数调用形式:volume(6.0); /相当于volume(6.0, ),7.2); / r的值为,h的值为7.2 如果函数有多个形参,可以对每个或局部形参指定默认值。 指定默认值的形参必须放在参数列表中的 最 右 边。课堂总结a 函数b 函数main 函数结束(2)(3)(4)(5)(6)(7)(8)(9)C语言不允许对函数作嵌套定义!3.4.1 嵌套

9、调用:在一个函数定义中,可以调用另一个函数。 程序执行时,在调用一个函数的过程中,又调用另一个函数。 例如:3.4 函数的 嵌套调用 和 递归调用调用 a 函数调用 b 函数main( )函数 直接地 调用了 a函数,main( )函数 嵌套地 调用了 b函数(间接调用)。long comb(int n, int m) /定义组合函数long c; c=fac(m)/(fac(n)*fac(m-n);/ 嵌套调用阶乘函数 return c;void main() int n,m; long c;coutplease input two integer numbers:m,nmn;c= comb

10、 (n,m); / 调用组合函数combcoutc=cendl;main()分析:定义函数long comb(int n,int m) 求组合数。定义函数long fac(int k)求k的阶乘。comb()fac()#include using namespace std;long fac(int k) / 定义求阶乘的函数long f=1; int i; for(i=1;i=k;i+) f = f*i; return f;【例3.6】编程求组合数,3.4.2 函数的 递归调用 在调用一个函数的过程中,被调用函数又直接或间接地调用 自身,这种调用过程称为函数的递归(recursive)调用。

11、直接递归 调用 函数 的代码形式:int f ( ) / 函数f1的定义 / 函数其它局部 z=f ( ); / 直接调用自身 / 函数其它局部 在函数f ( ) 中,又直接调用了f ( )函数。间接递归 调用 函数 可以表现为如下:int f1 ( ) / 函数f1的定义 / f1的其他局部x=f2 ( ); / 调用f2 ( ) / f1的其他局部 int f2 ( ) / 函数f2的定义 / f2的其他局部y=f1 ( ); / 调用f1 ( ) / f2的其他局部 函数的直接递归调用 函数的间接递归调用 图中调用过程特点:这两种递归调用都是无终止的自身调用?! 程序中不应出现这种无终止

12、的递归调用,而只应出现有限次数的、有终止的递归调用! 解决:用if语句来控制,只有在某一条件成立时才继续执行递归调用,否那么就不再继续。包含递归调用的函数称为递归函数。【例3.7】 用递归计算 n!。求n!,应先求n-1!;而求(n-1)!,又需要先求n-2!,而求(n 2)!;又可以变成求n-3!,如此继续,直到最后变成求1!的问题,而根据公式有1!=1(这就是本问题的递归终止条件。由终止条件得到1!结果后,再反过来 依次求出2!,3!直到最后求出n!。【例3.7】 用递归计算n!。 n!本身就是以递归的形式定义的:#include using namespace std;long fac(

13、int n)long f; if (n=1) f=1; else f=n*fac(n-1); / 递归调用,求(n-1)! return f;void main( )long y; int n; coutplease input a integer n n; y=fac(n); /调用fac(n)求n!coutn=n,y=y1)long fibonacci(int n)if( n=0|n=1 )return n;elsereturn fibonacci(n-1)+fibonacci(n-2);程序如下所示: ?实验教程?P19 三 实验思考 1:求Fibonacci数列 大于t的最小项 的值。

14、void main()int n=0,t;long result,t;cint;result=fibonacci(n);whlie (result=t) n+; result=fibonacci(n); coutresult;方法:1.递归函数?实验教程: P19 三 实验思考 1 ?2.用循环做 ?实验教程: p90.四,1 ?3. 数组 ?教材:p140,3?求两个数最大公约数的方法1. 辗转相除法 (p57)2. 短除法3. 试探法4. 递归方法 用 函数递归调用 做用 g(m,n) 表示m、n的最大公约数,请写出那么其递归定义。递归边界终止条件使问题向递归边界终止条件转化的规那么类似例

15、题习题:强调:上述问题的递归定义具备两个成分:递推方法程序描述繁杂,可读性差;主要采用 循环构造;逐步执行;当前值的求得总建立在前面求解的根底上;递归方法描述与原始问题递归公式比较接近;书写简洁、易读易写;易于分析算法的复杂性和证明算法的正确性;在问题转化时,需要花时间和存储空间将有关的“现场信息保存起来;当到达终止条件时,系统又需要花时间将有关的“现场信息恢复以便处理未曾处理完的函数调用 。占用存储空间少,执行速度快。递归 与 递推 算法递归函数的适应场合:待求解的问题含有递归关系。【例3.8】 汉诺塔问题abc汉诺塔Tower of Hanoi问题据说来源于布拉玛神庙。该问题的装置如下图(

16、图上仅画三个金片以简化问题的原理,原问题有64个金片),底座上有三根金钢石的针,第一根针a上放着从大到小64个金片。解决该问题就是要想法把所有金片从第一根针a上移到第三根针c上,第二根针b作为中间过渡。要求是每次只能移动一个金片,并且任何时候不允许大的金片压在小的金片上面。 图3.6 三个金片的汉诺塔问题装置1. 本问题的递归终止条件。如果只有1个盘,显然问题的解就很明显是:直接把金片从a移到c。因此终止条件是n = 1;终止条件对应的操作是直接把金片从a移到c,示意ac。2. 本问题的递归分析:移动n个金片从a到c,必须先将n-1个金片从a借助c移动到b,移动n-1个金片与原问题一样,但规模

17、变小,即向终止条件接近,因此,此问题可以用递归过程完成。递归过程可以用如下步骤表示:(1)将n-1个金片从a经过c移动到b。(2)将第n个金片从a直接移动到c。(3)再将n-1个金片从b经过a移动到c。 一般地,设将n个金片从x针借助y针移动到z针的函数原形为:void hanoi(int n,char x,char y,char z)根据解题步骤,可以写出求解n个金片的汉诺塔函数如下:#include /*ex3_8.cpp*using namespace std;void hanoi(int n,char x,char y,char z) if (n=1) /n=1时,直接将金片从x移动到

18、z cout x z 1时 hanoi(n-1,x,z,y); /先将n-1个金片从借助z移动到y cout x z 1时,就递归调用hanoi(),每次n减1。最后当n=1时,直接移动该金片就可以了。 主函数如下: void main() int n; cout input n: n; hanoi(n,a,b,c); / n个金片从a针借助b针移动到c针 虽然递归调用在写程序时很简单,但执行起来却很复杂时间、存储空间都开销大。对于汉诺塔问题程序的执行过程分析比较复杂,有兴趣的读者可参阅教材对3个盘情景的分析图3.7 及其相应文字表达。 3.5 内置函数 C+,选讲一般函数调用的过程:调用前:

19、参数传递,保存下条指令地址信息,和CPU状态信息,执行流程转入被调函数。调用完毕:传回函数值,执行流程回到主调函数。函数调用花费额外的时间和空间!如果函数频繁地被调用,如调用出现在循环中,那么开销大,影响效率缺点。函数的优点之一:便于实现模块化/构造化程序设计的方法。发挥其优点,抑制其缺点,采用内置函数3.5 内置函数 C+,选讲一般函数调用的过程:C+编译时将被调函数的代码直接嵌入到主调函数中,程序执行时不必将流程转出去。这种嵌入到主调函数中的函数称为内置函数(inline function),又称内嵌函数 或 内联函数。3.5.1 内置函数的作用 提高程序中函数调用的效率;并保持程序的可读

20、性。 适应场合:如果函数频繁地被调用.指定内置函数的方法:在函数定义首行或函数说明的左端加一个关键字inline即可。#include int is_number(char); /函数声明void main( ) char c; while (c= cin.get() !=n) if ( is_number(c) ) /调用一个小函数coutyou enter a digit n;else cout=0& ch=9)?1:0 ; 【例3.9】 判断用户从键盘输入的系列字符是数字字符还是其它字符的函数is_number()。程序中不断到设备中读取数据,频繁调用is_number()函数。为了防止

21、频繁调用函数,提高执行效率,可以将【例3.9】程序改为:#include /*ex3_9b.cpp*void main() char c; while (c=cin.get()!=n) if ( (c=0& c=9)?1:0 ) /修改处:直接计算表达式 coutyou enter a digit n; else coutyou enter a non-digit n; 修改后的程序在if语句中用表达式替换了函数调用。在程序运行上,提高了一些执行效率,因为免去了大量的函数调用开销。但是,由于is_number函数比相应的表达式可读性好,所以修改后的代码可读性降低,尤其假设程序中多处出现is_n

22、umber的替换时,会大大降低可读性。我们希望既要用函数调用来表达其构造化和可读性,又要使效率尽可能地高。为了尽量做到两全其美,C+中引入内置函数这个方法。内置函数的定义格式如下: inline 类型名 函数名(形参列表) /函数体 内置函数的声明格式如下:inline 类型名 函数名(形参类型表);其实,内置函数只要在开头一次性声明为inline即可,而后面的函数定义仍可写成一般函数定义的形式,编译器也会将函数视为内置函数。3.5.2 定义 和 使用 内置函数对【例3.9】使用内置函数来解决,代码可以写成以下形式:#include /*ex3_9c.cpp*inline int is_num

23、ber(char);/inline函数声明void main( ) char c; while (c=cin.get()!=n) if (is_number(c) /调用一个小函数coutyou enter a digit n;else cout=0& ch=9)?1:0; 1内置函数与一般函数的区别在于函数调用的处理。一般函数进展调用时,要将程序执行到被调用函数中,然后返回到主调函数中;而内置函数在调用时,是将调用局部用内置函数体来替换。2假设函数定义局部在调用之后,那么内置函数必须先声明后调用。因为程序编译时要对内置函数替换,所以在内置函数调用之前必须声明是内置的inline,否那么将会像

24、一般函数那样产生调用而不是进展替换操作。3在内置函数中,不能含有复杂的构造控制语句,如switch、for和while。如果内置函数有这些语句,那么编译器将该函数视同一般函数那样产生函数调用。4递归函数不能用作内置函数。5以后讲到的类中,所有定义在说明内部的函数都是内置函数。关于内置函数的说明:3.6 变量 和 函数 的属性变量的属性:类型、名称、作用域、生存期 3.6.1 变量的作用域 作用域:指变量在 空间上 的有效范围。1局部变量局部变量:在函数或程序块复合语句内定义的变量。其作用域:相应的函数体 或 程序块,从定义点到相应的函数体 或 程序块的尾部。void f( int t ) /

25、t为函数级的局部变量。 int x1 ; / x1为函数级的局部变量。 int y1 ; / y1为语句块级的局部变量, int y2 ; / y2为语句块级的局部变量, int x2 ; / x2为函数级的局部变量。 【例3.10】 局部变量的使用。#include double fun1(double a, double b) double c; /fun1函数中3个局部变量a、b、cc=a+b; return c; void main() /main函数中3个局部变量a、b、cdouble a,b,c; coutab; c=fun1(a,b); couta+b=cendl; c=fun2

26、(a,b); couta*b=cendl;局部变量同名现象:不同范围的局部变量可以同名,不同范围的同名局部变量表示不同的数据。但同一范围内不允许两变量同名出现。double fun2(double a,double b) double c; /fun2函数中3个局部变量a、b、cc=a*b; return c;注意: 在函数声明中出现的参数名,其作用范围只在本行的括号内。例如:int max(int a,int b); /函数声明中出现的a、b,它们的作用范围只在本行有效。 int max(int, int); 定义在函数以外的变量外部变量,静态全局变量。作用域:从变量定义处到该文件结尾处。

27、通过声明后, 对本程序的其它文件中的函数也可见。 2全局变量#include int a; /a的作用域为整个文件void fun1( ); /声明fun1函数void main( ) coutaendl; /main函数中使用了全局变量afun1( ); /调用fun1函数coutaendl; /main函数中再次使用全局变量avoid fun1( ) a=5; / fun1函数中使用全局变量a 程序运行结果如下:05没有设定初始值的全局变量,编译默认其初值为0。【例3.11】 全局变量 的使用说明:1没有人为设定初始值的全局变量,编译将其初值设为0全局变量默认初始值为0。 2全局变量可以定

28、义在任何位置,但其作用域是从定义的位置开场到文件的末尾。 而定义在文件中间的全局变量就只能被其下面的函数所使用,全局变量定义之前的所有函数不会知道该变量。 3全局变量 为函数之间 数据的传递 提供了通道。由于全局变量可以被其定义后的函数所使用,所以可以使用全局变量进展函数间数据的传递。而且这种传递数据的方法可以传递多个数据的值。gcd(a, b) maxlcm(a, b)main( ) min分析:由于求最小公倍数要依赖于最大公约数,所以应先求最大公约数。故应将求最大公约数的函数写在前面,求最小公倍数的函数放在后面。int gcd(int, int);/声明求最大公约数的函数int lcm(i

29、nt, int); /声明求最小公倍数的函数int max , min; /全局变量分别存放 最大公约数、最小公倍数void main( )【例3.12】 分别写两个函数求给定两个数的最大公约数和最小公倍数。其中,要求用全局变量存放最大公约数和最小公倍数。分析:由于求最小公倍数要依赖于最大公约数,所以应先求最大公约数。故应将求最大公约数的函数写在前面,求最小公倍数的函数放在后面。#include int gcd(int, int);/声明求最大公约数的函数int lcm(int, int); /声明求最小公倍数的函数int max , min; /全局变量分别存放最大公约数、最小公倍数void

30、 main( ) int a; int b; coutab; gcd (a,b); lcm(a,b); cout the greatest common divisor is :maxendl; /使用全局变量 max cout the lease common multiple is :minendl; /使用全局变量 min【例3.12】 分别写两个函数求给定两个数的最大公约数和最小公倍数。其中,要求用全局变量存放最大公约数和最小公倍数。int gcd(int x,int y) int t;int r; if (xy) t=x;x=y;y=t; r=x%y; while(r!=0) x=y

31、; y=r; r=x%y; max=y; return max;/使用全局变量maxint lcm(int x,int y) min=x*y/max; /使用全局变量max求全局变量min, return min; /返回全局变量min void gcd(int x,int y) int t;int r; if (xy) t=x;x=y;y=t; r=x%y; while(r!=0) x=y; y=r; r=x%y; max=y;(4) 全局变量降低了函数的通用性,建议不在必要时不要使用全局变量缺点。因为如果函数在执行的时候使用了全局变量,那么其他程序使用该函数时也必须将该全局变量一起移过去。

32、另外,全局变量在程序执行的全部过程都占用存储空间,而不是需要时才开辟存储空间。 3不同作用域的同名变量引用规那么 程序运行结果是:1,2,3,5 【例3】不同作用域的同名变量引用规那么例如。int a=5; /全局变量aint fun(); /声明一个函数main() int a; /函数级局部变量a a=1; /引用是函数级局部变量a couta,; /此处引用的是函数级局部变量a int a; /程序块级局部变量a a=2; /此处引用是程序块级局部变量a couta,; /此处引用的是程序块级局部变量a a=3; /此处引用的a是函数级局部变量a couta,; /此处引用的a是函数级局

33、部变量a coutfun()endl;int fun() return a; /全局变量a 重名变量作用域规那么:在某个作用域范围内定义的变量,在该范围的子范围内可以定义重名变量,这时原定义的变量在子范围内是不可见的,但是它还存在,只是在子范围内由于出现了重名的变量而被暂时隐藏起来,过了子范围后,它又是可见的。3.6.2 变量的生存期较难变量存储期(生命期) :变量(值)在内存中存在的时间。动态存储区(堆栈)静态(全局)存储区寄存器(CPU中)数据存储区变量存储区1短生存期变量动态存储方式2长生存期变量静态存储方式变量存储期长短 由变量的 存储方式 决定。动态存储方式:在程序运行期间动态地分配

34、存储空间给变量的方式。 包括:函数的形参,函数或程序块中定义的局部变量未用static声明。 具体有两种:自动变量、存放器类变量。静态存储方式:在程序运行期间分配固定的存储空间给变量的方式。 存储位置:静态(全局)存储区,生存期:为程序运行期间。包括:全局变量含外部变量、静态全局变量、静态局部变量。存储位置:在动态存储空间堆或栈或存放器中。存储期:为函数或程序块的运行期间。 存储位置:在动态数据存储区;生存期:函数 或 程序块 执行期间;作用域:其所在函数或程序块。用关键字auto作为存储类别的声明。例如:int fun() auto int a; /a为自动类变量 关键字“auto可以省略。

35、上述自动变量也可声明为 int a;(1)自动变量:函数中的局部变量默认是自动变量。(2)存放器变量:局部变量。存储位置:在CPU的通用存放器中;生存期: 作用域:特点:访问效率高,数量较少;用关键字register作为存储类别的声明。例如:void main() register int i; 1存放器变量不宜定义过多。计算机中存放器数量是有限的,不能允许所有的变量都为存放器变量。如果存放器变量过多或通用存放器被其他数据使用,那么系统将自动把存放器变量转换成自动变量。2存放器变量的数据长度与通用存放器的长度相当。一般是char型和int型变量。 存放器变量 的使用应注意以下问题:2长生存期变

36、量静态存储方式全局变量含外部变量、静态全局变量和 静态局部变量。1外部变量:未用static关键字定义的全局变量。如果不对外部变量另加声明,那么它的作用域是从定义点到所在文件的末尾。用extern关键词加以声明后将外部变量作用域扩展到声明位置,声明语句格式为extern 类型符 外部变量名; /int 类型符可省 改具体方式: 提前引用声明。扩展 外部变量 作用域 的方式【例3.14】 对定义在同一文件中外部变量,作提前引用声明 可以扩展其使用范围到文件前面的 声明 位置。#include void main() x=4; coutxendl;int x; /外部变量x的定义 extern i

37、nt x; /提前引用声明 跨文件引用声明。 扩展 外部变量 作用域 的方式【例3.15 】对定义在另一文件中的外部变量,作跨文件引用声明以扩展其作用域到 本文件。文件 的内容:#include void main() coutwendl; /使用文件中定义的变量w 文件 的内容:int w=10; / 外部变量 w 的定义程序运行结果如下:10 extern int w; / 跨文件引用声明用途:用于多个文件中的函数共享数据! 两个文件中不能出现 同名的外部变量! 2静态变量:静态全局变量、静态局部变量 静态全局变量:在定义全局变量时开头再添加一个static关键字所定义的全局变量。作用域:

38、定义点至定义所在文件的末尾;可以通过提前引用声明扩展其作用域;不能通过跨文件引用声明扩展其作用域只对本文件有效。一个文件中定义的静态全局变量与别的文件中定义的同名静态全局变量或同名外部变量没有牵连,互不影响!默认初值:0。【例3.17】 静态全局变量 的演示。文件的内容:#include static int u=10; /定义静态全局变量 void fun() coutThis is file1 文件的内容:#include extern int u; / 试图对u 作跨文件引用声明,此时行不通void main() coutuendl; /出现“变量u未定义错误2静态变量:静态全局变量、静

39、态局部变量 静态局部变量:在定义局部变量时开头再添加一个static关键字所定义的局部变量。生命周期:作用域:默认初值:0。【例3.16】使用静态局部变量的例子。#include void fun();void main() int i; for(i=0;i3;i+) fun( ); void fun() int a=0; /定义局部变量 static int b=0; /定义静态局部变量 a=a+1; b=b+1; couta,bendl;程序运行结果如下:1,11,21,3 变量属性 总结根据需要设置变量的属性!3.6.3 内部函数 和 外部函数 选讲 存储属性作用域 分别 类似 静态全局

40、变量、外部变量1 内部函数 存储属性 类似静态全局变量如果一个函数只能被 本文件 中 其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加static。函数首部的一般格式为static 类型标识符 函数名(形参表)如static int fun(int a,int b)内部函数又称 静态(static)函数。使用内部函数,可以使函数只局限于所在文件。不同文件中的同名内部函数互不干扰。【例3.18】 静态函数的例子。文件 中的内容:#include static void fun( ); void main( ) fun( ); static void fun( ) /文

41、件file1中定义静态函数,名称为fun coutthis in file1 endl; 文件 中的内容:#include static void fun() /文件file2中定义静态函数,名称也为fun coutthis in file2 endl; 程序运行结果如下: this in file1 2 外部函数存储属性 类似外部变量外部函数是可以被 整个程序 各文件中函数 调用的函数。1外部函数的定义。在函数类型前加存储类型关键字extern,或缺省存储类型关键字,定义格式如下:extern 函数类型 函数名(参数列表) 函数体 extern可缺省,即系统默认为extern型。2外部函数的

42、跨文件引用声明。文件A 在需要调用 文件B 中所定义的外部函数时,需要在文件A中用关键字extern对被调函数提出声明,声明格式如下:extern 函数类型 函数名(参数类型列表)【例3.19】 文件利用别的文件中的外部函数实现求阶乘。文件中的内容:#include using namespace std; void main( ) extern double fac(int); / 声明其他文件中定义的 外部函数int n;cout please input a integer to n :n;coutn!=fac(n)endl; 文件中的内容:#include using namespac

43、e std; extern double fac(int m) / 定义fac函数 extern 可以省略 int n; double s; s=1; for(n=1;nradius; length=2*PI*radius; /*引用无参宏名求周长*/ area=PI*radius*radius; /*引用无参宏名求面积*/ cout length area; length=2* *radius;例3.20 输入圆的半径,求圆的周长、面积。要求使用无参宏定义圆周率。1可提高源程序的可维护性2可提高源程序的可移植性 3减少源程序中重复书写字符串的工作量使用宏定义的优点说明:1在定义宏时,“宏名

44、和 “字符串 之间要用空格分开。而“字符串中的内容不要有空格。2宏名通常用大写字母定义。3宏定义是在编译前对宏进展替换的,但对程序中用双引号括起来的字符串内容,如果其中有与 宏名 一样的局部,是 不进展 文本替换的。例如:#include #define PI void main( ) coutPI=PIendl; 程序运行结果如下:PI= 3.14159 4宏定义后,可以在本文件各个函数中使用。也可以使用#undef取消宏的定义。5宏定义可以嵌套,已被定义的宏可以用来定义新的宏。例如:#include #define M 3 #define N M+2 /用已定义的宏M来定义新的宏N#def

45、ine L 4*N +6 /用已定义的宏N来定义新的宏Lvoid main( ) coutLendl; 程序运行结果如下:20 与 常变量 的区别 const double 2 . 有参数宏定义 带参数宏定义的一般格式 #define 宏名(形参表) 字符串 宏展开:不只是简单地将宏名用字符串替换,还要进展参数替换。 #define PI#define S(r) PI*r*rmain()float a,area; a=3.6; area=S(a); coutaarea;area=PI*a*aarea= 3.1415926*a*a1定义有参宏时,宏名与左圆括号之间不能留有空格。否那么,编译系统将空格以后的所有字符均作为替代字符串,而将该宏视为无参宏。2有参宏的展开,只是将宏名和参数进展字符串替换。为了保证宏的展开结果正确,在定义有参宏时,在所有 形参外 和 整个字符串 外,均加一对圆括号。 area=S(a+5);预期的替换 的结果:area= 3.1415926*(a+5)*(a+5)宏展开 (字符串替换) 的实际结果:area= 3.1415926*a+5*a+5d=1/S(a+5);预期的替换 的结果:d= 1/

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论