当前位置: 首页 > news >正文

5.C语言内存分区-堆-栈

目录

内存分区

运行之前

代码区

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

未初始化数据区(bss(Block Started by Symbol)区)

总结

运行之后

代码区 (text segment)

未初始化数据区(bss)

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

栈区(stack)

堆区(heap)


内存分区

运行之前

如果要执行一个C程序,那么第一步需要对这个程序进行编译。

1预处理宏定义展开,头文件展开,条件编译,这里不会检查语法
2编译检查语法,将预处理后的文件编译成汇编文件
3汇编将汇编文件生成目标文件(二进制) .o文件已生成
4链接 将目标文件链接为可执行程序  二进制文件转换可执行文件 类似.ext

当编译完成生成可执行文件之后,我们可以通过linux下的size买了查看一个可执行二进制文件基本情况:

通过上图可以得知,在没有运行程序前,也就是说,程序没有加载到内存前,可执行程序内部已分好3段信息,分别是 代码区(text)  , 数据区(data)  和未初始化数据区(bss) 3个部分(可以把data和bss合起来叫做静态区,或者全局区)

以下是细分:

bss区域放未初始化的数据如: static int a; //未初始化数据。
static int a = 10 ;//这个时候数据放在数据区 data区。

代码区

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

说白了,代码区,就是放代码的

以上重点
共享:比如我们创建了一个a.exe和a1.exe两个代码是一样然后,第一次点击a.exe ,第二次点击a1.ext其实运行的还是a.exe原因是代码一样,共享

只读:比如我们在开发一个游戏币,创建了游戏币和人名币两个变量,如果是可写的,那么吧游戏币写到人名币里面那这样就是大事故,所以设置成只读。

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

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

未初始化数据区(bss(Block Started by Symbol)区)

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

总结

程序源代码被编译之后主要分成两段: 程序指令(代码区)  和  程序数据(数据区) 。代指码段属于程序指令,而数据域段和bss段属于程序数据

为什么要分开?

程序被加载到内存中之后,可以将数据和代码分别映射到两个内存区域。由于数据区域对进程来说是可读可写的,而指令域对程序来说是只读的,所以区分之后,可以将程序指令区域和数据区域分别设置成可读可写或者只读。这样可以防止程序的有意或者无意被修改

当程序中运行着多个同样的程序的时候,这些程序执行的指令都是一样的,所以只需要内中保存一份程序的指令就可以了,只是每一个程序运行中数据不一样而已,这样可以节省大量的内存。

运行之后

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

代码区 (text segment)

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

案例:

int main() {int a = 1; // 这一行对应的机器指令就存储在代码区return 0;
}

未初始化数据区(bss)

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

案例

   int a; // 存储在BSS段,默认值为0static int i; // 局部静态变量,默认值也为0,存储在BSS段

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

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

案例

   int a= 10; // 存储在数据段static int i= 20; // 局部静态变量,同样存储在数据段

栈区(stack)

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

栈的空间是有限的,尽量用完就释放掉

1是第一个进入。

如果1想出来,那要吧4先扔掉,3在扔掉,2在扔掉,才是1

可以认为吃米饭一样,先吃上面的,才能见碗底。

堆区(heap)

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

大容量:大容量,到底有多大,要看机器有多好,看机器

分配:使用malloc函数分配

释放:使用free函数释放 ,如果不释放程序会在系统结束后回收 注意,一定要手动释放

生命周期

类型作用域生命周期存储位置
auto变量一对{}内当前函数栈区
static局部变量一对{}内整个程序运行期初始化在data段,未初始化在BSS段
extern变量整个程序整个程序运行期初始化在data段,未初始化在BSS段
static全局变量当前文件整个程序运行期初始化在data段,未初始化在BSS段
extern函数整个程序整个程序运行期代码区
static函数当前文件整个程序运行期代码区
register变量一对{}内当前函数运行时存储在CPU寄存器
字符串常量当前文件整个程序运行期data段

栈 注意事项

案例1

int* func() {int a = 10;return &a;
}void test01() 
{int* p = func();printf("p = %d\n",p);
}

运行结果:

从上面结果来看,不是我们预期的结果,我们预期结果是 p = 10

为什么是这样?

首先我们来看func函数,函数定义的是int a = 10, 函数最终返回了a的地址,所以a在栈区的值已经释放了,我们没有去操作这一块内存。

案例2

char * getMyName()
{char myName[] = "达帮主";return &myName;
}void test02()
{char* p = getMyName();printf("my name p = %s\n",p);
}

运行结果:

问题与案例1一样,也是释放了,不要在意结果。

栈的释放过程

从上面图中可以看出,当getMyName方法运行完成之后,常量区的内容是会被释放的,放回p收到的只是地址。所以上面案例2是乱码,内容被释放,我们根本不知道是上面东西。

总结

不要返回局部变量地址,局部变量在函数执行之后就释放了,我们没有权限去操作释放后的内存。

堆 注意事项

案例1

int* getSpace() {//手动分配堆空间int *p = malloc(sizeof(int)*5);if (p == NULL) {return 0;}for (int i = 0; i < 5; i++) {p[i] = 1000 + i;}return p;
}void test01() {int* p = getSpace();for (int i = 0; i < 5; i++){printf("p:%d \n",p[i]);}//手动释放堆空间free(p);p = NULL; //防止野指针
}int main() 
{test01();printf("\n\n");system("pause");return EXIT_SUCCESS;
}

运行结果:

从上面代码来看我们使用了malloc来分配空间,分配的内存是存在堆中,所以数据没释放是一直存在的。

案例2

void getMyName(char *pp) 
{//分配内存char * temp = malloc(sizeof(char)*50);if (temp == NULL) {return;}memset(temp,0,50);//赋值strcpy_s(temp,50,"达帮主");pp = temp;
}void test02()
{char* p = NULL;getMyName(p);printf("%s\n",p);
}

运行结果

上面的原因是因为同级指针通过函数参数是无法修饰到p的,所以我们要在函数参数写二级指针。

如果主调函数中没有给指针分配内存,被调函数用同级指针是修饰不到主调函数中的指针的。

看下面案例

void getMyName(char **pp) 
{//分配内存char * temp = malloc(sizeof(char)*50);if (temp == NULL) {return;}memset(temp,0,50);//赋值strcpy_s(temp,50,"达帮主");*pp = temp;
}void test02()
{char* p = NULL;getMyName(&p);printf("%s\n",p);
}

运行结果:

上下的区别是加入二级指针,以及传的是地址,最后吧分配的内存修饰给二级指针

流程图

总结

在理解C内存分区时,常会碰到术语:数据区,堆,栈,静态区,常量区,全局区,字符串常量区,文字常量区,代码区等等。在这里,尝试捋清楚以上分区的关系。

  •  数据区包括:堆,栈,全局/静态存储区。
  • 全局/静态存储区包括:常量区,全局区、静态区。
  • 常量区包括:字符串常量区、常变量区。
  • 代码区:存放程序编译后的二进制代码,不可寻址区。


可以说,C/C++内存分区其实只有两个,即代码区和数据区

相关文章:

5.C语言内存分区-堆-栈

目录 内存分区 运行之前 代码区 全局初始化数据区 、静态数据区 (data) 未初始化数据区(bss&#xff08;Block Started by Symbol&#xff09;区) 总结 运行之后 代码区 &#xff08;text segment&#xff09; 未初始化数据区(bss) 全局初始化数据区&#xff0c;静态…...

传统CV算法——基于opencv的答题卡识别判卷系统

基于OpenCV的答题卡识别系统&#xff0c;其主要功能是自动读取并评分答题卡上的选择题答案。系统通过图像处理和计算机视觉技术&#xff0c;自动化地完成了从读取图像到输出成绩的整个流程。下面是该系统的主要步骤和实现细节的概述&#xff1a; 1. 导入必要的库 系统首先导入…...

国产 HighGo 数据库企业版安装与配置指南

国产 HighGo 数据库企业版安装与配置指南 1. 下载安装包 访问 HighGo 官方网站&#xff08;https://www.highgo.com/&#xff09;&#xff0c;选择并下载企业版安装包。 2. 上传安装包到服务器 将下载的安装包上传至服务器&#xff0c;并执行以下命令&#xff1a; [rootmas…...

「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件

本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息&#xff0c;页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。 关键词 UI互动应用天气预报数据绑定动态展示状态管理 一、功能说明 自定义…...

Springboot @Transactional使用时需注意的几个问题

一、事务的隔离级别 在Springboot应用中&#xff0c;如果我们想实现方法一旦执行有异常产生&#xff0c;就触发事务回滚&#xff0c;可以在方法上面添加Transactional注解。如果应用采用mysql数据库&#xff0c;虽然mysql本身也有事务隔离机制&#xff0c;但在Sping数据库的应…...

数字经济下的 AR 眼镜

目录 1. &#x1f4c2; AR 眼镜发展历史 1.1 AR 眼镜相关概念 1.2 市面主流 XR 眼镜 1.3 AR 眼镜大事记 1.4 国内外 XR 眼镜 1.5 国内 AR 眼镜四小龙 2. &#x1f531; 关键技术 2.1 AR 眼镜近眼显示原理 2.2 AR 眼镜关键技术 2.3 AR 眼镜技术难点 3. &#x1f4a…...

力扣150题

88. 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 **注意&#xff1a;**…...

剑指offer搜索二维矩阵

题目连接 https://leetcode.cn/problems/search-a-2d-matrix-ii/’ 代码 自己想出来的 解法一 初始化两个指针&#xff0c;i0,j列数-1 若此时matrix[i][j]target 则返回true 若此时matrix[i][j]>target,表明在第j列中不可能存在target&#xff0c;因为列是升序的 若此时ma…...

如何设置浏览器不缓存网页

设置浏览器不缓存网页可以通过多种方法实现&#xff0c;以下是一些常见的策略&#xff1a; HTTP响应头控制&#xff1a; Cache-Control&#xff1a;这是最常用的HTTP头之一&#xff0c;用于控制响应的缓存行为。例如&#xff1a; Cache-Control: no-cache, no-store, must-r…...

Iris简单实现Go web服务器

package mainimport ("github.com/kataras/iris" )func main() {app : iris.New() // 实例一个iris对象//配置路由app.Get("/", func(ctx iris.Context) {ctx.WriteString("Hello Iris")})app.Get("/aa", func(ctx iris.Context) {ct…...

后端项目java中字符串、集合、日期时间常用方法

我这里只介绍了项目中最常用的哈,比如像集合有很多,但我们最常用的就是ArrayList。 然后我这里会以javascript中的字符串、数组的方法为基准来实现,有些方法js和java会有些区别也会介绍 字符串 每次修改 String 对象都会创建一个新的对象,而 StringBuffer 可以在同一个对象…...

【Spring事务】深入浅出Spring事务从原理到源码

什么是事务 保证业务操作完整性的一种数据库机制 &#xff08;driver 驱动&#xff09;事务特定 ACID A 原子性 &#xff08;多次操作 要不一起成功 要不一起失败 &#xff08;部分失败 savepoint&#xff09;&#xff09; C 一致性 &#xff08;事务开始时数据状态&#xff0c…...

vue.js滑动到顶便锁定位置

<template><div><div class"nav"></div><div class"searchBar" id"searchBar"><ul :class"searchBarFixed true ? isFixed :"> <li>区域<i class"iconfont icon-jiantouxia"…...

EdgeX Core Service 核心服务之 Core Command 命令

EdgeX Core Service 核心服务之 Core Command 命令 一、概述 Core-command(通常称为命令和控制微服务)可以代表以下角色向设备和传感器发出命令或动作: EdgeX Foundry中的其他微服务(例如,本地边缘分析或规则引擎微服务)EdgeX Foundry与同一系统上可能存在的其他应用程序…...

掌握常用HTML标签:创建个人简介网页

任务目标 理解HTML文档的基本结构&#xff0c;掌握常见的HTML标签及其用途&#xff0c;创建一个简单的个人简介网页。 学习内容脑图 #mermaid-svg-5GTdqH41gawr4v0h {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

音视频学习(二十五):ts

TS&#xff08;MPEG-TS&#xff0c;MPEG Transport Stream&#xff09; 是一种广泛应用于流媒体传输和存储的容器格式。它最早由 MPEG&#xff08;Moving Picture Experts Group&#xff09;组织制定&#xff0c;用于视频和音频的压缩编码。在 HLS&#xff08;HTTP Live Stream…...

10. 虚拟机VMware Workstation Pro下共享Ubuntu和Win11文件夹

本文记录当前最新版虚拟机VMware Workstation Pro&#xff08;2024.12&#xff09;如何在win11下共享文件&#xff0c;以实现Windows与Ubuntu互传文件的目的。 1. 创建共享文件夹 1.1 先关闭虚拟机的客户机&#xff0c;打开虚拟机设置 1.2 在虚拟机设置界面找到“选项”->“…...

单元测试mock框架Mockito

为了继续改进 Mockito 并进一步改善单元测试体验&#xff0c;我们希望您升级到 2.1.0&#xff01;Mockito 遵循语义版本控制&#xff0c;仅在主要版本升级时包含重大更改。在库的生命周期中&#xff0c;重大更改是推出一组全新功能所必需的&#xff0c;这些功能会改变现有行为甚…...

Python从0到100(七十八):神经网络--从0开始搭建全连接网络和CNN网络

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…...

2024多模态大模型综述最新总结

摘要 随着人工智能技术的快速发展&#xff0c;多模态大模型&#xff08;MLLM&#xff09;已成为研究的新热点。这些模型以强大的大型语言模型&#xff08;LLM&#xff09;为基础&#xff0c;能够处理和理解多种模态信息&#xff0c;如文本、图像、视频和音频。本文综述了MLLM的…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...