【C/C++基础】动态内存管理,内存分区模型,栈区堆区,new开辟内存

 

🍉内容专栏:【C/C++要打好基础啊】

🍉本文脉络:动态内存管理,内存分区模型,栈区堆区,new开辟内存

🍉本文作者:Melon西西

🍉发布时间 :2023.1.26

目录

1.为什么要有动态内存管理:

2.内存分区模型:

2.1C++程序在执行时,将内存大方向划分为四个区域:

代码区:存放函数的二进制代码,由操作系统进行管理

全局区:存放全局变量和静态变量以及常量

栈区:存放函数的参数值,局部变量等,由编译器自动分配释放

堆区:由程序员分配和释放,如果程序员不释放,程序结束时由操作系统回收。

2.2.程序执行前:

3.3由程序员管理的堆区,在C++中主要利用new在堆区开辟内存 

3、动态内存函数:

3.1. malloc。void* malloc (size_t size);

3. 2.realloc,重新开辟内存。realloc函数可以做到对动态开辟内存大小的调整。

4.动态内存常见错误:

4.1.对空指针解引用的操作

4. 2.对动态内存开辟空间的越界访问。

4.3.对非动态开辟内存使用free释放。

4.4.使用free释放一块动态开辟内存的一部分。

4.5.对同一块动态内存多次释放。

4.6.动态开辟内存忘记释放(内存泄漏)。

5、例子

5.1.形参开辟空间被销毁问题:

5. 2.返回栈空间地址的问题:​编辑


1.为什么要有动态内存管理:

用前面学的方法,int a=10;char arr[10]={0}这种,空间开辟的大小是固定的。但是对于空间的需求,有时候需要的空间大小在程序运行的时候才能知道,这时候只能用动态内存分配了。

2.内存分区模型:

2.1C++程序在执行时,将内存大方向划分为四个区域:

代码区:存放函数的二进制代码,由操作系统进行管理

全局区:存放全局变量和静态变量以及常量

栈区:存放函数的参数值,局部变量等,由编译器自动分配释放

            注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

堆区:由程序员分配和释放,如果程序员不释放,程序结束时由操作系统回收。

内存四区的意义:不同区域存放的数据,赋予不同的生命周期,让编程更灵活。

2.2.程序执行前:

程序执行前又代码区和全局区,栈区和堆区在程序运行后才有!!

在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域:

代码区:存放CPU执行的机器指令;

              代码区是共享的内存中只有一份代码即可,也是只读的,防止意外修改。

 全局区:该区域的数据在程序结束后由操作系统释放。

3.3由程序员管理的堆区,在C++中主要利用new在堆区开辟内存 

利用new关键字,可以将数据开辟到堆区,利用delete释放

用栈上的指针保存了堆区存放10的地址编号,当在解引用*p的时候也会拿到10

void  * func()
{
    int * p = new int (10) ;
    return p ;
}
int main()
{
     int * p = func();
     cout<< *p<<endl;  //输出为0
     delete p ;     //释放p 

int * arr = new int [10] ;  //10代表数组有十个元素,arr返回的是数组首地址。

delete arr ;

3、动态内存函数:

栈区:    局部变量,函数的形式参数。

堆区:   malloc/free,malloc,realloc,动态内存分配。

静态区:全局变量,静态变量。

3.1. malloc。void* malloc (size_t size);

函数向内存申请一块连续可通的空间,并返回指向这块空间的指针。如果开辟成功,则返回一个指向开辟好空间的指针;如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。两种写法:

​​​l

 

3. 2.realloc,重新开辟内存。realloc函数可以做到对动态开辟内存大小的调整。

假设40内存不够用了,想扩容成80空间放20个int元素:

 relloc函数会把前面的东西拷贝到新地址上,同时把旧的空间free掉。

如果扩容失败会返回空指针,为了防止前面东西丢失,后面用if语句再判断一下扩容后的是否为空

4.动态内存常见错误:

4.1.对空指针解引用的操作

解决办法:对函数的返回值进行判断,如果=NULL直接返回不往下走。

4. 2.对动态内存开辟空间的越界访问。

动态内存开辟空间和数组相似,都是在内存开辟一块连续的空间,访问的超出范围就会越界访问。

解决办法:自己仔细检查,编译器不会帮你。

4.3.对非动态开辟内存使用free释放。

局部变量的内存编译器会自动释放。

4.4.使用free释放一块动态开辟内存的一部分。

解决办法:free必须指向动态开辟内存的起始部分。

4.5.对同一块动态内存多次释放。

4.6.动态开辟内存忘记释放(内存泄漏)。

5、例子

5.1.形参开辟空间被销毁问题:

1.

  

分析:str空指针传给形参p,给p开辟100个内存空间没问题。但是p是形参,出了Memory函数p就销毁了,找不到p的起始地址了,无法释放内存,内存泄漏。销毁后str又成了空指针,对空指针解引用,程序崩溃。

正确修改:不适用形参实参,使用传地址。

5. 2.返回栈空间地址的问题:

分析:非法访问,和上面的类似,char p是临时变量,出来函数被收回,Test可以得到p return回来的地址,但是没有使用权限了,此时str指向一块空空间,成了野指针。栈空间地址不能随意返回,和变量不一样。


写在最后:

博主大一学识尚浅,内容仅供参考,欢迎大家在评论区交流分享。

以后会经常发关于C/C++的学习心得,感兴趣的小伙伴可以点个关注支持一下^_^

  • 18
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值