• C语言内存讲解-详说内存分布和heap空间


    目录

    内存分布

    变量

    内存4区模型

    开辟释放 heap 空间

    使用 heap 空间

    二级指针对应的 heap空间


    内存分布

    程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text)、数据区(data)和未初始化数据区(bss)3 个部分(有些人直接把data和bss合起来叫做静态区或全局区)。

    代码区

    存放 CPU 执行的机器指令。通常代码区是可共享的(即另外的执行程序可以调用它),使其可共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改了它的指令。另外,代码区还规划了局部变量的相关信息。

    全局初始化数据区/静态数据区(data段)

    该区包含了在程序中明确被初始化的全局变量、已经初始化的静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)。

    未初始化数据区(又叫 bss 区)

    存入的是全局未初始化变量和未初始化静态变量。未初始化数据区的数据在程序开始执行之前被内核初始化为 0 或者空(NULL)。

    程序在加载到内存前,代码区和全局区(data和bss)的大小就是固定的,程序运行期间不能改变。然后,运行可执行程序,系统把程序加载到内存,除了根据可执行程序的信息分出代码区(text)、数据区(data)和未初始化数据区(bss)之外,还额外增加了栈区、堆区

    代码区(text segment)

    加载的是可执行文件代码段,所有的可执行代码都加载到代码区,这块内存是不可以在运行期间修改的。

    未初始化数据区(BSS)

    加载的是可执行文件BSS段,位置可以分开亦可以紧靠数据段,存储于数据段的数据(全局未初始化,静态未初始化数据)的生存周期为整个程序运行过程。

    全局初始化数据区/静态数据区(data segment)

    加载的是可执行文件数据段,存储于数据段(全局初始化,静态初始化数据,文字常量(只读))的数据的生存周期为整个程序运行过程。

    栈区(stack)

    栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间。

    堆区(heap)

    堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

    变量

    局部变量:

     概念:定义在函数内部的变量。

     作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。

     生命周期:局部变量:从变量定义开始,函数调用完成。 --- 函数内部。

    全局变量:

    概念:定义在函数 外 部的变量。

    作用域:从定义位置开始,默认到本文件内部。 其他文件如果想使用,可以通过声明方式将作用域导出。

    生命周期: 程序启动开始,程序终止结束。  --- 程序执行期间。


    static全局变量:

    定义语法: 在全局变量定义之前添加 static 关键字。        static int a = 10;

    作用域:被限制在本文件内部,不允许通过声明导出到其他文件。

    生命周期:程序启动开始,程序终止结束。  --- 程序执行期间。


    static局部变量:

     定义语法: 在局部变量定义之前添加 static 关键字。

     特性: 静态局部变量只定义一次。在全局位置。 通常用来做计数器。

     作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。

     生命周期:程序启动开始,程序终止结束。  --- 程序执行期间

    全局函数:  函数

        定义语法: 函数原型 + 函数体

        生命周期:程序启动开始,程序终止结束。  --- 程序执行期间。

    static函数:

       定义语法:static + 函数原型 + 函数体

       static 函数 只能在 本文件内部使用。 其他文件即使声明也无效。

      生命周期:程序启动开始,程序终止结束。  --- 程序执行期间。
     

    内存4区模型

    代码段:.text段。 程序源代码(二进制形式)。

    数据段:只读数据段 .rodata段。初始化数据段 .data段。 未初始化数据段 .bss 段。

     stack:栈。 在其之上开辟 栈帧。    windows 1M --- 10M    Linux: 8M --- 16M

      

     heap:堆。 给用户自定义数据提供空间。 约 1.3G+
     

    当全局变量与局部变量命名冲突时采用就近原则

    开辟释放 heap 空间

    void *malloc(size_t size);  申请 size 大小的空间

            返回实际申请到的内存空间首地址。 【我们通常拿来当数组用】

     void free(void *ptr);    释放申请的空间

            参数: malloc返回的地址值。


    使用 heap 空间

        空间时连续。 当成数组使用。

        free后的空间,不会立即失效。 通常将free后的 地址置为NULL。

        free 地址必须 是 malloc申请地址。否则出错。

        如果malloc之后的地址一定会变化,那么使用临时变量tmp 保存。
     

    代码

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main()
    8. {
    9. //int arr[1000000] = {10, 20, 40};
    10. int *p = (int *)malloc(sizeof(int) * 10);
    11. //char *str = (char *)malloc(sizeof(char)*10);
    12. if (p == NULL)
    13. {
    14. printf("malloc error\n");
    15. return -1;
    16. }
    17. char *tmp = p; // 记录malloc返回的地址值。用于free
    18. // 写数据到 malloc 空间。
    19. for (size_t i = 0; i < 10; i++)
    20. {
    21. p[i] = i + 10;
    22. }
    23. // 读出malloc空间中的数据
    24. //for (size_t i = 0; i < 10; i++)
    25. //{
    26. // printf("%d ", *(p+i));
    27. //}
    28. for (size_t i = 0; i < 10; i++)
    29. {
    30. printf("%d ", *p);
    31. p++;
    32. }
    33. // 释放申请的内存。
    34. free(tmp);
    35. p = NULL;
    36. system("pause");
    37. return EXIT_SUCCESS;
    38. }

    二级指针对应的 heap空间

     申请外层指针: char **p = (char **)malloc(sizeof(char *) * 5);

     申请内层指针:

    1. for(i = 0; i < 5; i++)
    2.  {
    3.      p[i] = (char *)malloc(sizeof(char) *10);
    4.  }

        使用: 不能修改 p 的值。

    1. for(i = 0; i < 5; i++)
    2.  {
    3.      strcpy(p[i], "helloheap");
    4.  }

        释放内层:

    1.  for(i = 0; i < 5; i++)
    2.  {
    3.      free(p[i]);
    4.  }

        释放外层:

            free(p);

    我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=29tl2ib8yb6sk

  • 相关阅读:
    十六、【橡皮擦工具组】
    手机网页,输入时 软键盘盖住输入框完整解决方案,兼容安卓、鸿蒙、苹果IOS
    数据链路层及网络层协议要点
    数据双向绑定数据(v-model)
    Sora来袭!机器人+Sora落地性如何?
    【OpenCV】-图像的矩
    【超详细】Fastjson 1.2.24 命令执行漏洞复现-JNDI简单实现反弹shell(CVE-2017-18349)
    RK3568开发板在工控工业物联网网关方面的应用
    Primavera Unifier 报表管理系统 (再次总结)
    检查网络端口是否正常
  • 原文地址:https://blog.csdn.net/qq_64691289/article/details/127694728