首先,在C中我们使用malloc,calloc,realloc对内存空间的动态申请,并使用free完成对所申请到空间的释放,如下的一个简单操作示例:
//申请空间
int* p1 = (int*) malloc(sizeof (int));
int* p2 = (int*) malloc(10*sizeof (int ));
//释放空间
free(p1);
free(p2);
p1 = NULL;
p2 = NULL;
我们完成对申请一个int类型大小字节、对10个int类型大小字节的空间申请和对这两块空间的释放。那为什么要对p1和p2指针至空呢? 这边涉及到了野指针以及内存空间泄漏的问题,如果我们不对释放的这两个指针置NULL的话,在接下来程序的执行至结束之前的这段时间我们再也不能访问到这两块空间,这也就是内存泄漏问题。那野指针又是什么呢?简单来说就是未进行初始化的指针,它因为没有初始化所以指向内存中随机的位置。并且我们是不允许对未初始化的指针解引用的。 所以,为防止对空指针的解引用,我们对上面操作动态申请空间操作更规范的做法如下:
int* p1 = (int*) malloc(sizeof (int));
if (*p1 == NULL){
perror("申请空间失败!");
}
那malloc,calloc,realloc这三者都是动态申请空间,它们有什么区别呢? 1. malloc是对空间申请,但这片空间里的值都是随机的; 2. calloc相比于malloc多做一个事情,那就是它申请到的空间里面的值全都初始化为0; 3. 而realloc就复杂了许多,realloc可以在原来的空间紧接着扩容,或者是缩容。
在C++中我们可以用new来完成上面p1和p2内存申请的操作,如下:
int* p3 = new int;
int* p4 = new int[10];
delete p3;
delete[] p4;
p3 = NULL;
p4 = NULL;
个人认为这个写法更加便捷,可以看看如下这个例子:
在C语言中我们创建一个单链表,我么需要自己完成一下操作:
typedef struct ListNode{
int data;
struct ListNode* next;
}LNode;
LNode* createLNode(int x){
LNode* tmp = (LNode*) malloc(sizeof (LNode));
tmp->data = x;
tmp->next = NULL;
return tmp;
}
int main(){
LNode* node0 = createLNode(0);
LNode* node1 = createLNode(1);
LNode* node2 = createLNode(2);
node0->next = node1;
node1->next = node2;
return 0;
}
在C++中我们只需要这样做,不需要额外定义一个函数完成申请结点和初始化:
class ListNode{
public:
int _data;
ListNode* _next;
ListNode(int x)
:_data(x)
,_next(NULL)
{}
};
int main(){
ListNode* node0 = new ListNode(0);
ListNode* node1 = new ListNode(1);
ListNode* node2 = new ListNode(2);
node0->_next = node1;
node1->_next = node2;
return 0;
}
那么对于new和delete,那它们和malloc和free有什么完善吗?
1.?对于内置类型,new和malloc,delete和free是没有区别的;
2. 对于自定义类型,malloc只申请空间,new申请空间和构造函数初始化,free只释放空间,而 delete调析构函数释放资源和释放空间;
3.?malloc是一个函数和new是操作符,所以用法也不太一样,malloc返回的是一个void*类型,而new返回的是对应申请对象的类型的指针;
4. new申请空间失败了会抛出异常,而malloc返回0。
我们这里有一个简单的People类,如下:
class People{
public:
People(){
_age = 25;
_sex = 1;
}
private:
int _age;
char _sex;
};
People* peo1 = (People*) malloc(sizeof (People));
People* peo2 = new People;
free(peo1);
delete peo2;
我们分别采用malloc和new的方式完成对内存的申请,我们在调试下可以发现,对于自定义类型malloc只完成了申请空间,而new它还会调用构造函数初始化。如下:
peo2中的_age = 25, _sex = 1,是调用了类中的构造函数的结果,而peo1则没有,这也验证了上面说到的区别。
最后,在这里顺便提一下operator new就是由malloc和异常处理实现的,它在申请空间失败的时候会抛出异常,我们可以捕获,也可以不做任何处理。而new是由operator new和调用构造函数实现的,这也就是上面提到new和malloc的区别的原因。
以上内容如有错误欢迎大家指正。