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

内存管理这一块

文章目录

  • 前言
  • 一、C/C++内存分布
  • 二、C语言中动态内存管理方式
  • 三.C++的内存管理方式
    • new/delete操作内置类型
    • new/delete操作自定义类型
  • 四.定位new
  • 总结


前言

在一行一行的代码之中,不同的数据存放的位置是有所不同的,正是因为这些数据的性质不同,所以才被安排存放在不同的区域
所以,身为预备程序员,要能够分辨出不同的数据所存放的位置。


以下是本篇文章正文内容,下面案例可供参考

一、C/C++内存分布

我们先来看下面的一段代码和相关问题

int golbaval = 1;
static int staticGlobalvar = 1;
void test()
{static int staticval = 1;int localvar = 1;int num1[10] = {1,2,3,4};char char2[] = "abcd";const char * pchar3 = "abcd";int * p1 = (int *)malloc(sizeof(int)*4);int * p2 = (int *)calloc(4,sizeof(int));int * p3 = (int *)realloc(p2,sizeof(int)*4);free(p1);free(p3);}

代码如上,题目如下:
选项A.栈 B.堆 C.数据段(静态区)D.代码段(常量区),下面变量分别存放在哪里?
globavar(C)
staticGlobaval(C)
staticval(C)
localvar(A)
num1(A)

——往全局中看,globavarstatGlobaval均是在全局中定义的,所以在全局中定义的,均属于静态区
——static修饰的变量不管在哪里定义都位于静态区,所以在Test函数的staticval也位于静态区
——locavar与num1都是在局部定义的变量,出了这个Test函数,两者均会被销毁,生命周期较短,所以这两者均属于

接下来,是一些比较难的。
char2(A)
*char2(A)
pchar3(A)
*pchar3(D)
p1(A)
*p1(B)

我们可以看到,char2是数组名,char2的空间其实是有5个空间,最后一个空间留给了‘\0’,我们都知道,字符串都是位于常量区的,但是char是我们在栈中定义出来的数组名,也是个变量,相当于常量区中的"abcd\0"拷贝了一份给了char2,所以char2是位于中的,*char2也是位于中的,因为是从常量区拷贝一份给了栈上的char2。
pchar3是一个指针,它指向的位置是指向位于常量区的字符串"abcd\0",pchar3是我们在栈中定义的一个指针变量,所以它位于中,*pchar3就是这块位于常量区的"abcd\0"它位于代码段(常量区)
p1是我们在栈中定义的一个指针变量,与pchar3性质相同,所以它是位于
上的一个变量,这个指针变量指向的这块空间是位于上开辟的,所以p1在上,*p1位于堆上。
在这里插入图片描述

【说明】
1.又叫堆栈-非静态成员变量/函数参数/返回值等等,栈是向下生长的。
2.用于程序运行时动态的内存分配,一般来说堆是向上身上的,也不排除有例外是向下身上。
3.数据段–存储全局数据和静态数据(像我们在全局中定义的变量以及我们使用static关键字修饰的变量)
4.代码段–可执行的代码/只读常量
在这里插入图片描述

二、C语言中动态内存管理方式

之前我们在前面的学习中就已经对动态内存开辟有了一定的了解,现在让我们回顾一下吧。
1.void* malloc(size_t size)

括号中输入的是需要向堆申请多少字节的空间,例如我们想向堆中申请5个int类型的空间,也就是20个字节,那么我们可以这样描述。(int )malloc(5sizeof(int))。

2.void * calloc(size_t n nemb,size_t size)

跟malloc类似,前面的是元素个数,后面是单个元素字节数,同样我们向堆中申请5个int类型的空间,用calloc是这样表示的,(int *)calloc(5,sizeof(int))。
注:calloc会将申请的空间全部初始化为0

3.void *realloc(void * prt,size_t size)

①realloc是用来调整之前申请的内存的空间大小,所以待调整的内存必须是之前在堆上分配的空间。
②prt是指向原先内存的指针,size是新内存字节数,返回的是指向新内存的指针,故需要强转。
③申请失败会返回NULL,所以需要检查申请是否成功。

void test()
{int *p2 = (int *)calloc(4,sizeof(int));int *p3 = (int *)realloc(p2,sizeof(int)*10);//这里需要free(p2)吗?
}

这里是不需要free(p2)的,p2是指向我们calloc申请的空间,p3则是指向我们新内存的空间,以上代码是对原先的空间进行扩展。

假设申请失败,则返回空指针。如果申请成功,分为两种情况。
①直接在原先的空间后面追加需要添加的空间,这种情况下,p2就跟p3相同,所以free(p3)就等同于free(p2)。
②后面的空间不允许你进行扩展,那么编译器就会向堆上重新申请一块大的空间(这块空间的大小与我们扩展后的空间大小一致),然后把旧空间上的数据拷贝到新申请的大空间里,然后释放旧空间,即此类情况,编译器会自动帮我们释放p2。

三.C++的内存管理方式

C语言的内存管理方式在C++上同时适用,但是在一些场景上C语言就显得有点力不从心,所以C++推出了属于自己的内存管理方式。通过new以及delete进行操作。

new/delete操作内置类型

void test()
{//申请一块int类型的空间int * p4 = new int;//申请一块int类型的空间,并将其初始化为10int * p5 = new int(10);//动态申请10个int类型的空间int * p6 = new int[10];//释放空间delete p4;delete p5;delete []p6;
}

这里要对应上,你是new就delete,你是new[],就delete[]。不然容易出错。

new/delete操作自定义类型

class A
{
public:A(int a = 0):_a(a){cout<<"A()"<<endl;}~A(){cout<<"~A()"<<endl;}
}
private:int _a;
int main()
{A * p1 = malloc(sizeof(A));A * p2 = new int(1);free(p1);delete p2;//内置类型几乎没有区别int * p3 = (int *)malloc(sizeof(A));int * p4 = new int;free(p3);delete p4;return 0;
}
class Stack
{
public:Stack(int n = 4):_a(new int[n]),_size(0)_capacity(n){cout << "Stack()"<<endl;}~Stack(){free(_a);_size = _capacity = 0;}
private:int _a;size_t _size;size_t _capacity;
}
int main()
{Stack * p1 = (Stack *)malloc(sizeof(A);Stack * p2 = new Stack(10);free(p1);delete p2;
}

直接上结论:new/delete与malloc/free之间的区别是,前者new的过程中会调用构造函数,delete会调用析构,而后者没有执行此操作。
★new/delete的本质

new和delete相比于malloc/free而言,new会在malloc的基础上多了一次构造函数,delete会在free清理资源(也就是析构函数)的基础上,再次释放对象。这里我画个图,以Stack这个类举例
在这里插入图片描述

由图可知,在栈这个类里面,new会先对栈对象的整体大小进行一个计算,开出一个能够存放栈三个成员变量的空间,然后再调用构造函数对这个对象进行初始化。最后来到了delete,delete先把向堆上申请的空间资源进行一个清理,再对我们这个对象空间给释放。
简单讲,new就是operator new + 构造,delete就是operator delete + 析构。

new原理:
operator new函数申请空间。
在申请的空间上执行构造函数,完成对象的构造。
delete原理:
在空间上执行析构函数,完成对象中资源的清理工作。
调用operator delete函数释放对象的空间。
注意:new在创建对象的时候,创建失败要抛异常。

四.定位new

定位new是一种特殊的new,前面我们已经学过了普通的new,现在跟着我来看看这两者的区别吧。
简单一句话,普通new就是创建对象+构造,定位new就只有构造。

int main()
{A * p1 = (A*)malloc(sizeof(A));//这里p1只是指向了这块空间,还不能算作是关于A的对象,因为它还没有初始化。new(p1)A;//这一步就是对A的一个构造函数,此处也可传参参与构造p1->~A();//需手动进行析构清理资源(对象自身管理的资源)free(p1);//释放对象本身所在的内存块//下面案例更加具体A * p2 = (A*)operator new(sizeof(A));//operator new参与创建对象本身的空间new(p2)A(10);//这里使用定位new并且传参对对象进行构造p2->~A();free(p2);
}

在这里插入图片描述

总结

本文对内存管理进行了一个简单的讲解。new/delete相比于我们之前传统的内存管理方法要更方便,这里鼓励大家多使用new/delete进行内存的一个开发。


文章转载自:

http://en4QSxrm.gqwpL.cn
http://4wJTBeyK.gqwpL.cn
http://Koh7tCvf.gqwpL.cn
http://yYogbka9.gqwpL.cn
http://vE9id4R2.gqwpL.cn
http://z6XxYG5k.gqwpL.cn
http://9Cbc1EQ4.gqwpL.cn
http://IlBKHnsp.gqwpL.cn
http://PEkTKJgv.gqwpL.cn
http://460Z2OQW.gqwpL.cn
http://5YhDOUB8.gqwpL.cn
http://75BycaOB.gqwpL.cn
http://U2qMlXJj.gqwpL.cn
http://rSfyTUVe.gqwpL.cn
http://PHTFZ1Zj.gqwpL.cn
http://0wrhjMCA.gqwpL.cn
http://uUWmTTxz.gqwpL.cn
http://ODKj4jaC.gqwpL.cn
http://NkzvQn2g.gqwpL.cn
http://wg1E8oXK.gqwpL.cn
http://eXn06nPk.gqwpL.cn
http://tybRbWoj.gqwpL.cn
http://1DJxgtyJ.gqwpL.cn
http://bmR5HsII.gqwpL.cn
http://0LK2nEY9.gqwpL.cn
http://Zvfek1RJ.gqwpL.cn
http://wlf3KWcX.gqwpL.cn
http://ju29w9r8.gqwpL.cn
http://3CY0ylrC.gqwpL.cn
http://Uo2WoZMw.gqwpL.cn
http://www.dtcms.com/a/375376.html

相关文章:

  • 【深度学习新浪潮】什么是具身智能?
  • Linux tc 常用命令总结(网卡限速、延迟、丢包与整形)
  • Windows 命令行:路径末端的反斜杠
  • Shell脚本编程基本认识
  • Redis 面试
  • 大学地理信息科学该如何学习才能好就业
  • 浅谈“SVMSPro视频切片”技术应用场景
  • OpenHarmony多模输入子系统全链路剖析:从HCS配置到HDI芯片驱动源码深度解读
  • 1. linux 下qt 应用开机自启,需要sudo时
  • QML中的Popup
  • Cursor Pro试用
  • shell介绍
  • vla 开源最强的模型是哪一个
  • FreeRTOS任务切换详解
  • 面试不会问题
  • 享元模式,用Qt/C++绘制森林
  • GO RPC 教学文档
  • Atlantis Word Processor:全方位的文字处理专家
  • [iOS] 单例模式的深究
  • 视频通话实现语音转文字
  • String-HashCode源码分析
  • 深入浅出C++继承机制:从入门到实战
  • 级联框的实现
  • android 性能优化—内存泄漏,内存溢出OOM
  • 从PyTorch到ONNX:模型部署性能提升
  • JAVA:实现快速排序算法的技术指南
  • SQL 触发器从入门到进阶:原理、时机、实战与避坑指南
  • 无标记点动捕技术:重塑展厅展馆的沉浸式数字交互新时代
  • 【Agent】DeerFlow Planner:执行流程与架构设计(基于真实 Trace 深度解析)
  • R语言读取excel文件数据-解决na问题