各类变量生存周期及存储空间

一、运行时环境简介

程序在执行期间,将在其自己的逻辑地址空间内运行,其中每个程序值都在这个空间内有一个地址。一种典型的程序空间模式如下图:

首先,运行时的数据包含数据区和代码区。图中的Text就是代码区,存储目标代码。数据区包括图中的Data、BSS、Heap和Stack。

1.(常量区)Data区主要存储常量数据,主要是需要较多空间的常量,如 char s[32]=“Hello World”;中的“Hello World”。

2.(全局区)BSS主要存储全局和静态变量。

3.(堆区)Heap是动态存储空间,主要用于程序在运行过程中动态申请存储空间。

4.(栈区)Stack为运行时的函数提供存储空间,局部变量就在此空间中。当然,除了局部变量,stack中还存放实现函数调用所必需的多种数据。

为了更有效地利用存储空间,将Heap和Stack采取相向放置,每个区域向对方增长的形式。在具体实现时,栈向较低地址方向增长,而堆向较高地址方向增长。

二、局部变量和全局变量

在函数内部定义的变量将会分配在栈上,当函数被调用时,该变量才会被分配;当函数返回后,该变量就将被释放,因此,局部变量仅仅在该函数内部范围有效,只能在该函数内使用,因此称为“局部变量”,也称为“内部变量”。

局部变量的生存周期为函数的一次调用周期。

说明:

不同函数可以使用相同名字的局部变量,相互之间不会发生指代不明的情况,main函数虽然比较特殊,但是在局部变量的使用特点上与其他函数没有区别。最后,用于接收或存储参数的形式参数也被视为局部变量,同样可以按照局部变量的方式使用。

在函数外部定义的变量将会分配在BSS区,其有效与否与函数调用过程无关,因此,其他函数均可以访问此类变量,称为“全局变量”。

1)全局变量的作用范围:全局变量可被本文件中的其他函数访问,其有效范围是从定义变量的位置开始到该文件结束。在此有效范围内的所有函数都可以访问此变量,从而可以将全局变量作为函数之间交换信息的通道。

2)全局变量的生存周期:全局变量在程序执行过程中始终占用存储单元,即全局变量的生存周期为程序的生存周期。因此,若大量使用全局变量,可能使得程序占据存储单元过多,从而降低其他程序的可用储存空间。

三、动态存储和静态存储

局部变量和全局变量主要是从存储空间角度对变量加以归类,从变量的生存周期来看,可以分为静态存储和动态存储。

静态存储方式是指变量的空间分配不以程序运行状况决定,而是程序运行期间固定分配的方式。

动态存储方式下,变量的分配将根据程序运行情况(如函数调用、动态内存分配等)来进行。如函数调用发生时分配变量空间,函数调用结束时释放变量空间。

下面通过例子来理解变量生存期。

例1:(全局变量和局部变量生存周期)

int global_a;
int local_1()
{
    char local_1_c;
    local_2();
}

int local_2()
{
    char local_2_c;
}
int main()
{
    int main_i;
    for(main_i=0;main_i<3;main_i++)
    {
        local_1();
    }
    return 0;
}

1)假定t=1时程序启动,全局变量global_a就开始存在,直到程序结束;main函数中的main_i也开始存在,直到退出main函数。

2)t=2时,main函数调用local_1函数时,local_1_c变量被分配空间,形成3个变量同时存活情况。

3)t=3时,local_1函数调用local_2函数,因为local_2_c变量也会被分配,形成4个变量在程序中共存的情况。

4)t=4时,local_2函数运行结束,local_2_c变量将被释放,导致t=5时只有local_1_c、main_i和global_a共存的状况。

5)t=5时,local_1函数运行结束,因此local_1_c变量将被释放。导致t=5时只有main_i和global_a共存的状况。

此后情况与先前类似。

从上例可以看到,C程序从空间作用域出发,对全局变量采取默认静态分配策略,而对局部变量采取默认动态分配策略。C程序还提供了显式指出存储类别的变量分配方法。在C程序中,可以通过关键字auto和static来指定存储类别。auto类别的变量将动态地分配存储空间,数据储存在动态存储去中,如函数的形式参数和局部变量的缺省分配。而static类别的变量将存储在静态数据区,在程序执行期间一直存活。

void auto_static();
int main()
{
    int i;
    for (i=0;i<5;i++)
    {
        auto_static();
    }
    printf("\n");
    exit(0);
}

void auto_static()
{
    int var_auto=0;
    static int var_static=0;
    printf("var_auto is %d--",var_auto++);
    printf("var_static is %d\n",var_static++);
}

程序运行结果:

函数auto_static中,定义说明语句int var_auto=0;表明var_auto是局部变量,由于没有指定存储类别,所以默认采用动态存储方式。

定义说明语句

static int var_static=0;

表明var_static是局部变量,同时指定存储类别为static,所以将采取静态存储方式,var_static将在程序开始后分配内存空间,而无须等待auto_static()函数调用的发生。

四、内部函数和外部函数

当一个程序由多个源文件组成时,可以指定一个文件内的函数能被其他文件调用,也可以指定该函数只能被本文件使用。从这个意义上说,函数可以分为外部函数和内部函数,并通过指定函数类别限定符限制函数的相互调用。

函数在本质上是外部的,函数名同变量名一样遵循作用域规则。C语言不允许函数嵌套定义,各个函数之间是平行并列的关系,相互之间可以调用,因而函数具有全局的有效范围。但每个函数定义都附属于某个程序文件,类似于变量。我们可以决定该函数的可被调用范围是所有程序文件还是仅限于该函数定义所处的文件,即指定该函数是外部函数还是内部函数。

1.外部函数

在定义函数时,如果冠以关键字extern,则表示该函数是一个外部函数,例如:

extern double func1(double x){……}

这样函数func1可被调用范围(作用域)是所有程序文件,即它可以被任何其他函数所调用而不论这个函数是否与函数func1()处于同一个程序文件中。C语言规定,如果在定义时省略extern关键字,则默认为外部函数。

2.内部函数

在定义函数时,如果冠以关键字static,则表示该函数是一个内部函数,例如:

static double func1(double x){……}

这样函数func1可被调用范围(作用域)仅限于该函数定义所处的文件,即该函数被限制为仅能被本程序文件中的函数所调用。内部函数又称静态函数,使用内部函数时,有雨函数的调用仅局限于所在的文件,因而在不同文件中可以定义相同名称的内部函数而相互不干扰,这样方便大型应用程序的编写工作。

原文地址:https://www.cnblogs.com/Tang-tangt/p/9787225.html

时间: 2024-11-25 18:51:55

各类变量生存周期及存储空间的相关文章

各类变量

转自:http://www.cnblogs.com/hnrainll/archive/2011/08/26/2155079.html C语言中局部变量和全局变量变量的存储类别(static,extern,auto,register)   局部变量和全局变量 在 讨论函数的形参变量时曾经提到,形参变量只在被调用期间才分配内存单元,调用结束立即释放.这一点表明形参变量只有在函数内才是有效的,离开该函数就不能 再使用了.这种变量有效性的范围称变量的作用域.不仅对于形参变量,C语言中所有的量都有自己的作

变量生存周期和静态局部变量

只有当函数被调用时, 其形参和局部变量才被分配了内存, 一旦调用结束, 其空间将被回收.根据这种特性, 把局部变量称为自动变量. 定义形式  :   auto int x, y; 在定义时, auto一般省略. 静态变量赋初始值只有在函数第一次调用时起作用, 若没有赋初始值,系统自动赋0. 1 #include<stdio.h> 2 double fact_s(int i){ 3 static double f = 1; 4 f = f * i; 5 return f; 6 } 7 int m

C++中使用new为一个变量动态生成存储空间的3种方式

1 // 使用new动态分配存储空间 2 3 #include<iostream> 4 using std::cout; 5 6 int main() 7 { 8 // 第1种方式 9 int *a=new int; 10 *a=1; 11 cout<<"使用第一种方式进行动态分配存储空间的结果为:\n" 12 <<"*a= "<<*a<<std::endl; 13 // 第2种方式 14 int *b=n

【Java】Java_10 常量与变量

1.变量(variable) 1.1 我们通过变量来操纵存储空间中的数据,变量就是指代这个存储空间!空间位置是确定的,但是里面放置什么值不确定! 1.2 Java是一种强类型语言,每个变量都必须声明其类型. 1.3 Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域. 1.4 变量在使用前必须对其声明, 只有在变量声明以后,才能为其分配相应长度的存储单元,声明格式为: type  varName  [=value] [{,varName[=value]}] : 注意事项:

指针的含义——指针变量、指针的指针、指针使用的注意

指针其实很容易理解的,其他并不是大家想象的那么神奇,那么难. 一.指针的含义:指针其实就是一个变量,它所存放的不是数据,而是数据在内存中地址.当然指针也可以存放函数(方法)的地址,后面会讲到的.声明指针的关键符是*号,指向地址的关键符是&. 二.指针变量: 例如1:#include <stdio.h> int main {  int a =10;   //第一一个变量a,赋值为10 int *p = &a;   //p就是一个指针变量,所指向的就是变量a的地址 printf(&

「5」变量

1.为什么需要变量 ●内存就像储物柜,用来存放各种类型东西(数据) ●对程序员来说,数据存入内存只是第一步,还要考虑: 1.怎样找到存入的数据 2.存入的数据能否修改 ●写程序就是在做内存存取,先把数据存入内存,需要的时候取出来做处理 ●内存地址不好记,怎么办? ●为特定地址的内存起个别名,通过别名找到存储的数据 ●该别名就是变量名 ●变量就是数据存储空间的表示 2.变量的声明和使用 ●声明和使用变量的步骤: ●第一步:声明一个变量以分配空间 根据类型开辟空间 ●第二步:为变量赋值 将数据存入空

包的变量作用域测试说明

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 1. 包中作用域种类说明以及声明位置 a. publish.private.locavariable 三种类型,当然每种类型包括了变量.函数.类型等.     b. publish类声明在非包体中(不带body的)private类声明在包体中locavariable类声明在包中函数.过程对象里面的 2. 作用域说明 a. publish类,包外可以使用,可以进行取值.赋值操作,每次

初学c课程笔记整理5--&gt;&gt;进制(+位运算符变量)及一些补充

是什么?有什么用?用在什么地方?(理解) 养成良好的编程习惯; 培养编程思想: 写代码之前应该先分析需求,分析完需求再开始写代码:(写注释) 1.进制 1.1进制的概念 是一种计数的方式,数值的表现形式 1.2常见的进制 十进制.二进制.八进制.十六进制 1.3进制的进位方法 十进制 0.1.2.3.4.5.6.7.8.9 逢十进一 二进制 0.1 逢二进一 书写形式:需要以0b或者0B开头,比如0b101 八进制 0.1.2.3.4.5.6.7 逢八进一 书写形式:在前面加个0,比如045 十

JS 变量详解

关于JS中的变量 JS中的变量是松散类型的,可以存储任何类型的数据. JS变量松散类型的本质,决定了变量只是在特定时间用于保存特定值的一个名字而已. 由于不存在定义某个变量必须要保存何种数据类型的值的规则,变量的值及其数据类型可以在脚本的生命周期内改变. 用var关键字声明的变量,未经初始化时,保存的是一个特殊的值——undefined. 变量初始化仅仅是给变量赋一个值. 可以在一条语句中声明多个变量,初始化或不初始化皆可,变量之间用逗号隔开. 用var关键字声明的变量是定义该变量的作用域中的局