C++程序设计课件 设计制作:徐龙琴 2
?掌握 外部存储类型 和 静态存储类型 在多文件中 作用
?理解 作用域, 可见性, 生命期, 多文件结构 及 编译
预处理 的 概念
?学会 使用头文件
本章要点:
C++程序设计课件 设计制作:徐龙琴 3
§ C++程序结构
一个较小规模的程序,常用一个源文件(,cpp和,h)来实现。
但 大程序 多将其 分解为 多个源文件 。其 好处是:
① 便于功能 的 划分,便于程序的 调试 。
② 可以 避免重复编译 。(因为编译是以文件为单位的,若程序
只有一个源文件,若改动了其某个函数,则整个源文件都得
重新编译。)
③ 可以把相关的函数放到一个源文件中
不管 大程序分解为 多少个源文件,其中 有且仅有 一个文件 中 包含
一个函数 main( ) 。 每个源文件分别编译,再通过连接程序把它们及程序中
用到的库函数连接成一个可执行的程序。
C++程序设计课件 设计制作:徐龙琴 4
例, 编写求两个自然数 m和 n的最大公约数和最小公倍数。 (用
函数调用来实现。 )
//主函数,cpp
#include <stdio.h>
unsigned int yue(unsigned int x,
unsigned int y);
void main ( )
{unsigned int m,n,b,y;
scanf ("%u%u",&m,&n);
b=m*n;
y=yue(n,m);
printf ("%u,%u\n",y,b/y);
}
//最大公约数,cpp
unsigned int yue(unsigned int x,
unsigned int y)
{int t;
if (x<y)
{ t=x;
x=y;
y=t;}
while (y!=0)
{t=x%y;
x=y;
y=t;}
return x;}
C++程序设计课件 设计制作:徐龙琴 5
总结 C++程序结构,
① 逻辑上,一个 C++程序 由 一些 函数 和一些 全局 (外部) 变
量 或 对象 构成, 其中必须 有且仅有 一个名字为 main
的函
数,整个 程序 从函数 main开始 执行直到其结束 。
② 物理上,一个 C++程序 可以放在 一个或多个源文件 (模块)
中,源文件的文件名以,cpp和,h作为扩展名,每个文
件 包
含 一些函数和全局变量或对象的定义,其中有且仅有
一个
C++程序设计课件 设计制作:徐龙琴 6
§ 6.1外部存储类型
若想在程序 某个源文件 中 用 该程序其它源文件 定义的
全局变量 或 函数, 要用 exterm对其声明。
//file2.cpp
int y=0;
static char c='A';
f()
{,..y,.,//Ok
...c,.,//Ok
...x,.,/Error,x未声明
...z,.,/Error,z未声明
}
double z=2;
g( )
{,..z,.,//Ok}
例:
//file1.cpp
int x=1;
extern int y;
void main()
{,..x,.,//Ok
...y,.,//Ok
...z,.,//Error,z未声明
...c,.,//Error,c不可使用
}
C++程序设计课件 设计制作:徐龙琴 7
① 本文件中, 在 定义前要使用全局变量, 可用 extern对变量作引用说明 。
例,extern int n; //对全局变量 n作 引用性 说明
void t1(int a,int b)
{ … 使用全局变量 n …
}
……
int n; //对全局变量 n作 定义
② 在同一项目(程序)的 其它源程序文件中定义的全局变量,通过 extern 说
明后,可在该文件中使用,
extern的用法:
C++程序设计课件 设计制作:徐龙琴 8
§ 6.2 静态存储类型
变量 的 静态存储类型有,全局 变量和 静态 变量,它门
都 存方在 内存的全局数据区。都在 定义 时开辟 存储 空间,程序
结束时释放存储空间 ; 生命周期均 为程序运行期间。 其值都具
有继承性且其默认的初值为 0。
函数 按 其 存储类型 也可以 分为 两类,内部 函数和 外部 函数
1.内部函数,是 只能在定义它的文件中被调用 的函数,而
在同一程序的 其他文件中不
可调用 。内部函
数 定义时,在函数类型 前
加 static,所以也
称为静态函数。
C++程序设计课件 设计制作:徐龙琴 9
⑴ 静态函数格式如下:
static 函数类型 函数名(参数列表)
{ 函数体 }
内部函数的 作用域 只限
于 定义它的文件,所以在 同一个
程序的不同文件中可以有相同命
名的函数,它们互不干 扰。
例,静态函数的例子。
//文件 file1.cpp中
#include <iostream.h>
static void fun( );
void main( )
{ fun( ); }
static void fun( )
{ cout<<"this in file1 "<<endl; }
C++程序设计课件 设计制作:徐龙琴 10
⒉ 外部函数,是可以在 整个程序各个文件中被调用的函数 。
外部函数定义时,在函数类
型前加 extern,格
式如下:
如果定义时 没有声明函数的存储类型,系统 默认为 extern型。
extern <函数类型 > <函数名 > (<参数列表 >)
{ <函数体 > }
C++程序设计课件 设计制作:徐龙琴 11
? 通过 static对函数进行文件作用域的限定,可
以避免不同文件使用相同函数名引起的冲突
文件 1:
extern func32();
static func11(){}
func12(){}
func13(){}
文件 2:
func21(){}
static func22(){}
func23(){}
文件 3:
extern func12();
func31(){}
func32(){}
func33(){}
仅限“文件 1”中
调用
仅限“文件 2”中
调用
调用“文件 3”
中的 func32()
调用“文件 1”
中的 func12()
C++程序设计课件 设计制作:徐龙琴 12
§ 6.3 作用域
C++的 作用域有下面 4种,
1,程序级,构成程序的 所有源文件 。
2,文件级,定义 标识符的源文件 。
3,函数级, 定义标识符的函数 。
4,局部级, 定义标识符 的 复合语句 或 分程序 。
在一个标识符的作用域中 使用该标识符时, 如果 未见
到 该标识符的 定义, 则 在 使用前 往往 需要声明 之 。
C++程序设计课件 设计制作:徐龙琴 13
例, //file1.cpp
#include <iostream.h>
int x; //程序 级
static int y; //文件 级
void main()
{ int x; //函数 级
… …
if (int y=a) //局部 级
… …
}
C++程序设计课件 设计制作:徐龙琴 14
§ 6.4~ 6.5 可见性和生命期
⒈ 可见性,某 标示符 在某个位置 可见, 表示 该 标示符可被引
用 。 可见性是 分析某位置标示符的有
效性 。 在
内层作用域中, 外层的同名标示符是不可
见的, 即
内部变量能屏蔽外层定义的同名变量 。
注意,在同名内部变量作用范围内,对外部变量的存取可用
作用域运算符,:
int n=10;
void t1(int n,int m)
{ ……
cout<<“n=“<<n;
cout<<“n=“<<::n; }
例:
C++程序设计课件 设计制作:徐龙琴 15
⒉ 生命期, 变量的生存期是指变量占用内存的时间段,或变量
存在的时间段 。 全局变量 和 静态变量 的 生存期 都 是
整个程序运行期间; 局部变量和形式参数 的 生存期
一般为函数被调用期间; 生存期 与 存储区 密切相关,
存储区主要有,代码区、全局数据区、堆区、栈区。
对应的 生命其为,静态 生命期,局部 生命期和 动态
生命期。
⑴ 静态生命期
它 与程序的运行期相同 。凡存放在 全局数据
区的变量 都具有 静态生命期 。静态生命期的变量 无初始
化时 其默认值为 0
C++程序设计课件 设计制作:徐龙琴 16
⑵ 局部生命期
形参 和 局部变量 都 具有 局部生命期,其生命期
开始于 程序执行经过其声明点,结束 其作用域结束处。局
部生命期的变量 存放在 栈区。
⑶ 动态生命期
动态生命期的变量 存放在 堆中,当 用函数
malloc()或操作符 new为变量分配空间时,生命期开始,
当用函数 free()或操作符 delete释放变量的空间时,生命
期结束。
C++程序设计课件 设计制作:徐龙琴 17
例,生存期的例题
#include <iostream.h>
int f(int a) //a的生存期为函数 f被调用期间
{ int x=0; // x的生存期为函数 f被调用期间
static int y=1; //y的生存期为整个程序运行期间
x++;
y++;
return (a+x+y); }
void main( )
{ int x,y;
x= 2;
y= 2;
cout<<f(x)<<,” << f(y) ;
}
运行的结果为:
5 6
C++程序设计课件 设计制作:徐龙琴 18
? 存储类别小结
性 能 自动变量 外部变量 外部静态 内部静态 寄存器变量
记忆能力
多个函数共享
在不同文件共享性
未显示赋值的取值
作用域
无 有 有 有 无
否 可 可 否 否
否 可 否 否 否
不定 0 0 0 不定
当前函数 整个程序 文件 函数 当前函数
C++程序设计课件 设计制作:徐龙琴 19
§ 6.6 头文件
◇ C++提供了大量的库函数, 这些库函数分类放在不同的,h文
件, 即头文件 。 在调用这些库函数时必需用文件 包含指令
#include 将其所在的头文件包含进来,格式为:
#include < 文件名 > //从 include目录中查找头文件
#include,文件名, //先从当前目录中查找,没有再从 include找
编译前 将头文件中所用内容 复制 到该文件 中,然后 进行 编译 。
C++程序设计课件 设计制作:徐龙琴 20
例如,①数学中:求指数、对数、绝对值、三角函数等放在
math.h头文件中
②判断字母、数字、大写字母、小写字母函数放在
ctype.h文件中
③字符串处理函数放在 string.h文件中;
④屏幕处理函数放在 conic.h中;
⑤图形处理函数放在 graph.h等
C++程序设计课件 设计制作:徐龙琴 21
通常, 在 一个源文件中定义的, 允许在其它源文件中
使用的全局变量, 函数等, 常把 它们的声明放在某个 xxx.h头文
件 中, 在需要使用这些变量及函数的源文件中写上,#include
"xxx.h"例:
// file1.cpp
#include "file.h"
int x=1;
int y=0;
main()
{...x,..
...g( ),..
...z,..
f( ); }
// file.h
extern int x;
extern int y;
extern double z;
f();
g();
//file2.cpp
#include "file.h"
static char c='A';
f()
{,.x,..
...y,..
...c,..
}
double z=2;
g( )
{,..z,..}
C++程序设计课件 设计制作:徐龙琴 22
例, 用程序一次输出课本 4.9的后两个图:
// tab2.cpp
#include <iostream.h>
#include <iomanip.h>
void tab2()
{ cout <<" *";
for(int k=1; k<=9; k++)
cout <<setw(4) <<k;
cout <<"\n -------------------- "
<< " --------------------- \n";
for(int i=1; i<=9; i++){
cout <<setw(3) <<i;
for(int j=1; j<=i; j++)
cout <<setw(4) <<i*j;
cout <<endl; }
cout <<endl <<endl; }
// tab3.cpp
#include <iostream.h>
#include <iomanip.h>
void tab3()
{ cout <<" *";
for(int k=1; k<=9; k++)
cout <<setw(4) <<k;
cout <<"\n------------------ "
<< " -----------------------\n";
for(int i=1; i<=9; i++){
cout <<setw(3) <<i;
if(i!=1)
cout <<setw(4*i-4) <<" ";
for(int j=i; j<=9; j++)
cout <<setw(4) <<i*j;
cout <<endl;}
cout <<endl <<endl;}
//main,cpp
void tab2();
void tab3();
void main()
{ tab2();
tab3();}
C++程序设计课件 设计制作:徐龙琴 23
例, 头文件一次输出课本 4.9的后两个图:
// tab2.cpp
#include "tt.h"
void tab2()
{ cout <<" *";
for(int k=1; k<=9; k++)
cout <<setw(4) <<k;
cout <<"\n -------------------- "
<< " --------------------- \n";
for(int i=1; i<=9; i++){
cout <<setw(3) <<i;
for(int j=1; j<=i; j++)
cout <<setw(4) <<i*j;
cout <<endl; }
cout <<endl <<endl; }
// tab3.cpp
#include "tt.h"
void tab3()
{ cout <<" *";
for(int k=1; k<=9; k++)
cout <<setw(4) <<k;
cout <<"\n------------------"
<< " -----------------------\n";
for(int i=1; i<=9; i++){
cout <<setw(3) <<i;
if(i!=1)
cout <<setw(4*i-4) <<" ";
for(int j=i; j<=9; j++)
cout <<setw(4) <<i*j;
cout <<endl;}
cout <<endl <<endl;}
//tt.h
#include <iostream.h>
#include <iomanip.h>
void tab2();
void tab3();
//main,cpp
#include "tt.h"
void main()
{ tab2();
tab3();}
C++程序设计课件 设计制作:徐龙琴 24
§ 6.8 编译预处理
编译预处理 是指 在程序进行编译之前, 先执行的预处理
命令 。 C++的 预处理命令 都是 以, #”开头, 末尾 不加分号 的
命
令 。 常用的 预处理命令 有 宏定义, 文件包含 和 条件编译 。⒈ 宏定义, 包含 无参 和 有参 宏定义
⑴ 无参宏定义格式,#define 宏名 字符串
注,在 编译 预处理 时,将 宏名 用 字符串替换 。 宏名 通 常
用 大写 以区别于变量名。
至少有一个空格至少有一个空格
C++程序设计课件 设计制作:徐龙琴 25
例,无参宏定义的例子
//源程序
#include <iostream.h>
#define PI 3.1415927
void main( ){
float r,l,s;
cout<<“输入圆半径,” ;
cin>>r;
l=PI*2*r; s=PI*r*r;
cout<<“圆周长” <<l<<endl;
cout<<“圆面积, <<s<<endl;
}
//预编译后
#include <iostream.h>
#define PI 3.1415927
void main( ){
float r,l,s;
cout<<“输入圆半径,” ;
cin>>r;
l= 3.1415927 *2*r;
s= 3.1415927 *r*r;
cout<<“圆周长” <<l<<endl;
cout<<“圆面积, <<s<<endl;
}
C++程序设计课件 设计制作:徐龙琴 26
//源程序
#include <iostream.h>
#define PI 3.1415927;
void main( ){
float r,l,s;
cout<<“输入圆半径,” ;
cin>>r;
l=PI*2*r; s=PI*r*r;
cout<<“圆周长” <<l<<endl;
cout<<“圆面积, <<s<<endl;
}
//预编译后
#include <iostream.h>
#define PI 3.1415927
void main( ){
float r,l,s;
cout<<“输入圆半径,” ;
cin>>r;
l= 3.1415927; *2*r;
s= 3.1415927; *r*r;
cout<<“圆周长” <<l<<endl;
cout<<“圆面积, <<s<<endl;
}
加入
分号!
编译
时出
错!
C++程序设计课件 设计制作:徐龙琴 27
例,嵌套宏替换:
#define PI 3.14
#define R 5
#define D 2*R
#define L PI*D
#define S PI*R*R
void main( )
{ cout<<“设圆半径是, <<R<<endl;
cout<<“圆周长是, <<L<<endl;
cout<<“圆面积是, <<S<<endl;
}
相当于,2*5
相当于,3.14*2*5
相当于,3.14*5*5
C++程序设计课件 设计制作:徐龙琴 28
⑵ 有参宏定义格式, #define 宏名 (参数表 ) <字符串 >
注,在 编译预处理时,将 宏名 用 字符串中与参数表相同的字
符序列替换
例,#define M(x,y) x+y
#define N(x,y) x-y
计算,int I=M(1,2+3 ) * 3 / N(4+2,2 )
替换结果,x y x y
I= x + y * 3 / x - y1 2+ 3 4+ 2 2 = 5
注意:
① 采用宏定义时, 如果一行写不下, 在本
行最后用续行符, \”转到下一行 。
② 宏定义是文本替换, 应加上必要的括号
C++程序设计课件 设计制作:徐龙琴 29
#define M(x,y) x+y
#define N(x,y) x*y
#define M(x,y) ( x+y)
#define N(x,y) ( x*y)
#define M(x,y) (( x) +( y))
#define N(x,y) (( x) *( y))
I= x + y * 3 / x * y1 2+3 4+2 2
I= ( x + y ) * 3 / ( x * y )1 2+3 4+2 2
I= ( x + y ) * 3 / ( x * y )(1) (2+3) (4+2) (2)
例,比较计算 I=M(1,2+3 ) * 3 / N(4+2,2 )
C++程序设计课件 设计制作:徐龙琴 30
例,宏定义的例子:
#include<iostream.h>
void main( )
{ int B=5; //定义了一个变量 B,其值为 5
#define B 2 //用简单宏定义定义了一个符号常量 B
#define f(x) B*(x) //用带参数的宏定义定义了一个宏 f(x)
int y =3;
cout<<f(y+1)<<endl; //在各种不同的情况下调用该宏
#undef B //取消对符号常量 B的宏定义
cout <<f(y+1)<<endl;
#define B 3 //再次用简单宏定义定义符号常量 B
cout <<f(y+1)<<endl;
}
运行的结果为:
8
20
12
C++程序设计课件 设计制作:徐龙琴 31
⒉ 文件包含,用于将一个文件的内容全部插入到程序的编译预
处理命令位置。
① 文件包含指令的 格式为:
#include < 文件名 > //从 include目录中查找头文件
#include,文件名, //先从当前目录中查找,没有再从 include找
② 含义:
用文件名所指定的文件内容替代该命令。
C++程序设计课件 设计制作:徐龙琴 32
⒉ 条件编译,用于 定义某些编译内容在满足一定条件时才能参
加编译。 其 格式为:
① 格式 1,#ifdef <标识符 >
<程序段 1>
#else
<程序段 2>
#endif
当 标识符已被定义过时,则 编译程序段 1,否则 编译程序段 2。
C++程序设计课件 设计制作:徐龙琴 33
② 格式 2,#ifndef <标识符 >
<程序段 1>
#else
<程序段 2>
#endif
当 标识符未被定义过,则 编译程序段 1,否则编译程序段 2
③ 格式 3,#if <常量表达式 1> <程序段 1>
#elif <常量表达式 2> <程序段 2>
#elif <常量表达式 3> <程序段 3>
┇
#else <程序段 n+1>
#endif
哪个 表达式值为真,就 编译哪个程序段,没有真的编译 程序段 n+1
C++程序设计课件 设计制作:徐龙琴 34
例,条件编译的例子:
#include <iostream.h
#define R 1
void main()
{
float c,r,s;
cout<<"input a number,"<<endl;
cin>>c;
#if R
r=3.14159*c*c;
cout<<"area of round is:"<<r<<endl;
#else
s=c*c;
cout<<"area of square is"<<s<<endl;
#endif
}
C++程序设计课件 设计制作:徐龙琴 35
§ 程序举例
例, 分析下列程序的运行结果。
/* 文件一 */
#include, stdio.h”
static int x = 2;
int y = 3;
void main ( )
{ extern void add2( );
void add1( );
add1( ); add2( );
add1( ); add2( );
printf ("x=%d,y=%d\n",x,y);}
void add1( )
{ x += 2; y += 3; printf ("in add1 x=%d\n",x);}
/* 文件二 */
#include, stdio.h”
static int x=10;
void add2( )
{ extern int y;
x += 10;
y += 2;
printf ("in add2 x=%d\n",x);}
in add1 x=4
in add2 x=20
in add1 x=6
in add2 x=30
x=6,y=13
运行的结果,
C++程序设计课件 设计制作:徐龙琴 36
例,输入的四个数按从大到小排序并输出(注:用两个文件来实
现,一个文件含主函数,另一个文件实现对两个数的排序。)
// swap.cpp
void swap(float &x,float &y)
{ float t;
if(x<y)
{t=x;
x=y;
y=t;}
}
// main.cpp
#include "iostream.h "
void swap(float &x,float &y);
void main( )
{ float a,b,c,d;
cout<< "请输入四个数, " ;
cin>>a>>b>>c>>d;
if(a<b) swap(a,b);
if(a<c) swap(a,c);
if(a<d) swap(a,d);
if(b<c) swap(b,c);
if(b<d) swap(b,d);
if(c<d) swap(c,d);
cout<<a<< "," <<b<< "," <<c<< "," <<d;}
C++程序设计课件 设计制作:徐龙琴 37
例,三角形的面积为,area=sqrt(s*(s- a)* (s- b)* (s- c)),其中
s=(a+b+c)/2,a,b,c为三角形的三边。定义两个带参的宏,一
个用来求 s,另一个用来求 area。试编程实现。
#include <iostream.h>
#include <math.h>
#define S(a,b,c) (a+b+c)/2
#defineAREA(a,b,c) sqrt(S(a,b,c)*(S(a,b,c)-a)*(S(a,b,c)-b)*(S(a,b,c)-c))
void main()
{ float a,b,c;
cout<<"Input a,b,c:";
cin>>a>>b>>c;
if(a+b>c&&a+c>b&&b+c>a)
cout<<"area="<<AREA(a,b,c)<<endl;
else
cout<<"Not a triangle!"<<endl;}
C++程序设计课件 设计制作:徐龙琴 38
例, M为 1编译输出, M is 1”,如果 M为 2编译输出, M is 2”,否则
编译输出 "M is other"。
#include <iostream.h>
#define M 10
void main( )
{
#if M==1
cout<<"M is 1"<<endl;
#elif M==2
cout<<"M is 2"<<endl;
#else
cout<<"M is other"<<endl;
#endif
}
程序运行结果如下:
M is other