【c++】变量的作用域和生存周期

【c++】变量的作用域和生存周期

一.作用域和生存周期

二.局部变量和全局变量

三.变量的存储类别

四.分别介绍以上四种存储类型(auto/static/register/extern

五.四种变量的作用域、生命周期、内存分布(全局、静态全局、静态局部、局部变量)

参考:

c++从入门到精通》人民邮电出版社

C语言中变量的作用域和生命周期https://blog.csdn.net/zsjalive/article/details/51076956

C语言中变量的作用域https://blog.csdn.net/guoyunhe/article/details/483982(很详细)

C++中变量的作用域与生命周期 https://blog.csdn.net/yunyun1886358/article/details/5632087

 

 

一.作用域和生存周期

       c++变量有两个属性非常重要:作用域和生命周期,它们从两个不同的维度描述了一个变量--时间和空间。顾名思义,作用域就是一个变量可以被引用的范围,如:全局作用域、文件作用域、局部作用域;而生命周期就是这个变量可以被引用的时间段(生存期表示变量存在的时间。不同生命周期的变量,在程序内存中的分布位置是不一样的。一个程序的内存分为代码区、全局数据区、堆区、栈区,不同的内存区域,对应不同的生命周期

                                

一个程序将操作系统分配各其运行的内存块分为4个区域:

(1)代码区:存放程序的代码,即程序中的各个函数代码块。

(2)全局数据区:存放程序的全局数据和静态数据

(3)堆区:存放程序的动态数据。

(4)栈区:存放程序的局部数据,即各个函数中的数据。

二.局部变量和全局变量

       局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内离开该函数后再使用这种变量是非法的。
      全局变量也称为外部变量,它是在函数外部定义的变量。它不属于哪一个函数,它属于一个源程序文件。其作用域是整个源程序。

 

      从变量的作用域(全局作用域,局部作用域,文件作用域)(即从空间)角度来分,可以分为:
                  
全局变量(静态全局变量的作用域是该文件范围(文件作用域)
                 
局部变量

 

     从另一个角度,从变量值存在的作用时间(即生存期)角度来分,生存周期只是和变量存储的位置相关。可以分为

                  静态存储方式(在程序运行期间,系统对变量分配固定的存储空间)

                  动态存储方式(在程序运行期间,系统对变量动态(不固定)的分配存储空间)

 

 

三.变量的存储类别

生存周期只是和变量存储的位置相关。变量的存储类别,可以分为静态存储方式和动态存储方式。

对变量的存储类型说明有以下四种:

    auto  自动变量(动态存储方式

   static    静态变量(静态存储方式)  

    register  寄存器变量(动态存储方式) 
    extern    外部变量(静态存储方式)
 
      

        自动变量和寄存器变量属于动态存储方式,外部变量和静态变量属于静态存储方式。在介绍了变量的存储类型之后,可以知道对一个变量的说明不仅应说明其数据类型,还应说明其存储类型。 因此变量说明的完整形式应为:

         存储类型说明符 数据类型说明符 变量名,变量名… 

例如: 
   staticint a,b;           说明a,b为静态类型变量 
   autochar c1,c2;         说明c1,c2为自动字符变量 
   staticint a[5]={1,2,3,4,5};      说明a为静整型数组 
   externint x,y;           说明x,y为外部整型变量 

 

 

四.分别介绍以上四种存储类型

一)自动变量的类型说明符为auto 
       这种存储类型是C语言程序中使用最广泛的一种类型。C语言规定, 函数内凡未加存储类型说明的变量均视为自动变量, 也就是说自动变量可省去说明符auto 在前面各章的程序中所定义的变量凡未加存储类型说明符的都是自动变量。例如: 

{ int i,j,k;
 
char c;
 
…… 
}
等价于: { auto int i,j,k; 
auto char c;
 
…… 
}
 
 自动变量具有以下特点: 
 1. 自动变量的作用域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效 例如: 
intkv(int a) 

auto int x,y; 
{ auto char c; 
} /*c的作用域*/ 
…… 
} /*a,x,y
的作用域*/ 
 2. 自动变量属于动态存储方式,只有在使用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。因此函数调用结束之后,自动变量的值不能保留。

(二)外部变量的类型说明符为extern 
         在前面介绍全局变量时已介绍过外部变量。这里再补充说明外部变量的几个特点: 
 1. 外部变量和全局变量是对同一类变量的两种不同角度的提法全局变量是从它的作用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。 
 2. 当一个源程序由若干个源文件组成时, 在一个源文件中定义的外部变量在其它的源文件中也有效。例如有一个源程序由源文件F1.CF2.C组成:

 F1.C 
int a,b; /*
外部变量定义*/ 
char c; /*
外部变量定义*/ 
main()
 
{
 
…… 
}
 

F2.C 
extern int a,b; /*
外部变量说明*/ 
extern char c; /*
外部变量说明*/ 
func (int x,y)
 
{
 
…… 
}
 
         F1.CF2.C两个文件中都要使用a,b,c三个变量。在F1.C文件中把a,b,c都定义为外部变量。在F2.C文件中用extern把三个变量说明为外部变量,表示这些变量已在其它文件中定义,并把这些变量的类型和变量名,编译系统不再为它们分配内存空间。 对构造类型的外部变量, 如数组等可以在说明时作初始化赋值,若不赋初值,则系统自动定义它们的初值为0 

 

(三)静态变量static 

        静态变量的类型说明符是static 静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量, 例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。 对于自动变量,前面已经介绍它属于动态存储方式。 但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。 
由此看来, 一个变量可由static进行再说明,并改变其原有的存储方式。 
 1. 静态局部变量 
         在局部变量的说明前再加上static说明符就构成静态局部变量。 
 例如: 

static int a,b; 

static floatarray[5]={1,2,3,4,5} 
 静态局部变量属于静态存储方式,它具有以下特点: 
 (1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序 
 (2)静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。 
 (3)允许对构造类静态局部量赋初值。在数组一章中,介绍数组初始化时已作过说明。若未赋以初值,则由系统自动赋以0值。 
 (4)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。 根据静态局部变量的特点, 可以看出它是一种生存期为整个源程序的量。虽然离开定义它的函数(作用域但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。 因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。 
main()
 
{
 
int i;
 
void f(); /*
函数说明*/ 
for(i=1;i<=5;i++)
 
f(); /*
函数调用*/ 
}
 
void f() /*
函数定义*/ 
{
 
auto int j=0;
 

Static int k=0;
++j;
 

++k;
printf("%d %d/n",j,k);
 
}
 
 程序中定义了函数f,其中的变量j 说明为自动变量并赋予初始值为0。当main中多次调用f时,j均赋初值为0,故每次输出值均为1;kstatic型变量,每次保留之前值,所以依次为 12345
 2.静态全局变量 
     全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的 静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。 

 

 四)寄存器变量 register

      变量一般都存放在存储器内, 因此当对一个变量频繁读写时,必须要反复访问内存储器,从而花费大量的存取时间。 

为此,C语言提供了一种寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写 这样可提高效率。寄存器变量的说明符是register 对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。 
求∑200i=1imain() 
{
 
register i,s=0;
 
for(i=1;i<=200;i++)
 
s=s+i;
 
printf("s=%d/n",s);
 
}
 
         本程序循环200次,is都将频繁使用,因此可定义为寄存器变量。对寄存器变量还要说明以下几点: 
 1. 只有局部自动变量和形式参数才可以定义为寄存器变量。因为寄存器变量属于动态存储方式凡需要采用静态存储方式的量不能定义为寄存器变量 
 2. Turbo CMS C等微机上使用的C语言中, 实际上是把寄存器变量当成自动变量处理的。因此速度并不能提高。而在程序中允许使用寄存器变量只是为了与标准C保持一致。

3. 即使能真正使用寄存器变量的机器,由于CPU 中寄存器的个数是有限的,因此使用寄存器变量的个数也是有限的。 


五.四种变量的作用域、生命周期、内存分布

全局变量

  • 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件。)
  • 生命周期:程序运行期一直存在
  • 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量。
  • 内存分布:全局数据区
  • 注意:如果在两个文件中都定义了相同名字的全局变量,连接出错:变量重定义
  • 例子:

[cpp]  view plain  copy
  1. //defime.cpp  
  2. int g_iValue = 1;  
  3.   
  4. //main.cpp  
  5. extern int g_iValue;  
  6.   
  7. int main()  
  8. {  
  9.     cout << g_iValue;  
  10.     return 0;  
  11. }  

 

全局静态变量

  •  作用域:文件作用域(只在被定义的文件中可见。)
  • 生命周期:程序运行期一直存在
  • 内存分布:全局数据区
  • 定义方法:static关键字,const 关键字
  • 注意:只要文件不互相包含,在两个不同的文件中是可以定义完全相同的两个静态变量的,它们是两个完全不同的变量
  • 例子:

[cpp]  view plain  copy
  1. const int iValue_1;  
  2. static const int iValue_2;  
  3. static int iValue_3;  
  4.   
  5. int main()  
  6. {  
  7.     return 0;  
  8. }  

 

静态局部变量

  • 作用域:局部作用域(只在局部作用域中可见)
  • 生命周期:程序运行期一直存在
  • 内存分布:全局数据区
  • 定义方法:局部作用域用中用static定义
  • 注意:只被初始化一次,多线程中需加锁保护
  • 例子:

[cpp]  view plain  copy
  1. void function()  
  2. {  
  3.     static int iREFCounter = 0;  
  4. }  

 

局部变量

  • 作用域:局部作用域(只在局部作用域中可见)
  • 生命周期:程序运行出局部作用域即被销毁
  • 内存分布:栈区
  • 注意:auto指示符标示

-------------------------------------------         END      -------------------------------------


猜你喜欢

转载自blog.csdn.net/u012679707/article/details/80188124