1、空间域空间域:一个类型或量值,从程序的什么位置到什一个类型或量值,从程序的什么位置到什么位置是有效的,是可以引用的,是占据内存么位置是有效的,是可以引用的,是占据内存的。的。时间域时间域:一个类型或量值,在程序执行过程中,从一个类型或量值,在程序执行过程中,从什么时刻开始到什么时刻是占据内存的。什么时刻开始到什么时刻是占据内存的。第第6章名词的空间域、时间域和物理存储位置章名词的空间域、时间域和物理存储位置 名词的空间域和时间域不完全一致名词的空间域和时间域不完全一致。有空间域的类型或量值,一定有时间域。有空间域的类型或量值,一定有时间域。即在程即在程序的某位置可以访问的类型或量值,此时一定序
2、的某位置可以访问的类型或量值,此时一定占据内存;占据内存;有时间域的类型或量值,不一定有空间域。有时间域的类型或量值,不一定有空间域。即有即有的时候,程序执行到某个位置,某个类型或量的时候,程序执行到某个位置,某个类型或量值虽然占据内存,但无法访问,即在该位置不值虽然占据内存,但无法访问,即在该位置不可见。可见。6.1 C/C+程序的逻辑结构程序的逻辑结构程序从小到大可分为如下逻辑单位:程序从小到大可分为如下逻辑单位:语句(语句(statementstatement):分号结束分号结束 2.2.模块(模块(blockblock):一对花括号括起的若干语句。一对花括号括起的若干语句。3.3.嵌套
3、模块嵌套模块:1.1.多对花括号的嵌套。多对花括号的嵌套。4.4.文件(文件(filefile):程序的存盘单位。文件中通常包含多个模块(或嵌程序的存盘单位。文件中通常包含多个模块(或嵌套模块),每个模块内包含多个语句。套模块),每个模块内包含多个语句。5.5.工程(工程(projectproject):工程是功能单位,是对多个文件进行组织和管理的工程是功能单位,是对多个文件进行组织和管理的框架。同一个工程内的文件之间可以交换数据,共享框架。同一个工程内的文件之间可以交换数据,共享函数。函数。6.6.工作区(工作区(workspaceworkspace):工作区是工作区是VC+VC+最大的开发
4、单位,是对多个工程进行最大的开发单位,是对多个工程进行组织和管理的框架。一个工作区内的多个工程应该是组织和管理的框架。一个工作区内的多个工程应该是相关的。不同工程间可以共享文件。相关的。不同工程间可以共享文件。图6.1 C/C+程序逻辑结构6.2名词性的类型和量值在各逻辑结构上的空间域名词性的类型和量值在各逻辑结构上的空间域 6.2.16.2.1模块域模块域模块模块 是空间作用域的最小范围。是空间作用域的最小范围。缺省情况下,定义在模块内(一对花括号内)缺省情况下,定义在模块内(一对花括号内)的类型和量值,其有效范围是从定义位置到本的类型和量值,其有效范围是从定义位置到本模块结束。出本模块右花
5、括号后,该类型或量模块结束。出本模块右花括号后,该类型或量值因为释放内存空间而失效,无法访问。值因为释放内存空间而失效,无法访问。例例6.1 量值模块作用域的验证量值模块作用域的验证#include int fun(int x)void main()int a=10;int b;printf(a=%dn,a);b=fun(a);printf(a=%d,b=%dn,a,b);调用调用fun函数,函数,a(10)为实参)为实参fun函数的声明函数的声明int fun(int x)int a=20;printf(a=%d,x=%dn,a,x);return a+x;fun内定义的内定义的a只在只在f
6、un内有效内有效返回返回a+x的值的值(20+10)a=10a=20,x=10a=10,b=30Press any key to continuemain()中的输出中的输出fun()中的输出中的输出main()中的输出中的输出例例6.1 量值模块作用域的验证量值模块作用域的验证#include int fun(int x)void main()int a=10;int b;printf(a=%dn,a);b=fun(a);printf(a=%d,b=%dn,a,b);printf(“x=%dn,x);调用调用fun函数,函数,a(10)为实参)为实参fun函数的声明函数的声明编译出错:编译出
7、错:error C2065:x:undeclared identifierint fun(int x)int a=20;printf(a=%d,x=%dn,a,x);printf(b=%dn,b);return a+x;fun内定义的内定义的a只在只在fun内有效内有效返回返回a+x的值的值(20+10)编译出错:编译出错:error C2065:b:undeclared identifier例例6.2 类型模块作用域的验证类型模块作用域的验证#include Person fun();Person fun()struct Person int id;char name10;ZS=1,张三张三
8、;return ZS;void main()Person LiSi;LiSi=fun();fun内定义的类型内定义的类型Person,只在只在fun内有效内有效在在main函数内声明一个在函数内声明一个在fun函数内定义的函数内定义的Person类型的变类型的变量量LiSi,编译出错,编译出错声明声明Person类型的类型的变量变量ZS,并赋值并赋值例例6.2 类型模块作用域的验证类型模块作用域的验证#include struct Person int id;char name10;Person fun();void main()Person LiSi;LiSi=fun();printf(id
9、=%dn,LiSi.id);printf(name=%sn,LiSi.name);Person fun()Person ZS=1,张三张三;return ZS;id=1name=张三Press any key to continue6.2.26.2.2嵌套模块的层域嵌套模块的层域 当一个模块内嵌套另一个模块时,定义在内层模当一个模块内嵌套另一个模块时,定义在内层模块的类型和量值的空域就是内层模块;块的类型和量值的空域就是内层模块;定义在外层模块内的类型和量值的空域是外层模定义在外层模块内的类型和量值的空域是外层模块,当然涵盖内存模块,即在内层模块内可以引用定块,当然涵盖内存模块,即在内层模块内
10、可以引用定义在外层模块内的类型和量值。义在外层模块内的类型和量值。当内层模块内定义了和外层模块内同名的类型和当内层模块内定义了和外层模块内同名的类型和量值时,量值时,内层的类型和量值覆盖了外层模块的同名类内层的类型和量值覆盖了外层模块的同名类型和量值,型和量值,导致只能引用内层中定义的部分。导致只能引用内层中定义的部分。例例6.3 嵌套模块中的同名类型或量值的空间域嵌套模块中的同名类型或量值的空间域#include void main()struct Person int id;char name10;struct Date int year;int month;int day;main函数内
11、(外层模块)函数内(外层模块)定义的定义的Person类型类型main函数内(外层模块)函数内(外层模块)定义的定义的Date类型类型Person ZS;/内嵌模块开始内嵌模块开始struct Person int id;char name10;int Class;Person LiSi;Date Birthday;printf(sizeof(LiSi)=%dn,sizeof(LiSi);/内嵌模块结束内嵌模块结束printf(sizeof(ZS)=%dn,sizeof(ZS);printf(%d,sizeof(LiSi);声明外层模块定义的声明外层模块定义的Person类型的变量类型的变量Z
12、S内、外层定义了同名的内、外层定义了同名的Person类型,类型,LiSi是内层是内层的的Person类型的变量类型的变量内层模块定义的同名内层模块定义的同名Person类型,成员不同类型,成员不同声明外层模块定义的声明外层模块定义的Date类型的变量类型的变量Birthday,外,外层定义,内层可见层定义,内层可见在内层输出内层在内层输出内层Person类类型变量型变量LiSi的大小的大小在外层输出外层在外层输出外层Person类型变量类型变量ZS的大小的大小在外层输出内层在外层输出内层Person类型变量类型变量LiSi的大小,编译出错的大小,编译出错sizeof(LiSi)=20size
13、of(ZS)=16Press any key to continue6.2.36.2.3文件域文件域程序的所有代码都是写在文件中的。程序的所有代码都是写在文件中的。用用C/CC/C编写程序,最少要有一个文件。编写程序,最少要有一个文件。在文件内定义的类型或量值(在文件内定义的类型或量值(注意:不包含在任何模注意:不包含在任何模块中,而是直接定义在文件中块中,而是直接定义在文件中)的空间域是从定义位)的空间域是从定义位置开始,到本文件的结束。本文件内,在定义该类型置开始,到本文件的结束。本文件内,在定义该类型或量值后面的或量值后面的任何模块内或模块外任何模块内或模块外,都可以引用该类,都可以引用
14、该类型或量值。型或量值。类型只能定义在前,引用在后类型只能定义在前,引用在后。变量变量通常通常定义在前,引用在后。定义在前,引用在后。变量如果定义在后,引用在先,必须在引用前明确用变量如果定义在后,引用在先,必须在引用前明确用关键字关键字externextern声明。声明。例例6.4 文件中定义的类型或量值的空间域文件中定义的类型或量值的空间域#includestruct Person int id;char name10;int i;定义在文件中定义在文件中的的Person类型类型定义在文件中定义在文件中的的int型变量型变量ivoid main()Person ZS=1,张三张三;i=10
15、;printf(i=%dn,i);printf(“id=%d name=%sn,ZS.id,ZS.name);在在main函数的外层模块函数的外层模块中声明一个中声明一个Person类型类型的变量的变量ZS,并赋值,并赋值在在main函数的内层模块中函数的内层模块中引用整型变量引用整型变量i,并赋值,并赋值i=10id=1 name=张三Press any key to continue一个编译出错的示例程序一个编译出错的示例程序:程序中,将程序中,将Person类型的定义写在文件类型的定义写在文件的后端的后端,而文件前端的而文件前端的main函数模块内函数模块内,引用了后面才定义的引用了后面
16、才定义的Person类型。程序编类型。程序编译出错。译出错。#includeint i;void main()Person ZS=1,张三张三;i=10;printf(i=%d,i);printf(%d%sn,ZS.id,ZS.name);struct Person int id;char name10;在在main函数的外层模块中函数的外层模块中声明一个定义在文件后面声明一个定义在文件后面的的Person类型的变量类型的变量ZS,并赋值。编译出错并赋值。编译出错定义在文件后面的定义在文件后面的Person类型类型用用extern声明定义在后的变量的情况。声明定义在后的变量的情况。例例6.6
17、变量的先声明,再应用,而后定义变量的先声明,再应用,而后定义#include#includestruct Person int id;char name10;定义在文件前面的定义在文件前面的Person类型类型void main()extern int i;i=10;extern Person ZS;ZS.id=1;strcpy(ZS.name,张三张三);printf(i=%dn,i);printf(“id=%d name=%sn,ZS.id,ZS.name);Person ZS;int i;定义在文件后面的变量定义在文件后面的变量i,ZS声明在文件后面定义的变量声明在文件后面定义的变量i声
18、明在文件后面定义的变量声明在文件后面定义的变量ZSi=10id=1 name=张三Press any key to continue#include#includestruct Person int id;char name10;void main()Person ZS=1,张三张三;int i=10;printf(i=%dn,i);printf(%d%sn,ZS.id,ZS.name);extern int j;j=200;printf(“j=%dn,j);int j;出错出错原因原因:”定义在后,重定义在后,重新声明,然后引用新声明,然后引用”的的规则模块外(文件内)规则模块外(文件内)的
19、全局变量在模块内引的全局变量在模块内引用的规则,不能应用于用的规则,不能应用于模块内声明的局部变量。模块内声明的局部变量。注意注意:”定义在后,重定义在后,重新声明,然后引用新声明,然后引用”的的规则不适合类型,只适规则不适合类型,只适合变量。合变量。6.2.46.2.4工程域工程域工程中可以有多个文件工程中可以有多个文件每个文件中可以有多个全局的类型、全局的量值和全每个文件中可以有多个全局的类型、全局的量值和全局的函数模块局的函数模块函数模块内可以有多个局部的类型和局部的量值。函数模块内可以有多个局部的类型和局部的量值。局部的类型和量值的空间域限制在它所在的模块,不局部的类型和量值的空间域限
20、制在它所在的模块,不会影响到同一个工程中的其它文件。会影响到同一个工程中的其它文件。能够在一个工程中的多个文件之间相互影响的是一个能够在一个工程中的多个文件之间相互影响的是一个文件内的全局类型、全局量值和全局函数模块。文件内的全局类型、全局量值和全局函数模块。例例6.7工程内全局类型和量值空间域(工程内全局类型和量值空间域(包含包含3个文件个文件)(1)在在VC中创建中创建Win32 Console Application工程工程MyMFile(系统会自动添加文件扩展名(系统会自动添加文件扩展名.dsw)(2)创建创建C+Source File文件文件MyMFile0(系统会自动添加(系统会自
21、动添加文件扩展名文件扩展名.cpp),文件内容如下:),文件内容如下:int MyMax(int x,int y)return xy?x:y;求最大值函数求最大值函数(3)新建新建C/C+Header File文件文件MyMFile(系统会自动添(系统会自动添加文件扩展名加文件扩展名.h),文件内容如下:),文件内容如下:#include#includestruct Person int id;char name10;int MyMax(int,int);int i=100;定义在本工程中各个文件内的定义在本工程中各个文件内的函数(函数(MyFile0.cpp)的声明)的声明对系统头文件的包含
22、对系统头文件的包含本工程要使用的类型定义本工程要使用的类型定义本工程中其它文件要使本工程中其它文件要使用的全局变量的定义。用的全局变量的定义。(4)新建)新建C+Source File文件文件MyMFile1,文件内容如下:,文件内容如下:#include MyMFile.hvoid main()Person ZS;ZS.id=i;strcpy(ZS.name,张三张三);printf(i=%dn,i);printf(“id=%d name=%s,ZS.id,ZS.name);int max;max=MyMax(2,20);printf(max=%d,max);putchar(n);i=100
23、id=100 name=张三max=20Press any key to continue写成:写成:#include 出错,用户自定义的头文件只出错,用户自定义的头文件只能使用双引号能使用双引号可能会有这样的情况:可能会有这样的情况:某些全局类型、全局量值和函数某些全局类型、全局量值和函数只使用在某几个特只使用在某几个特定文件中定文件中。这时,要单独新建特定的头文件,只在。这时,要单独新建特定的头文件,只在这几个文件中,包含该头文件,在其它文件中不要这几个文件中,包含该头文件,在其它文件中不要包含该头文件。包含该头文件。就是说,一个工程中,可以根据全就是说,一个工程中,可以根据全局内容的使用
24、范围,创建多个不同的头文件。局内容的使用范围,创建多个不同的头文件。某些全局类型、全局量值和函数某些全局类型、全局量值和函数严格限定只能使用严格限定只能使用在某一个特定文件中在某一个特定文件中。这时,将它们定义在这个文。这时,将它们定义在这个文件中,并且在全局量值和函数的定义前使用关键字件中,并且在全局量值和函数的定义前使用关键字staticstatic。这时,同工程的其它文件无法使用。这时,同工程的其它文件无法使用。如果如果MyMFile0.cppMyMFile0.cpp文件的内容是如下形式:文件的内容是如下形式:staticstatic int MyMax(int x,int y)int
25、MyMax(int x,int y)return xy?x:y;return xy?x:y;这时,程序就会出错。这时,程序就会出错。原因是原因是MyMaxMyMax函数用函数用staticstatic关键字,被限定在本文件关键字,被限定在本文件MyMFile0.cppMyMFile0.cpp中的其它函数调用,同工程的其它文件中中的其它函数调用,同工程的其它文件中的函数无法使用该函数,导致的函数无法使用该函数,导致MyMFile1.cppMyMFile1.cpp中的中的mainmain函函数调用出错。数调用出错。6.3名词性的类型和量值在各逻辑结构上的时间域名词性的类型和量值在各逻辑结构上的时间
26、域 通常通常:类型和量值的时间域和空间域是一致的。类型和量值的时间域和空间域是一致的。特殊情况下特殊情况下:用关键字用关键字staticstatic对定义的变量和函数做限对定义的变量和函数做限定时,空间域和时间域不同,定时,空间域和时间域不同,时间域会大于空间域时间域会大于空间域。6.3.16.3.1模块内模块内staticstatic模块内用模块内用staticstatic定义的变量,其空间域仍然限定在该定义的变量,其空间域仍然限定在该模块,但其时间域是整个工程,即在工程存活期内,模块,但其时间域是整个工程,即在工程存活期内,该变量都占据内存,一直保持着原来的量值,但是在该变量都占据内存,一
27、直保持着原来的量值,但是在模块外由于超出空间域而无法访问,在模块内由于空模块外由于超出空间域而无法访问,在模块内由于空间域和时间域重合,可以被访问。间域和时间域重合,可以被访问。这种变量叫这种变量叫“静态变量静态变量”。与其相对,缺省定义的变。与其相对,缺省定义的变量,叫做量,叫做“动态变量动态变量”,如通常的,如通常的int a;int a;详细的可以详细的可以写为写为autoauto int a;int a;。动态量值在其被定义的模块外同时丧失空间域和时间动态量值在其被定义的模块外同时丧失空间域和时间域,即其占用的内存被释放,它的值当然就不存在了,域,即其占用的内存被释放,它的值当然就不存
28、在了,也就无法访问了也就无法访问了 例例6.8计算计算15的阶乘的阶乘#includeint fac(int);void main()int i;for(i=1;i=5;i+)printf(%d!=%dn,i,fac(i);循环调用阶乘函数循环调用阶乘函数阶乘函数的声明阶乘函数的声明int fac(int n)static int f=1;f=f*n;return(f);定义定义f为静态变量为静态变量1!=12!=23!=64!=245!=120Press any key to continuemain()fac(1)fac(1)static int f=1return ff=f*n=1fac
29、(2)f=1return ff=f*n=2fac(2)fac(3)f=2return ff=f*n=6fac(3)fac(4)fac(4)f=6return ff=f*n=24fac(5)fac(5)f=24return ff=f*n=120#includeint fac(int);void main()int i;for(i=1;i=5;i+)printf(%d!=%dn,i,fac(i);int fac(int n)int f=1;f=f*n;return(f);1!=12!=23!=34!=45!=5Press any key to continuemain()fac(1)fac(1)i
30、nt f=1return ff=f*n=1fac(2)int f=1return ff=f*n=2fac(2)fac(3)int f=1return ff=f*n=3fac(3)fac(4)fac(4)int f=1return ff=f*n=4fac(5)fac(5)int f=1return ff=f*n=56.3.26.3.2文件内的文件内的staticstatic 文件内只有三种成分:文件内只有三种成分:1.1.类型的定义;类型的定义;2.2.全局变量的定义;全局变量的定义;3.3.函数的定义。函数的定义。定义在文件内而模块外的类型其时间域和空间域永定义在文件内而模块外的类型其时间域和
31、空间域永远相同,是整个工程。远相同,是整个工程。文件内定义的全局量值和函数,默认情况下时间域文件内定义的全局量值和函数,默认情况下时间域也是整个工程的运行时间。所以在本工程内的其它文件也是整个工程的运行时间。所以在本工程内的其它文件中,可以访问。中,可以访问。当在定义全局量值和函数时,用当在定义全局量值和函数时,用staticstatic加以限定,加以限定,这时的全局量值和函数的时间域是整个工程,但空间域这时的全局量值和函数的时间域是整个工程,但空间域被限定在本文件。被限定在本文件。例例6.9工程内全局类型和量值时间域工程内全局类型和量值时间域(1)在)在VC+环境中新建工程环境中新建工程te
32、m。(2)新建)新建C+Source File文件文件tem1。输入如下代码:。输入如下代码:int a=1;(3)新建)新建C+Source File文件文件tem2。输入如下代码:。输入如下代码:#includevoid main()extern int a;printf(“a=%dn,a);对定义在本工程其它文对定义在本工程其它文件中全局变量的声明件中全局变量的声明a=1Press any key to continue例例6.9工程内全局类型和量值时间域工程内全局类型和量值时间域(1)在)在VC+环境中新建工程环境中新建工程tem。(2)新建)新建C+Source File文件文件te
33、m1。输入如下代码:。输入如下代码:static b=2;(3)新建)新建C+Source File文件文件tem2。输入如下代码:。输入如下代码:#includevoid main()extern int b;printf(b=%dn,b);在文件在文件tem1中变量中变量b是用是用static定义的,它的空间域定义的,它的空间域被限定在文件被限定在文件tem1中中编译出错:在文件编译出错:在文件tem2中无法对中无法对b声明和调用。声明和调用。例例6.9工程内全局类型和量值时间域工程内全局类型和量值时间域(1)在)在VC+环境中新建工程环境中新建工程tem。(2)新建)新建C+Source
34、 File文件文件tem1。输入如下代码:。输入如下代码:int a=1;(3)新建)新建C+Source File文件文件tem2。输入如下代码:。输入如下代码:#includevoid main()int a;printf(“a=%dn,a);main()函数内的局部变量,未函数内的局部变量,未赋值;而并非赋值;而并非tem1文件中声文件中声明的全局变量明的全局变量a,初值为,初值为1a=-858993460Press any key to continue6.3.36.3.3关于关于staticstatic的总结的总结staticstatic用在模块中,作用是:用在模块中,作用是:扩大时
35、间域;扩大时间域;staticstatic用在文件中,作用是:用在文件中,作用是:缩小空间域;缩小空间域;静态变量(模块内和文件内)是在编译时赋初值的,静态变量(模块内和文件内)是在编译时赋初值的,即无论程序运行几次即无论程序运行几次初值只赋一次初值只赋一次;模块内的动态变量每次调用一切重新开始。模块内的动态变量每次调用一切重新开始。静态变量速度快,耗费资源;动态变量反之。静态变量速度快,耗费资源;动态变量反之。6.3.36.3.3关于关于staticstatic的总结的总结对不初始化的静态变量(模块内和文件内),系统对不初始化的静态变量(模块内和文件内),系统会自动赋会自动赋0 0(数值型)
36、或空字符(字符型);(数值型)或空字符(字符型);对模块内动态变量,是随机数。对模块内动态变量,是随机数。对不初始化的文件内动态变量(即不用对不初始化的文件内动态变量(即不用staticstatic限定限定的文件内变量),系统也会自动赋初值的文件内变量),系统也会自动赋初值0 0或空字符。所或空字符。所以,有的书中将文件中的变量都叫做以,有的书中将文件中的变量都叫做“静态变量静态变量”。例例6.9工程内全局类型和量值时间域工程内全局类型和量值时间域(1)在)在VC+环境中新建工程环境中新建工程tem。(2)新建)新建C+Source File文件文件tem1。输入如下代码:。输入如下代码:in
37、t a;(3)新建)新建C+Source File文件文件tem2。输入如下代码:。输入如下代码:#includevoid main()extern int a;printf(“a=%dn,a);对不初始化的文件内动态变对不初始化的文件内动态变量,系统也会自动赋初值量,系统也会自动赋初值0a=0Press any key to continue6.4变量的物理存储位置变量的物理存储位置 定义的变量通常情况下,无论是动态的还是静态的,定义的变量通常情况下,无论是动态的还是静态的,都是存储在都是存储在ROMROM(随机只读存储器,内存)中的。(随机只读存储器,内存)中的。在小型计算机或大型计算机中
38、允许用关键字在小型计算机或大型计算机中允许用关键字registerregister定义存储在定义存储在CPUCPU的寄存器的寄存器中的变量,该变量的存取速度中的变量,该变量的存取速度更快。但更快。但CPUCPU的寄存器数量很少,所以这样的变量通常的寄存器数量很少,所以这样的变量通常是对程序运行速度影响很大的循环变量。是对程序运行速度影响很大的循环变量。寄存器变量只能是动态的。用寄存器变量只能是动态的。用registerregister定义的寄存器定义的寄存器变量,运行在微机环境中,编译器会自己将其变量,运行在微机环境中,编译器会自己将其转化为转化为存储在存储在ROMROM中。中。例例6.10寄存器变量的定义和使用寄存器变量的定义和使用#includevoid main()register int i;for(i=0;i10;i+)printf(i=%dn,i);上面程序运行在微机和其它计算机上的物理机制不同,上面程序运行在微机和其它计算机上的物理机制不同,但结果相同。但结果相同。