• C中存储分区详解


    一. 在c中分为这几个存储区:栈(stack),堆(heap),代码段(text),数据段(data),bss 段,常量存储区,
    1.栈(stack):由编译器自动分配释放
    自动分配,自动回收:栈区里面存放的是局部变量;在定义局部变量的时候,系统在栈区自动分配内存,在结束时,自动回收内存;
    脏内存:栈区每次使用之前需要对栈区进行初始化;对于定义局部变量时,需要对局部变量进行初始化;
    临时性:(函数不能返回栈变量的指针,因为这个空间是临时的)
    反复使用:栈内存在程序中其实就是那一块空间,程序反复使用这一块空间。
    栈的大小有限,因此 会出现栈溢出

    2.堆(heap): 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
    手动分配:malloc分配内存,free进行释放内存;
    脏内存:堆区每次使用之前呢需要对堆区进行初始化;
    临时性:堆区每次分配的内存释放之后,就不能在使用;
    malloc的使用:malloc每次分配的内存之后需要进行对其返回指针为void *类型,需要进行强制类型转换,并对返回指针进行检查是否为null;
    malloc和free为c语言的标准库函数,不能分配对象;
    内存泄漏;
    gcc中的malloc默认最小是以16B为分配单元的;如果malloc小于16B的大小时都会返 回一个16字节的大小的内存。

    3.代码段(text):

      也叫文本段,代码段其实就是函数编译后生成的东西;

    4.数据段(data):

      也被称为数据区、静态数据区、静态区;
    c语言中
    1.显示初始化为非零全局变量
    2.显示初始化为非零的静态局部变量存储在这个段;

    5.bss 段(又叫:ZI(zero initial)段):.bss 段
    c语言中
    1).显示初始化为0的全局变量;

    2).未初始化的全局变量存储在这个段。--零初始化段;

    3).显示初始化为0的static局部变量;

    4).未初始化的static局部变量存储在这个段;

    6.自定义段:

      段名由程序员自己定义,段的属性和特征也由程序员自己定义。

    7.常量存储区:

      一块比较特殊的存储区,存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)

    8.文件映射区:

      进程打开了文件后,将这个文件的内容从硬盘读到进程的文件映射区,以后就直接在内存中操作这个 文件,读写完了后在保存时再将内存中的文件写到硬盘中去。

    9.内核映射区:

      内核映射区就是将操作系统内核程序映射到这个区域了。

    10.不同的存储方式有不同的特点,简单总结如下:
    1)函数内部临时使用,出了函数不会用到,就定义局部变量
    2)堆内存和数据段几乎拥有完全相同的属性,大部分时候是可以完全替换的。

      生命周期不一样:

        堆内存的生命周期是从malloc开始到free结束;

        全局变量是从整个程序一开始执行就开始,直到整个程序结束才会消灭,伴随程序运行的一生。

      启示:如果变量只是在程序的一个阶段有用,用完就不用了,就适合用堆内存;

         如果这个变量本身和程序是一生相伴的,那就适合用全局变量。

    补充1:
    1)所有未初始化的静态(static)变量和全局变量,编译器会默认赋初值0。
    2)程序在加载到内存前,代码区(text)和全局区(data和bss)的大小就是固定的,程序运行期间不能改变。
    3)data段和bss区中的数据的生存周期为整个程序运行过程。
    4)data段、text区和bss区是由编译器在编译时分配的,堆和栈是由系统在运行时分配的。

    12.生命周期/作用域:
    1).生命周期:指变量活着或者说是存在的时间;
    2).作用域:指可以使用这个变量的范围;

    结合示例详解:

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int c = 1;              //初始化为非零的全局变量:.data段
    int a = 0;           //初始化为0的全局变量:.bss段
    char *p1;             //未初始化的全局变量:.bss段
    void main()
    {
      int b;            //局部变量:stack(栈)
      char s[] = "abc";      //局部变量:stack(栈)
      char *p2;           //局部变量:stack(栈)
      char *p3 = "123456";    //字符串"123456"在常量区,p3局部变量:stack(栈)
      static int c = 0;      //显示初始化的局部变量:.bss段
      p1 = (char *)malloc(10);  //malloc分配的内存:heap(堆)
      strcpy(p1, "123456");
    
      system("pause");
      return;
    }

    补充2:

    明确区分堆与栈:
    在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。
    首先,我们举一个例子:

    void func()
    { 
    int* p=new int[5];    //包含了堆与栈
    }

    new分配了一块堆内存;
    局部变量指针变量p分配的是一块栈内存;
    意义:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中。

  • 相关阅读:
    Django笔记
    在vue框架里添加bootstrap与axios
    Mysql8和Mysql5.7部署同一服务器
    docker迁入迁出mysql
    mysql导出csv
    Yearning启停脚本(开机自启)
    go 语言的基础知识
    阅读《深入理解Kafka核心设计与实践原理》第五章 日志存储
    阅读《深入理解Kafka核心设计与实践原理》第四章 主题与分区
    阅读《深入理解Kafka核心设计与实践原理》第三章 消费者
  • 原文地址:https://www.cnblogs.com/weiyouqing/p/9073420.html
Copyright © 2020-2023  润新知