C 语言变量在内存中的分布情况

关于内存的基础知识: 一个由C/C++编译的程序占用的内存分为以下几个部分:
    1. 栈区:由编译器自动分配释放,存放函数的参数值、返回值和局部变量,在程序运行过程中实时分配和释放,栈区由操作系统自动管理,无须程序员手动管理。 
    2.堆区:堆是由malloc()函数分配的内存块,使用free()函数来释放内存,堆的申请释放工作由程序员控制,容易产生内存泄漏。   
    3. 数据区:存放已初始化的全局变量、静态变量(全局和局部)、常量数据。 
    4.BBS区:存放的是未初始化的全局变量和静态变量。 
    5.代码区:存放CPU执行的机器指令,代码区是可共享,并且是只读的。
下面给出例子程序:         

#include <stdio.h>

#include <stdlib.h>
#include <string.h>
int y;                                                        全局未初始化变量  ================> BSS段
int f=7;                                                    全局已初始化变量  ================>数据段(data)
static int r;                                               全局未初始化的静态变量  ==========>BSS段  
static int z=4;                                          全局已初始化的静态变量  ==========>数据段(data)
int main (void)                                                                 ==================>函数是在内存的 代码段(text) 里分配
{
    static int n;                                          局部未初始化的静态变量  ==========>BSS段
    static int m=6;                                     局部已初始化的静态变量  ==========>数据段(data)
    auto int i;                                            局部未初始化的自动变量  ==========>
    auto int j=8;                                        局部已初始化的自动变量  ==========>栈
    char *temp;                                        局部未初始化的自动变量  ==========>栈
    char *p="it is string at rodata !";         局部已初始化的自动变量  ==========>数据段的只读段(rodata) 
    printf("n=%d m=%d r=%d z=%d\n",n,m,r,z);
    printf("y=%d f=%d i=%d j=%d\n",y,f,i,j);
    temp=malloc(20*sizeof(char));           ============>在 里面分配内存空间;                    
    if (temp == NULL)  return -1;
    strcpy(temp,"hello everyone !");
    printf("p=%s\n temp=%s\n",p,temp);
    return 0;  
}
执行结果:
        
针对字符常量进行简单是说明:
    实例如下:
#include <stdio.h>

int main (void)
{
    char *ptr = "hello world !" ;      // “hello world !”是代表字符串的地址,它本身存储在数据的只读数据段中;
    char ar[] = "hi everyone !";       //   "hi everyone !"  存储在栈上; 
    printf("ptr1 = %s\n ar1 = %s\n",ptr,ar);
     //*ptr = 'H';  //如果未注销,编译时产生段错误;
    *ar = 'H';
    printf("ptr2 = %s\n ar2 = %s\n",ptr,ar);
    return 0;  
}
执行结果:
        

下面我们来看看变量的分类:
1.作用域角度分,有全局变量和局部变量它们采用的存储类别如下:
          全局变量:静态外部变量 、外部变量
          局部变量:自动变量、静态局部变量、寄存器变量
2.从变量存在的时间分,有静态存储和动态存储两种类型;静态存储是指程序整个运行时期都存在,动态存储是指程序被调用时被临时分配;
          静态存储:静态外部变量、静态局部变量、外部变量
          动态存储:自动变量、寄存器变量、形参变量
3.从变量值存放的位置来区分,
          内存中静态存储区:静态外部变量、静态局部变量、外部变量
          内存中动态存储区:自动变量、形参变量
          CPU中的寄存器    :寄存器变量
    
¨ 对于 局部变量 来说,声明存储类型的作用是指定变量存储的区域以及由此产生的生存期的问题,
¨对于 全局变量 来说,声明存储类型的作用是变量作用域的扩展问题。
n static  声明一个变量的作用是:

(1) 局部变量static声明,把它分配在静态存储区,该变量在整个程序执行期间不释放,其所分配的空间始终存在。

(2) 全局变量static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)

nstatic对局部变量和全局变量的作用不同:

¨ 局部变量使变量由动态存储方式改变为静态存储方式
¨ 全局变量使变量局部化 ( 局部于本文件 ) 但仍为静态存储方式
¨ 从作用域角度看 凡有 static 声明的 其作用域都是局限的 或者是局限于本函数内 ( 静态局部变量 ) 或者局限于本文件内 ( 静态外部变量 )

1. auto存储类型

    auto只能用来标识局部变量的存储类型,对于局部变量,auto是默认的存储类型,不需要显示的指定。因此,auto标识的变量存储在栈区中。

2. extern 存储类型

    extern用来声明在当前文件中引用在当前项目中的其它文件中定义的全局变量。如果全局变量未被初始化,那么将被存在BBS区中,且在编译时,自动将其值赋值为0,如果已经被初始化,那么就被存在数据区中。全局变量,不管是否被初始化,其生命周期都是整个程序运行过程中,为了节省内存空间,在当前文件中使用extern来声明其它文件中定义的全局变量时,就不会再为其分配内存空间。

3.  register 存储类型  

    声明为register的变量在由内存调入到CPU寄存器后,则常驻在CPU的寄存器中,因此访问register变量将在很大程度上提高效率,因为省去了变量由内存调入到寄存器过程中的好几个指令周期。

4.  static 存储类型  

    被声明为静态类型的变量,无论是全局的还是局部的,都存储在数据区中,其生命周期为整个程序,如果是静态局部变量,其作用域为一对{}内,如果是静态全局变量,其作用域为当前文件。静态变量如果没有被初始化,则自动初始化为0。静态变量只能够初始化一次。

5. 字符串常量
     字符串常量存储在数据区中, 其生存期为整个程序运行时间, 但作用域为当前文件。

根据上面的几种类型,比较他们的作用域、生存域和存储位置的差异:
类型
作用域
生存域
存储位置
auto 变量
一对{}内
当前函数
变量默认存储类型,存储在栈区
extern 函数
整个程序
整个程序运行期
变量默认存储类型,代码段
extern 变量
整个程序
整个程序运行期
初始化在data段,未初始化在BSS段
static 函数
当前文件
整个程序运行期
变量默认存储类型,代码段
static 全局变量
当前文件
整个程序运行期
初始化在data段,未初始化在BSS段
static 局部变量
一对{}内
整个程序运行期
初始化在data段,未初始化在BSS段
register变量
一对{}内
当前函数
运行时存储在CPU寄存器中
字符串常量
当前文件
整个程序运行期
数据段

C语言程序的内存分配方式 
1.内存分配方式有三种:  
  [1]从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。 
  [2]在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
          栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 
  [3]从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

根据上面的描述绘出变量在内存中的存储模型,如下图:
    

总结:
     1.未初始化的全局自动变量和静态变量(全局和局部)存储在BSS段,在编译时分配内存空间并 被初始化为0
    2.已初始化的全局自动变量和静态变量(全局和局部)存储在data段,在编译时分配内存空间;常量数据被分配在rodata段
    3.局部自动变量和函数参数以及函数返回值存储在栈上,在函数执行时计算机自动分配,无需程序员管理;
    4.库函数(malloc free ··· )是在函数运行时分配在堆上,需要程序员自己分配与销毁内存空间。


  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值