c++程序设计上海大学通信与信息工程学院2020/1/29第六章程序结构第一节变量的存储类型第一节变量的存储类型C/C++中的变量都有两个属性:数据类型和存储类别。C/C++语言中定义了4个关键字作为变量的存储类别的修饰词,分别为:auto(自动)、static(静态)、register(寄存器)和extern(外部)。变量的存储类别决定了变量作用范围及在内存中的存储区域。在声明变量时可以指定变量的存储类型,形式如下:存储类型数据类型变量名列表;如:autointa;staticfloatb,c;externintd,f;第一节变量的存储类型内存存储区及内存分配方式第一节变量的存储类型程序内存空间三种内存分配方式代码区(Codearea)程序代码全局数据区(Dataarea)全局和静态数据静态分配:系统为每个程序开辟一个固定的静态存储区。程序开始执行时变量就占用内存,直到程序结束时变量才释放内存。堆区(Heaparea)动态数据动态分配:称为堆的内存,处于栈和静态存储区之外的自由存储单元。完全由程序自身控制内存分配和释放。栈区(Stackarea)函数中形参和局部数据自动分配:程序运行后,系统为程序开辟一块称活动存储区,为变量临时分配空间。程序运行后,在变量作用域开始时由系统自动分配内存,在作用域结束后即释放内存。外部存储类型(extern)第一节变量的存储类型用来声明全局变量,以扩展全局变量的作用域在一个文件内使用extern声明全局变量如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该全局变量,则应该在引用之前用关键字extern对该变量作外部变量声明,表示该变量是一个将在下面定义的全局变量。这种声明称为提前引用声明。#includeiostream.hintmax(int,int);//函数声明voidmain(){externinta,b;//对全局变量a,b//作提前引用声明coutmax(a,b)endl;}inta=15,b=-7;//定义全局变量a,bintmax(intx,inty){intz;z=xy?x:y;returnz;}外部存储类型(extern)第一节变量的存储类型用来声明全局变量,以扩展全局变量的作用域在多文件的程序中声明外部变量如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量n,不能分别在两个文件中各自定义一个外部变量n。正确的做法是:在任一个文件中定义外部变量n,而在另一文件中用extern对n作外部变量声明。externintn;file1.cppfile2.cppexterninta,b;inta=3,b=4;intmain()voidfn(){couta″,″bendl;{a=a+b;return0;coutaendl;}}外部存储类型(extern)第一节变量的存储类型带extern变量说明是变量声明而不是变量定义。注意使用extern带来的错误:file1.cppinta=5;intb=6;externintc;…file2.cppinta;//error:多次定义externdoubleb;//error:类型不一致externintc;//error:无定义静态和自动存储类型(static/auto)第一节变量的存储类型可用于局部变量和全局变量。声明局部变量函数中的局部变量,如果不用关键字static加以声明,编译系统对它们是动态地分配存储空间的这类局部变量称为自动变量(autovariable)。自动变量用关键字auto作存储类别的声明。#includeiostream.hintf(inta){intb=0;staticintc=3;b=b+1;c=c+1;returna+b+c;}#includeiostream.hintf(inta){intb=0;autointc=3;b=b+1;c=c+1;returna+b+c;}静态和自动存储类型(static/auto)第一节变量的存储类型可用于局部变量和全局变量。在多文件程序中声明全局变量有时在程序设计中希望某些外部变量只限于被本文件引用,而不能被其他文件引用。这时可以在定义外部变量时加一个static声明。file1.cppfile2.cppstaticinta=3;inta;intmain()intfun(intn){{┆┆a=a*n;┆}}第二节函数的存储类型内部函数和外部函数第二节函数的存储类型函数本质上是全局的,因为一个函数要被另外的函数调用,但是,也可以指定函数只能被本文件调用,而不能被其他文件调用。根据函数能否被其他源文件调用,将函数区分为:内部函数(static):staticintfun(inta,intb);外部函数(extern):externintfun(inta,intb);内部函数和外部函数第二节函数的存储类型File1.cppvoidstaticFn();//error:静态函//数不能被File1.cpp使用voidfn();voidmain(){fn();staticFn();//error:静态函数//不能被File1.cpp使用}File2.cpp#includeiostream.hstaticvoidstaticFn();voidfn(){staticFn();coutthisisfn()\n;}voidstaticFn(){coutthisisstaticFn()\n;}第三节作用域、生命期、可见性作用域第三节作用域、生命期、可见性标识符在程序中的有效范围全局作用域:在程序的文件中有效:外部全局变量文件作用域:在该文件中有效:静态全局变量函数原型作用域:开始于函数声明的左括号,结束函数声明的右括号:函数声明语句中的变量局部作用域(块作用域):在函数内部的动作序列描述中,依据各语句块甚至整个函数体范围内所定义的数据应遵循的数据访问规则:自动局部变量和静态局部变量类作用域:类名空间作用域第三节作用域、生命期、可见性a:全局作用域b:局部(块)作用域c:局部(块)作用域生命期第三节作用域、生命期、可见性标识符的生存周期,与存储区域密切相关。静态生命期代码区(codearea)存放程序的代码,即各函数代码块全局数据区(dataara)存放程序的全局数据和静态数据动态生命期堆区(heaparea)存放程序的动态数据。用malloc()、new分配空间生命期开始,用free()、delete()释放该变量生命期结束局部生命期栈区(stackarea)存放程序的局部数据,即各个函数中的数据局部静态变量具有局部作用域,静态生命期。生命期第三节作用域、生命期、可见性a:全局作用域,静态生命期b:局部(块)作用域,局部生命期c:局部(块)作用域,静态生命期可见性第三节作用域、生命期、可见性用于分析标识符在某一位置的有效性。有效性与作用域通常是一致的,但出现同名标识符嵌套时例外。{inti;charch;i=3;{doublei;i=3.0e3;//inti被隐藏ch=‘A’;//charch仍可见}//doublei作用域结束i+=1;//inti可见}//inti,charch作用域结束由于“地方保护主义”,使得某一变量在内层块中不可见。作用域限定符(::)p111第三节作用域、生命期、可见性这是C++所有的,C语言中没有。在C++语言中,可以通过(::)来标识引用同名的全局变量。ints=0;voidf(){floats=3.0;//和全局变量同名inta;{floata=2.0;::a=1;//错,a不是全局变量::s=1;//通过::来访问全局变量ss=2.0;//访问局部变量s}}第四节头文件与多文件多文件与头文件第四节头文件与多文件一个程序在很小的规模下,可以用一个源文件来完整表达。但一般具有应用价值的程序都是由多文件组成,其中只有一个源文件具有主函数main()为使在不同的源文件中保持声明的一致性,采用头文件*1.h*1.ccp*2.h*2.ccp*3.h*3.ccp翻译单元1翻译单元2翻译单元3*1.obj*2.obj*3.obj.exe可执行文件运行连接.libC++标准库函数标准类库预处理编译多文件与头文件第四节头文件与多文件第五节编译预处理命令编译预处理指令编译预处理是指在对源程序进行通常的编译之前,先对这些命令进行预处理,然后将预处理的结果和源程序一起再进行通常的编译处理。预处理命令是C++统一规定的,但是它不是C++语言本身的组成部分,不能直接对它们进行编译。C++提供的预处理功能主要有以下3种:(1)宏定义:#define(2)文件包含:#include(3)条件编译:#if,#else,#elif,#endif,#ifdef,#undef分别用宏定义命令、文件包含命令、条件编译命令来实现。为了与一般C++语句相区别,这些命令以符号“#”开头,而且末尾不包含分号。第五节编译预处理命令宏定义:#define第五节编译预处理命令用一个指定的标识符(即宏名)来代表一个字符串。定义宏的作用一般是用一个短的名字代表一个长的字符串:#define标识符字符串#definePI3.1415926定义带参数的宏:#define宏名(参数表)字符串#defineS(a,b)a*b//a、b为宏的参数area=S(3,2);//等价于area=3*2;c++增加了内联函数(inline),基本上已不再用#define命令定义宏了,主要用于条件编译中。文件包含:#include第五节编译预处理命令指一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。C++提供了#include命令用来实现“文件包含”的操作。如在file1.cpp中有以下#include命令:#include″file2.cpp″等价于文件包含:#include第五节编译预处理命令include命令的两种形式:#include文件名#include″文件名″#includeiostream.h#include″myarea.h″#include″file2.cpp″文件包含:#include第五节编译预处理命令#includemycircle.cpp#includemyrect.cpp条件编译指令第五节编译预处理命令一般情况下,在进行编译时对源程序中的每一行都要编译。但是有时希望程序中某一部分内容只在满足一定条件时才进行编译,也就是指定对程序中的一部分内容进行编译的条件。如果不满足这个条件,就不编译这部分内容。这就是“条件编译”。条件编译指令的结构类似于C/C++的if结构,每种条件编译指令以#if、#ifdef或#ifndef语句开始,中间可以有#else语句,最后以#endif语句表示一条编译指令的结束。条件编译指令的三种形式第五节编译预处理命令#if…[#else]…#endif#ifdef…[#else]…#endif#ifndef…[#else]…#endif#if指令检测其后表达式的值是否为真,如果为真,则表示随后的源代码要参加编译,直到出现#else或#endif;如果不为真则这部分代码不参加编译。#ifdef指令是#ifdefined指令的缩写,它检测其后的宏是否被定义,如果被定义过则表示随后的源代码要参加编译。#ifndef指令也检测其后的宏是否被定义,但只有当该宏没有被定义过,随后的源代码才参加编译。条件编译举例第五节编译预处理命令例:在调试程序时,常常希望输出一些所需的信息,而在调试完成后不再输出这些信息。可以在源程序中插入条件编译段。#includeiostream.h#defineRUN//在调试程序时使之成为注释行intmain(){intx=1,y=2,z=3;#ifndefRUN//本行为条件编译命令cout″x=″x″,y=″y″,z=″z;/