malloc/calloc/realloc函数的区别及用法
malloc/calloc/realloc函数都是分配内存,但是也存在一定的差异。
1.malloc函数
malloc函数文档
函数原型:void* malloc (size_t size);
返回值: 成功时指向由函数分配的内存块指针,此指针的类型总是void*
,该数据指针可以转换为所需类型的数据指针(如下例的int类型),以便可以解除引用。如果函数未能分配请求的内存块,则空指针会被归还。
参数:size为要申请的空间大小,需要我们计算。如:
int *p=(int*) malloc(10 * sizeof (int))
,如果编译器默认int为4字节的话,那么10个int类型的空间大小就是40字节。一次性申请40字节的连续空间,并将空间基地址强转为int类型,赋值给指针p,此时内存里存放的值是不确定的。
2.calloc函数
calloc函数文档
函数原型:void* calloc (size_t num, size_t size);
返回值: 成功时指向由函数分配的内存块指针,此指针的类型总是void*
,该数据指针可以转换为所需类型的数据指针(如下例的int类型),以便可以解除引用。如果函数未能分配请求的内存块,则空指针会被归还。
参数:num为要分配的元素数,size为每个元素的大小。 其比malloc函数多了一个参数num,省去了需要人为计算所申请空间大小。比如要申请10个int类型的空间:int *p = (int *)calloc(10, sizeof (int))
。
calloc函数与malloc函数最大的区别是:malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,对空间逐一进行初始化,并设置值为0。
#include<iostream>
using namespace std;
int main() {
int* p = (int*)malloc(10 * sizeof(int));
int* pp = (int*)calloc(10, sizeof(int));
int i;
cout<<"malloc申请的空间的值:"<<endl;
for (i = 0; i < 10; i++)
cout<<*p++<<" ";
cout << endl;
cout<<"calloc申请的空间的值:"<<endl;
for (i = 0; i < 10; i++)
cout<<*pp++<<" ";
cout << endl;
return 0;
}
既然calloc不需要计算空间并且可以直接初始化内存避免错误,那为什么不直接使用calloc函数,malloc函数还有什么用呢?
主要原因就是效率。calloc函数由于给每一个空间都要初始化值,那必然效率比malloc要低,并且实际应用中,很多情况的空间申请是不需要初始值的,这也就是为什么许多初学者更多的接触malloc函数的原因。
3.realloc函数
realloc函数和上面两个有本质的区别,它用于对动态内存进行扩容(及已申请的动态空间不够使用,需要进行空间扩容操作)。
函数原型:void* realloc (void* ptr, size_t size);
返回值: 指向重新分配的内存块的指针,该指针可以是ptr或者一个新的地点。此指针的类型为void*,该数据指针可以转换为所需类型的数据指针,以便可以解除引用。
参数:ptr为指向原来空间基址的指针, size为接下来需要扩充容量的大小。
#include<iostream>
using namespace std;
int main() {
int* p = (int*)malloc(10 * sizeof(int));
int* pp = (int*)realloc(p, 40 * sizeof(int));
cout << "原来的p_Address: " << p << " " << "扩容后的pp_Address: " << pp << endl;
return 0;
}
扩容后地址和原先地址是不一样的,但是这仅仅取决于扩容的内存大小。
实际上:
- 如果size较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容,并返回原动态空间基地址;
#include<iostream>
using namespace std;
int main() {
int* p = (int*)malloc(10 * sizeof(int));
int* pp = (int*)realloc(p, 14 * sizeof(int));
cout << "原来的p_Address: " << p << " " << "扩容后的pp_Address: " << pp << endl;
return 0;
}
- 如果size较大,原来申请的空间后面没有足够大的空间扩容,系统将重新申请一块(20+size)*sizeof(int)的内存,并把原来空间的内容拷贝过去,原来空间free;如果size非常大,系统内存申请失败,返回NULL,原来的内存不会释放。
注意:如果扩容后的内存空间比原空间小,将会出现数据丢失,如果直接realloc(p, 0)
,相当于free(p)
。