【C++基础】内存分区模型
1|0内存分区模型
C++程序在执行时,将内存大致划分为4个区域
- 代码区:存放函数体的二进制代码,由操作系统进行管理
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值、局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
代码区:所有的代码的英文字母、注释
内存四区意义:
不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
栈区数据由编译器管理,堆区由程序员管理
程序运行前,内存划分了两个区域是代码区、全局区
程序运行后,内存中才会有栈区和堆区
1|1程序运行前
在程序编译后,生成了后缀名为exe的可执行程序,未执行可执行程序前分为两个区域
代码区:
-
存放CPU执行的机器指令(就是所写的代码)
-
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可,不造成资源浪费
所写的程序只要生成成功,就只有一份代码,不会因为每次要执行可执行程序,就再生成一份代码
-
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
- 全局变量和静态变量存放在此
- 全局区还包含了常量区,字符串常量和全局常量(const修饰的全局变量)也存放在此
- 该区域的数据在程序结束后由操作系统释放
全局区
全局变量:没有写在函数体中的变量
全局变量与普通局部变量的地址比较:
从输出内容可以看出,局部变量和全局变量没有放在一个段里
静态变量与全局变量、局部变量的地址比较:
从输出可以看出来,全局变量和静态变量是放在一块的,属于同一个区段里,即都放在全局区中。
常量分为字符串常量、const修饰的两种变量(const修饰的全局变量:全局常量、const修饰的局部变量:局部常量)
但是保存在全局区的只有字符串常量、全局常量(const修饰的全局变量)
字符串常量与局部变量、全局变量、静态变量的地址比较:
可以看出来,常量区的字符串常量和全局变量、静态变量都离得很近,同属于全局区,但是要细看的话,常量区和全局变量、静态变量稍微有点距离
const修饰的变量有两种
- const修饰的全局变量,称为全局常量
- const修饰的局部变量,称为局部常量
放在全局区的是全局常量
全局常量与局部变量、全局变量、静态变量、字符串常量的地址比较:
可以看出来,全局常量、字符串常量都放在全局区里很近的位置,全局变量、静态变量也放在全局区,只是与全局常量、字符串常量还有一定距离,但是离得不远
局部常量与局部变量、全局变量、静态变量、字符串常量的地址比较:
可以看到,局部常量并不存放在全局区,而是和局部变量存储在一块
综上,全局区里存储的数据:全局变量、静态变量、全局常量、字符串常量
不在全局区中的数据:局部变量、局部常量(const修饰的局部变量)
有局部两个字,就不会存放在全局区
全局区中的数据:全局变量、全局常量(const修饰的全局变量)、静态变量(static)、字符串常量
示意图:
总结:
- C++在程序运行前,分为全局区和代码区
- 代码区的特点是共享和只读
- 全局区中存放全局变量、静态变量、常量(全局常量、字符串常量)
- 常量区中存放 const 修饰的全局常量 和 字符串常量
1|2程序运行后
栈区
栈区:由编译器自动分配释放,存放函数的参数值、局部变量等。
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。
局部变量和形参都放在栈区
- 对于形参,在调用函数时,形参会在栈区开辟数据空间
- 对于局部变量,存放在栈区,栈区的数据在函数执行完后自动释放
定义在函数里的局部变量,在函数执行完后,会被编译器自动释放。如果我们在这个函数中返回这个局部变量的地址,那么编译器会保留一次这个地址的值,但是由于函数执行结束后,局部变量被释放,当第二次访问这个地址时,则无法访问到原本定义的值。
从输出结果可以看出,第一次对返回的指针进行解引用,还可以访问到原本的数据,但是第二次就不行了。这是因为编译器对这个数据进行了一次保留,但是由于在func函数执行完后,局部变量a已经被编译器释放,栈上的数据就清空了,再次访问这个地址只会是乱码。
所以,不要返回局部变量的地址
堆区
堆区:由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中,程序员主要利用关键字new在堆区开辟内存
这里的数据不会一直放在内存上,在程序运行期间,如果程序员不释放,则这个数据不会被释放,当程序结束时,会由操作系统回收
程序员自己开辟的内存,是由程序员自己管理的,存放在了堆区,所以函数执行完,会把栈区清空,但是不会影响到堆区。
语法:new 数据类型(值);
返回值:这段内存的地址
用同类型的指针去接收这个返回值。
此处需要注意:
在func中用于接收堆区内存地址的指针p1本质上也是一个局部变量,这个指针p1是开辟在栈区的,在func函数执行完后,它也会被释放。
所以我们在调用func函数时,已经在main函数中开辟了一个新的指针p来保存这个返回值,也就是保存了堆区的地址,所以即使func函数执行完,p1被释放了,但是堆区的地址我们已经获取到了,而且函数执行完时,堆区地址是不会释放的,所以我们可以多次访问这个堆区地址,并且每次输出都是一样的值。
若func返回的是局部变量的地址,这个指针所指向的内存是栈区,函数执行完,栈区清空后,这个地址的内存被释放了,所以即使我们在main函数中获取了这个地址也没用,编译器只会保留一次数据,第二次访问时就找不到这个数据了,已经被清空了。
1|3new操作符
C++中利用new操作符在堆区开辟数据,利用delete操作符在堆区释放数据
若开辟一个变量,语法:new 数据类型()
若开辟一个数组,语法: new 数据类型[数组长度]
利用new创建的数据,会返回该数据对应类型的指针,也就是存放在堆区的地址
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符 delete
释放单个变量,语法:delete 变量地址
释放数组,语法:delete[] 数组名
12行代码报错如下:
属于是非法访问。
__EOF__

本文链接:https://www.cnblogs.com/seansheep/p/15968996.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)