malloc和new
若想在堆区开辟空间时,C是使用malloc函数,而在C++则是使用new关键字。那么,C中的malloc和new有什么区别呢?这也是在面试时常见的问题。
目录
一、malloc和new的基本用法
二、自由存储区&堆的概念
三、malloc的实现方式
四、new的实现方式
一、malloc和new的基本用法
malloc: 它是C语言的一个函数,主要是在堆区申堆区请一块指定大小(由开发者指定)的内存空间,由开发者自己管理那一块内存空间。如下:
int *p = (int*)malloc(sizeof(int));
这里的意思是:在堆区申请一块长度为int字节的内存空间,这里可以使用字面变量,但是不建议,因为很危险,然后malloc返回出开辟后的空间,它返回的是void*类型,所以这里我们强转为自己想要的类型。
new: C++中开辟空间的关键字,主要作用是在自由存储区申请一块内存空间,申请一块内存空间。如下:
int *p = new int(20);
上面的意思是:在自由存储区申请一块长度为int的内存空间,里面存放着值为20。
从宏观上看,这就相当于C++中的bool类型和Java中的boolean类型一样,都是实现同样的功能,这是它们本质的作用,但是往跟深的看那还有有很多不一样的。malloc和new都是自己开辟内存空间,自己管理释放,相对的配套使用则是free()函数和delete关键字。其中free函数是用来释放malloc申请的空间,而delete是释放new开辟的空间。
二、自由存储区&堆的概念
在某些教材中,C++的分区模块是四大部分:代码区、全局区、栈区、堆区。这样说也没错,但实际上还有一个分区:自由存储区(free store)。关于对自由存储区的解释:自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。而堆(heap) 是C语言和操作系统的一个术语,堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能。我们可以用土办法来下面代码输出的结果:
int* p = (int*)malloc(4);
cout << "malloc = " << p << endl;
p = (int*)malloc(4);
cout <<"malloc = " << p << endl;
int* p2 = new int(50);
cout << "new = " << p2 << endl;
int *p3 = new int(100);
cout << "new = " << p3 << endl;
运行结果为:
可以发现两个malloc出来的地址和new出来的不太一样,这是因为C++使用的区域是自由存储区。关于自由存储区的来历,它是C++在堆上建立的一块区域,其中就是供new来使用。但是需要注意:自由存储区并不等价于堆区,这一点是不能弄混的,不能说自由存储区建立在堆区上那就是堆了。
三、malloc的实现方式
malloc的实现方式是将堆的特定段空间申请出来,然后供开发者使用,我们以下面这个为示例:
int* p = (int*)malloc(sizeof(int));
上面说过。malloc是个函数,sizeof(int)表示申请的空间大小,之后返回void*类型的地址,这里转为int类型的地址,这一步一定要转类型,否则有可能出现乱码,例如下面这种情况:
void* p = malloc(sizeof(char));
char* ch = (char*)p;
*ch = 'a';
cout << ch << endl;
输出结果:a葺葺葺葺葺輯竱1,反正就是乱码。
四、new的实现方式
new关键字的实现方式是申请一块特定的区域给某个类型,而且更智能,而非malloc那么繁琐,语法上也更加简单也更智能,并且支持重载。C++底层源码中它是这么写的:
这是编译器提供的底层和重载,可以看见它还重载了[],保证在创建数组的时候能使用,我们也可以自己重载。它在申请内存时分为三部分:
1、调用operator new
2、编译器运行相应的构造函数以构造数据类型,并为其传入初值。
3、对象构造完成后,返回一个指向该数据类型的指针。
注意:当我们重载new的时候,它存放的地方是由我们指定的。在众多C++编译器中,有部分编译器new关键字在底层的写法就是采用malloc来实现,这就是上面所说的有些教材说new是建立在堆区的。