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

C/C++ 中的堆和栈分别是什么?

前言:本人是一位单片机软件工程师,在这里记录一下自己的学习笔记。文档中可能存在不足或错误的地方,欢迎大家批评指出,谢谢!


一、什么是堆栈?

说到堆栈,肯定跟内存分区有关系。据所周知,我们编写的代码中的函数、局部变量、全局变量、常量都是要占内存的。

内存又可以分为四个区:代码区、数据区、堆区、栈区。

代码区

在程序运行前加载到内存中,这块内存是只读的。

1、函数定义:void test()...

2、结构体定义:struct Data{}...

3、类定义:class Man{}...

如果想用指针去修改这部分内存,就会爆炸

错误示范:

void test(){} char* p = (char*)test; *p = 48;

数据区

逻辑上连续的内存(常量字符串也是只读的)

1、全局常量:const int g_num1;

2、(全局)变量:int g_num2;

3、常量字符串:"常量字符串";

4、静态变量:static int num = 30;

常量字符串也是只读的,如果又想用指针骚操作也是不行的。强行修改也会炸

错误示范:

char* p = (char*)"我是一个大帅哥"; *p = '6';

除此之外其他的全局变量,甚至是const修饰的,都可以用指针骚操作了。

正确示范;

const int g_num1; int* p = &g_num1; *p = 666;

堆区

用malloc和new关键字申请的内存存放在堆区

注:堆区内存申请了不用必须要记得释放

int*p = (int*)malloc(200); char* data = new char[2000]; free(p); delete[] data;

堆区的大小是动态增长的,申请内存时只要系统有富余内存,就可以申请得到。所以堆区的内存块是不连续的。

栈区

栈区是程序启动时就已经分配好的一块内存,大小是固定的。

通常容量很小,在windows上的是1MB,在Linux上是8MB。

栈区里面是如何存放的呢?

void test2(int count){ int a = 40; } void test1(int num){ static int s_num = 50; int a = 30; test2(num); } int main(){ int a = 20; test1(a); return 0; }

看这样一段代码,黑框表示栈区。

1、int a = 20; 这时候就会把a这个变量压入栈帧。这个局部变量存储在栈区

2、test1(a); 这句时,会生成一个新的栈帧。同时把当前test1的调用地址压到最顶的栈帧中作为返回地址。

3、同时传入一个参数a,相当于生成了一个变量压到这个栈帧中,用来接收外部传进来的值。

4、static int s_num = 50; 这是个函数内的局部变量,存在数据区中,存在于整个程序的生命周期。

5、int a = 30; 创建了一个局部变量,也是存放于该栈帧中。

6、test2(num); 此步调用其他函数,就会生成新的栈帧,同时把地址压进去。

7、同时传入一个参数num,相当于生成了一个变量压到这个栈帧中,用来接收外部传进来的值。

8、int a = 40; 局部变量,继续放在顶部栈帧中

栈区就是用来存储程序返回地址参数局部变量的。

因为由于栈帧的保护,是的不用函数里的同名局部变量都能正确访问自己的内存,互不干扰。

二、大坑

坑点1:

假如在test1中返回局部变量的指针会怎么样呢?

void test1(int num){ static int s_num = 50; int a = 30; test2(num); return &a; }

答案也一样是会爆炸,因为你指向的内存已经被回收掉了,这块内存会被后面运行的其他代码给覆盖掉。

所以说千万別返回一个局部变量的地址来使用。点

坑点2:

栈区还有一个坑点就是:栈区的空间非常小,如果存满再继续存的话,就会导致栈溢出导致程序崩溃。

举例1:使用局部变量声明大内存数组

int main(){ char buff[2000000]; }

举例2:递归函数导致的真层次调用

void test(int num){ if(num > 0){ test(num - 1); } } int main(){ test(10000); }

三、总结

代码区和数据区在程序,运行前已经加载了,大小固定,逻辑上这两个区的地址是连续的,处于低地址。

接着是堆区,运行过程中是动态改变的,处于较高的地址上。

最后是栈区大小固定,占用情况可变,处于高地址上。

http://www.jsqmd.com/news/472192/

相关文章:

  • 7步打造实时信用卡欺诈检测系统:PostgresML终极实战指南
  • MetaSeq模型编辑完全指南:安全修改预训练模型知识的10个关键技巧
  • uni-app x 学习系列(五)—— 视图容器 之 View 视图组件
  • 10个高级Android Gradle面试问题与解答:助你轻松拿下Android开发岗位
  • eslint-plugin-sonarjs核心规则解析:如何检测并修复常见代码问题
  • 如何用DeepSpeedExamples快速训练类ChatGPT模型:完整指南与实战技巧
  • Schej.it高级使用技巧:如何利用文件夹功能组织多个会议
  • 终极Maccy瘦身指南:5个高效方法减小macOS剪贴板管理器体积
  • 如何用External-Attention-pytorch构建强大的情感分析系统:文本与语音情感识别完整指南
  • 如何快速上手Transformer模型:run_model_example函数完全指南
  • 深入浅出理解电感:从理论到实践的电路“惯性”元件
  • embedded-graphics核心功能解析:掌握DrawTarget接口与显示驱动集成
  • 终极指南:如何让Maccy实现跨屏幕剪贴板管理,提升多显示器工作效率
  • QuickGUI界面详解:探索直观设计背后的用户体验哲学
  • 终极指南:ExcelJS中ProtectionXform如何实现电子表格保护设置的XML转换
  • Windows 12前瞻:AI硬件强制升级与订阅制来袭
  • ngxtop vs 传统监控工具:为什么它是Nginx管理员的新宠
  • windows默认的环境变量及查看或设置环境变量
  • 【2026 最新】下载安装 Git 详细教程 (Windows)
  • LoRA训练助手开源可部署:支持私有化部署的LoRA训练辅助系统
  • 终极RetDec高级功能解析:探索函数识别与类型重建的核心技术
  • 基于微信小程序实现互助学习管理系统【项目源码+论文说明】
  • ngxtop常见问题排查指南:解决日志读取失败与权限问题的终极方案
  • 从崩溃到修复:TooLargeTool帮你彻底解决TransactionTooLargeException
  • ccmusic-database/music_genre部署教程:容器化打包(Dockerfile)与镜像体积优化技巧
  • 7个核心模块深度解析:Probabilistic-Programming-and-Bayesian-Methods-for-Hackers项目架构全指南
  • 先天易学:地支只有六冲,地支“合害迫会刑”根本不存在
  • 听我一句劝!家用充电桩别瞎买,这台“宝藏国货”让我彻底告别续航焦虑 - 深度智识库
  • Redis lua 执行性能优化
  • 记录踩过的坑-金蝶云·苍穹平台-流程开发