zoukankan      html  css  js  c++  java
  • 堆、栈、数据区、bss、代码段

    一个程序的运行是需要内存的,那么我们平常写的程序的内存都是怎么分配的呢 

     (1)首先我们要知道,内存是真实存在的,内存是一个物理器件。它时由操作系统管理的,我们平常只要使用它就行了,为了方便管理。操作系统提供了很多种机制来管理内存,每一种机制都有其特点。
    (2)三种内存来源:栈(stack)、堆(heap)、数据区(data)
    (3)我们获取内存的来源就是其中一种,(C语言程序中)

    1.什么是栈?

    1.1.栈的特点
    (1)使用时自动分配,用完自动释放。
     

    1 #include<stdio.h>
    2 main()
    3 {
    4 int a = 1;
    5 int b = 2;
    6 
    7 }
    8  

     总结:a和b都是局部变量,都是栈内存,自动分配和释放 

    (2)栈内存反复使用。使用完后不会清零,这就是为什么每次分配局部变量若不初始化就是随机值的原因。
     

    1 int a ;
    2 printf("a = %d
    ",a);
    3 // a是随机值

    (3)临时性:函数不能返回栈变量的指针。局部变量的地址是不能返回的。在一个函数内部分配的局部变量在函数结束时,其内存就已经不存在了。返回其地址是很危险的。

     1 #include<stdio.h>
     2 int * test();
     3 main()
     4 {
     5 int * w;    //局部变量,栈上分配
     6 w = test();    
     7 *w = 20;    
     8 }
     9 
    10 int* test()
    11 {    
    12 int a = 10;    //局部变量,栈上分配    局部变量,作用域为test函数,生命周期为test函数从执行到执行完毕
    13 int *p = &a;
    14 return p;
    15 }

    分析:

    (1)test函数能不能返回p的值?

    test函数中的a和p都是局部变量,作用域为test函数,生命周期为test函数从执行到执行完毕,当test函数执行完后,为a和p分配的栈上的内存已经释放了。也就是说,原来分配的地址已经不能在被a和p使用了。这里可以返回p的值,只是没有意义了,而是很危险的行为。
    (2)能不能通过 *w = 20?

    能访问,但可能会出错,原a的内存已经被释放,原来的地址已经不再属于a,这时候就会使程序崩溃。访问了不属于它的地址。
    (3)数组越界问题 (栈溢出)
     

    1 main()
    2 {    
    3 int arr[5];    //局部变量,栈上分配
    4 
    5 arr[10] = 100;
    6 }    
    7  

    给arr数组分配了5个地址空间,访问第11个空间则会出错。

     2.什么是堆? 

    (1)操作系统堆管理器管理。堆管理器是操作系统的一个模块
    (2)大块内存,分配自如。按需分配。
    (3)堆内存手动分配&释放,malloc,free
    (4)堆内存也是反复使用的, 堆管理器不会去清零堆内存,下一个使用的变量才去清零。
    (5)堆内存。从分配到释放一直属于同一个进程,之前或者之后都不可以再访问。

    1 //堆内存的使用范例
    2  
    3 main()
    4 {
    5 int*p=(int *)malloc(1000*sizeof(int));    
    6 }
    7 //使用malloc()分配的内存是在堆上分配的
    8 //这里的p仍旧是栈上分配,p是一个指针。该指针指向的内存是堆内存。(4000个字节的首四个字节)
    9  

    3.数据区

    (1)数据段:(也被称作数据区、静态数据区、静态区)程序运行所需要的数据存放在这,比如函数执行过程中调用的一些变量(全局变量),产生的一些数据。注意:全局变量才算是程序的数据,局部变量算是函数的数据,局部变量不是程序的数据。 局部变量属于栈管理,在栈分配。
    (2)bss段
    bss段:(也叫ZI段,zero initial 段,bss段的特点就是被初始化为0,bss段本质上也是数据段,bss段就是被初始化为0的数据段)

    总结:(1)全局变量初始化为非0,存放在数据段。
    static修饰的局部变量存放到数据段
    (2)全局变量 未初始化 或 初始化为0,存放在bss段
    (3)bss段是数据区的一部分

    4.代码段 

    就是存放代码的地方,需要注意的是像char *p="aabbcc";这样的也会被分配的代码段,代码段的东西时不可以被修改的。

    接下来我们看一个程序,具体分析,每一个变量存放在哪里
     

     1 #include<stdio.h>
     2 
     3 int test1 = 250    //全局变量,数据区
     4 int test2 = 0    //初始化为0的全局变量,数据区的bss段
     5 int test3    //未初始化全局变量,数据区的bss段
     6 
     7 char * display();//代码段
     8 
     9 void main()
    10 {
    11 
    12 int ok1 = 1;    /*    局部变量
    13 int ok2 = 0;    栈上分配    
    14 int ok3;    */
    15 
    16 int * pre;    //局部变量指针,栈上分配
    17 pre = display();
    18 
    19 
    20 }
    21 
    22 int * display();
    23 {
    24 char * word = "he is goudan";
    25 //代码段
    26 
    27 int * re = (int*)malloc(100*sizeof(int));
    28 //re指针在栈分配
    29 //re指针指向的是内存在堆上分配
    30 //当display()函数执行完毕后,re指针本身地址被释放,
    31 //re所指向的堆内存依旧存在(若未保留该指针则内存泄漏)
    32 return re;
    33 }
    34 
    35  

    总结:

    (1)程序经过编译后,分成不同的段,程序就是由好多个段组成的。数据段,代码段,bss段。
    (2)全局变量才属于程序的数据,局部变量属于函数的数据。
    (3)有些特殊数据会放在代码段,像字符串。

  • 相关阅读:
    洛谷 [P1024]一元三次方程求解
    洛谷 [P1426] 通往奥格瑞玛的道路
    洛谷 [p1439] 最长公共子序列 (NlogN)
    洛谷 [P1182] 数列分段
    洛谷 [P1314] 聪明的质检员(NOIP2011 D2T2)
    洛谷 [P1280] 尼克的任务
    洛谷 [P1801] 黑匣子
    洛谷 [p1196] 银河英雄传说
    洛谷 [P2024] 食物链
    洛谷 [P1198] 最大数
  • 原文地址:https://www.cnblogs.com/1024E/p/13208840.html
Copyright © 2011-2022 走看看