C中的动态内存方式
整体代码测试环境:VS 08
1.堆上申请内存空间
(1)malloc申请 内存空间
void* malloc(字节数)
说明:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数size为0,malloc的行为是标准是未定义的,取决于编译器
(2)calloc申请内存空间
void* calloc(元素个数,元素类型字节)-->0 初始化
说明:函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为 0。
- 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
(3)realloc申请内存空间
void* realloc(void* p, size_t size)
说明:ptr 是要调整的内存地址
- size 调整之后新大小 返回值为调整之后的内存起始位置。
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
- realloc在调整内存空间的是存在两种情况:
注意:他们三个都需要free来释放,否则会发生内存泄漏问题
2.栈上申请内存空间
使用_alloca在栈上动态开辟内存,栈上开辟的内存由编译器自动维护,不需要用户显示释放
<strong>C++的动态内存管理方式</strong>
C++中的动态内存方式
1.C++中通过new和delete运算符来进行动态内存管理
图 new和delete的使用方法
注:new申请出来的空间无需判空
new[]和delete[]一定要搭配使用,否则可能出现内存泄漏甚至崩溃的问题
class Test
{
public:
Test()
{
//_p = new int(10);
cout<<"Test():"<<this<<endl;
}
~Test()
{
/*if(_p)
{
delete _p;
}*/
cout<<"~Test()"<<this<<endl;
}
int data;
//int* _p;
};
void FunTestc()
{
Test *p1 = (Test*)malloc(sizeof(Test)); //没有调用构造函数,不是一个完整的Test类型对象,_p指向的空间是随机值
Test *p2 = (Test*)malloc(sizeof(Test));//屏蔽_p
delete p1;
delete[] p2;
Test *p3 = new Test;
Test *p4 = new Test;
free(p3);
delete[] p4;
Test *p5 = new Test[10];
Test *p6 = new Test[10];
free(p5);
delete p6;
}
int main()
{
FunTestc();
return 0;
}
一经调试,会发现走到 delete[] p2 的位置发生了中断,把 delete[] p2 屏蔽掉后,再往下走没有任何问题,但是一走到 delete[] p4的位置就又发生了中断 ,具体原因我们在下面进行剖析
但是如果在类里面加入 int* _p和析构函数,就会发现在一开始的mian函数里面的 p1就发生了错误,原因是malloc在开辟的空间的时候,没有调用构造函数,也就是没有完成对对象的赋值,所以没有创建一个完整的Test对象,自然也就崩溃了
那么问题来了,既然C中有了malloc/free来管理内存空间,为什么C++还要定义new/delete运算符来动态管理内存空间?(面试题)
1.他们都是动态管理内存的入口
2.malloc/free是C/C++标准库的函数,而new/delete是C++的操作符
3.malloc/free只是动态分配内存空间/释放空间,而new/delete除了分配空间还会调用构造函数和析构函数进行初始化和清理(清理成员)
4.malloc/free需要手动的计算类型大小且返回值是void*,需要用户自定义其类型,new/delete可以自己计算类型的大小,返回对应的类型指针
2.深度剖析new/new[]/delete/delete[]
class Test
{
public:
Test()
{
_data = 100;
cout<<"Test():"<<this<<endl;
}
~Test()
{
cout<<"~Test()"<<this<<endl;
}
int _data;
};
int main()
{
Test* pA = new Test;
delete pA;
/*Test* pA = new Test[10];
delete[] pA;*/
return 0;
}
- new
我们在main函数的第一句代码处下一个断点,然后往里面一走,就会发现里面调用的是这样的:
其实就是将malloc重新封装了一下
总结一下new的机制:
- delete
所以delete做的只有两件事: 调用pA对象指向的析构函数,对打开的文件进行关闭
调用operator delete标准库函数来释放该对象的内存空间 ,传入函数的参数为 pA 的值,也就是0x007d290
- new T[N]
经过调试发现new T[N]背后做了这些事
- .delete[]
那么delete[]就很简单了