1、malloc/free和new/delete之间关系和差异。
C通过malloc/free来管理动态内存,而C++通过new/delete管理动态内存。
malloc/free的使用方法与new/delete有所不同。
malloc/free:
int main()
{
int *p=(int *)malloc(sizeof(int));
free p;
return 0;
}
malloc的函数原型为void *malloc(size_t size)
new/delete:
int main()
{
int *p=new int;
delete p;
return 0;
}
new没有函数原型,因为new和delete都是C++中的关键字
总结它们之间的关联与区别:
(1)它们都是用来管理动态内存的。
(2)new/delete,malloc/free都要成对出现,否则会造成内存泄漏的问题。
(3)malloc函数在使用时需要指定开辟空间大小,而且因为malloc函数返回值是void*,所以需要强制转换。
而new则会自己及计算空间大小,返回对应类型指针。
(4)malloc/free只负责开辟空间释放空间,而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理
成员)。
(5)malloc/free是C的库函数,而new/delete是C++的关键字。
2、剖析new/delete、new[]/delete[]到底做了些什么事情。
在C++中,new/delete开辟对象空间,new[]/delete[]开辟对象数组空间。
new[]的方括号中是数组中对象的个数(N),使用new[]开辟空间时,不仅要开辟N个空间,还需要在这N个空间之前开辟4个字节的空间,
用来存放N,以此来告诉编译器要调用多少次构造函数,多少次析构函数。这4个字节非常重要。
int main()
{
int *p1=new int; //类型
int *p2=new int(3); //初始化
int *p3=new int[3]; } //数组个数
(1)new做了两件事:
a. 调用operator new分配空间。
b. 调用构造函数初始化对象。
(2)delete也做了两件事
a. 调用析构函数清理对象
b. 调用operator delete释放空间
(3)new[N]
a. 调用operator new分配空间。
b. 调用N次构造函数分别初始化每个对象。
(4)delete[]
a. 调用N次析构函数清理对象。(思考这里怎么N是怎么来的?)
b. 调用operator delete释放空间。
我们可以用图表示出来-------
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Array
{
public:
Array(size_t size = 10) //数组类的构造函数
: _size(size)
, _a(0)
{
cout << "Array(size_t size)" << endl;
if (_size > 0)
{
_a = new int[size];
}
}
~Array() //析构函数
{
cout << "~Array()" << endl;
if (_a)
{
delete[] _a;
_a = 0;
_size = 0;
}
}
#define NEW_ARRAY(PTR,TYPE,N)\ //利用宏开展实现new[]
do \
{ \
PTR = (TYPE*)operator new(sizeof(TYPE)*N+4); \ //调用operator new函数开辟N个TYPE类型的空间,还要另外开辟4个字节空间
(*(int*)PTR) = N; \ //在开辟的4个字节空间中存放N,即对象个数
PTR = (TYPE*)((int*)PTR + 1); \ //将PTR指针后移到对象空间
for (size_t i = 0; i < N; ++i) \ //对对象数组空间调用构造函数
new(PTR + i)TYPE; \
}while (false); \
#define DELETE_ARRAY(PTR,TYPE)\
do{ \
size_t N = *((int*)PTR - 1); \ //在NEW_ARRAY中PTR指向对象数组,现在将4个字节处的值取出来赋给N
for (size_t i = 0; i < N; ++i) \ //调用析构函数释放空间
PTR[i].~TYPE(); \
PTR = (TYPE*)((char*)PTR - 4); \ //开辟的空间还有4个字节未释放,将PTR前移,调用operator delete释放
operator delete(PTR); \
} while (false);
private:
int*_a;
size_t _size;
};
int main()
{
Array*p1;
NEW_ARRAY(p1, Array, 10);
DELETE_ARRAY(p1, Array);
system("pause");
return 0;
}
运行结果如下,可以看出,调用了10次构造函数和10次析构函数
void* realloc(void* ptr, unsigned newsize);
void* malloc(unsigned size);
void* calloc(size_t numElements, size_t sizeOfElement);
都在stdlib.h函数库内
它们的返回值都是请求系统分配的地址,如果请求失败就返回NULL
malloc用于申请一段新的地址,参数size为需要内存空间的长度,如:
char* p;
p=(char*)malloc(20);
calloc与malloc相似,参数sizeOfElement为申请地址的单位元素长度,numElements为元素个数,是申请连续字节空间,如:
char* p;
p=(char*)calloc(20,sizeof(char));
这个例子与上一个效果相同
realloc是给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度
如:
char* p;
p=(char*)malloc(sizeof(char)*20);
p=(char*)realloc(p,sizeof(char)*40);
C语言的标准内存分配函数:malloc,calloc,realloc,free等。
malloc与calloc的区别为1块与n块的区别:
malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。
calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。
realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。