再上一篇:5.7 函数的重载
上一篇:5.8 编译预处理
主页
下一篇:第六章 数组
再下一篇:6.2 字符数组的定义及应用
文章列表

5.9 程序的多文件组织

《VC++程序设计基础》,讲述C++语言的语法和标准库,以及Visual C++ 函数库和MFC类库的使用,并附相关代码示例。

当编写功能简单的程序时,可以将一个完整的程序放在一个源程序文件中。而在设计一个功能复杂的大程序时,为了便于程序的设计和调试,通常将程序分成若干个模块,把实现一个模块的程序或数据放在一个文件中。当一个完整的程序被存放在多于一个文件中时,称为程序的多文件组织。这种多文件组织的程序存在如何进行编译和连接的问题;另外也存在一个文件中的函数要调用到另一个文件中的函数或用到另一个文件中的全局变量等问题。

5.9.1内部函数和外部函数

5.9.1.1内部函数

在一个源程序文件中定义的函数,限定它只能在本源程序文件内使用时,称这种函数为内部函数。定义内部函数的方法是:在定义函数时,在函数的类型标识符前加static修饰词。如:

static float fun()

{

......

}

5.9.1.2外部函数

在多文件组织的程序中,一个源程序文件中定义的函数,不仅能在本源程序文件内可使用,而且也可以在其它的源程序文件中使用时,这种函数称为外部函数。

定义外部函数的方法是:在定义函数时,在函数的类型名前加修饰词extern 。若省略extern时,C++编译器也约定为外部函数。设一个程序文件中的程序片段为:

......

extern int f1()

{

......

}

......

float f2()

{

......

}

其中函数f1()和f2()均为外部函数。

多文件组织方式中,在一个文件中要调用在另一个程序文件中定义的外部函数前,必须对被调用的函数作原型说明,并在函数原型说明的前面加上修饰词extrn。设在程序文件c1.cpp中定义了函数f1():

int f1(float x, float y) //函数定义

{

...... //函数体的定义

}

在程序文件c2.cpp 中要调用文件c1.cpp中定义了函数f1(),则在调用前增加如下形式的函数原型说明:

extrn int f1(float , float ); //函数原型说明

......

i= f1(x,y); //调用函数f1()

在程序的多文件组织中,有关全局变量的使用方法与函数的用法类同,即在定义全局变量时,若在说明变量的类型前加上修饰词 static,表示所定义的全局变量只能在所定义的文件中使用;而不加修饰词static或加上修饰词extrn,则允许所定义的全局变量在其它程序文件中使用。在一个文件中要用到另一个文件中定义的全局变量时,要对其进行外部变量说明。例如,设文件t.cpp的内容为:

extern float x=2.71828; //也可省略修饰词extern

设文件tt.cpp的内容为:

#include

void main(void)

{

extern float x; //说明x为外部变量

cout << "x="<

}

在这个例子中,文件tt.cpp中用到了在文件t.cpp中说明的全局变量x。这二个程序文件经编译连接,并执行程序后的输出为:

x=2.71828

5.9.2 多文件组织的编译和连接

当一个完整的程序由多个源程序文件组成时,如何将这些文件进行编译并连接成一个可执行的程序文件呢?对于不同的计算机系统,其处理的方法可能是不同的。 通常有以下几种处理方法:

1、用包含文件的方式,在定义 main()函数的文件中将组成同一程序的其它文件用包含指令包含进来,由编译程序对这些源程序文件一起编译,并连接成一个可执行的文件。对于编写一些不大的程序时,可以采用这种方法进行编译和连接。但当编写大的程序时,不宜采用这种方法。因对任一文件中的微小修改,均要重新编译所有的文件,然后才能连接。

2、将各个源程序文件单独编译成目标程序, 然后用操作系统或编译器提供的连接程序将这些目标程序文件连成一个可以执行的程序文件。

3、使用工程文件的方法,将组成一个程序的所有文件都加到工程文件中,由编译器自动完成多文件组织的编译和连接。如在 VC++中,可有多种方法建立工程文件。一种方法是先为包含 main()函数的文件建立一个工程文件,然后选择主菜单上的“Project”菜单,再选择 Project 菜单中的子菜单“Add toproject”,再选择其子菜单“Files”,将其它的程序文件加入到工程文件中。这时,对多个文件的编译和连接方法,与一个文件组成一个程序的方法完全相同。有关工程文件的更详细的说明,可查阅有关的手册。

当设计编写大程序时,建议使用这种方法。因为当修改某一个源程序文件时,编译器仅编译已修改的源程序文件,而没有必要对其它源程序文件重新编译,所以可以提高编译和连接的效率。

习题与思考5

1.输入三个整数,求出其中的最大数并输出。用函数求出二个数中的最大数。2.计算组合数:C(m,r)= m!/(r!×(n-r)!),其中m,r为正整数,且m>r。分别求出C(4,2),C(6,4),C(8,7)的组合数。求阶乘和组合数用函数实现。3.输入一个十进制整数,输出相应的十六进制数。设计一个函数实现数制转换。4.求出5~100之间的所有素数,要求每行输出5个素数。判断一个整数是否为素数用一个函数来实现。

5.输入二个整数,求出这二个整数的最小公倍数。求二个数的最小公倍数用一个函数来实现。

6.输入二个整数,求出这二个整数的最大公约数。求二个数的最大公约数用一个函数来实现。

7.通过重载求二个数中大数的函数max(x,y),分别实现求二个实数和二个整数的大数。

8.用内联函数实现求出三个实数中的最大数,并输出最大数。

9.定义一个求n!的函数,n的缺省值为10。

10.设计一个参数数目可变的函数,第一个参数n为参数的个数。求出这n个实参之和并输出。

11.设计一个参数数目可变的函数,第一个参数n为参数的个数。调用这函数时,若n的值为3,则求出后三个实参之积并返回这值;若n的值为4,则求出后四个实参的平均值并返回这个值。

12.用递归函数实现求Fibonnaci数列的前n项,n作为函数的参数。

13.当x>1时,Hermite多项式定义为:

1 n=0

(x)= 2x n=1

Hn ⎨

⎪ n>1

⎩2xHn=1(x)−2(n−1)Hn−2(x)

当输入实数x和整数n后,求出Hermite多项式的前n项的值。分别用递归函数和非递归函数实现。

14.阿克曼函数定义为:

n+1 m=0

Acm(m,n)= Acm(m−1,1) n=0

Acm(m−1,Acm(m,n−1)) n>0,m>0

其中m,n为正整数,分别求出Acm(5,3)、Acm(4,2)和Acm(5,5)的值。15.输入一个整数,实现逐位正序和反序输出。如输入一个整数3456,则输出3456和6543。分别设计二个函数,一个实现正序输出;另一个实现反序输出。算法提示:重复除以10求余,直到商为0为止。如3456%10的余数为6,商为345。345%10的余数为5,商为34。34%10的余数为4,商为3。3%10的余数为3,商为0。至此结束。先输出余数,后递归,则为反序输出。先递归后输出余数,则为正序输出。

16.将求二个实数的最大值函数放在一个头文件“myfun.h”,在源程序文件“mypro.cpp”中包含这个头文件,并实现输入三个实数,求出最大值。

17.定义带参数的宏MAX(A,B)和MIN(A,B),分别求出二数中的大数和小数。在主函数中输入三个数,求出这三个数中的最大数和最小数。

18.已知三角形的三条边a,b,c,则三角形的面积为:

area= s(s−a)(s−b)(s−c)

其中s=(a+b+c)/2。分别用带参宏和函数求三角形的面积。

19.自己设计一个程序,使用条件编译输出调试信息。