在c/c++中, malloc() 、calloc()、realloc()、free()都是与动态内存分配相关的函数(动态内存分配是在程序运行时在heap(堆)上进行)。四者都在头文件<stdlib.h>中进行定义。
本文先对malloc()和calloc()进行简单介绍,再对内存调整函数realloc()进行重点介绍,最后是示例程序。
一、malloc() 和 calloc() 主要区别:
1、原型
void* malloc( size_t size );
size为分配内存的总大小。
例如,为 int[10] 分配内存:malloc( sizeof(int) * 10).
void* calloc( size_t numElements, size_t sizeOfElement);
sizeOfElement 为分配内存的单元大小,numElement 为个数。即numElement 个大小为sizeOfElement 的内存。
例如,为 int[10] 分配内存:calloc( sizeof(int), 10)。
2、分配内存是否初始化
malloc() 不进行初始化,calloc() 进行初始化。
二、malloc() 和 calloc()的相同点
1、返回
如果调用成功,函数malloc()和函数calloc()都将返回所分配的内存空间的首地址,否则返回空指针NULL。所以调用之后最好进行一下判断。
int* arrMalloc = (int*)malloc(sizeof(int) * 10);
if(!arrMalloc){
printf("Allocation Failed!");
exit(-1);
}
int* arrCalloc = (int*)calloc(sizeof(int), 10);
if(!arrCalloc){
printf("Allocation Failed!");
exit(-1);
}
2、free() 释放
二者都使用free() 进行内存释放。free之后将其置为NULL,避免成为野指针。
free(arrMalloc);
arrMalloc = NULL;
free(arrCalloc);
arrCalloc = NULL;
注意,动态内存分配之后一定要进行释放,不然会造成内存泄漏(Memory Leak)。 同时,对于已经释放过的内存不能再次释放,否则会报错。
三、realloc()
realloc,动态内存调整(reset allocation),即对已经(使用malloc() 和calloc())分配的动态内存空间进行大小上的更改。
原理:
先判断当前的指针是否有足够的连续空间,如果有,即:realloc的内存 ≤ 原来的内存 + 原来的内存后面还剩余内存,则扩大mem_address指向的地址空间大小,并且将mem_address返回(注意:此时原内存空间里面的内容不变,还是返回原来内存的地址,但是是释放过后重新返回的);
如果空间不够,realloc将申请新的内存,按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。
//函数原型
void* realloc(void* mem_address, unsigned int newsize);
//mem_address:指要向改变内存大小的动态内存的指针名
//newsize:新的内存大小。注意是“总大小”,即sizeof(dataType) * newsize
说明:
- 新的内存可大可小
如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失。 - 返回值
如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL;
当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL时,原内存变成“free”的了。此时也返回为NULL。
int* arrMalloc = (int*)malloc(sizeof(int) * 10);
free(arrMalloc);
//即上下两个语句块等价
int* arrMalloc = (int*)malloc(sizeof(int) * 10);
realloc(arrMalloc, 0)
- 当内存不再使用时,应使用 free()函数将内存块释放。
- 如果 mem_address为 NULL,则realloc()和malloc()类似,分配一个大小为newsize的内存块,返回一个指向该内存块的指针。
int* arrRealloc = (int*)realloc(NULL, sizeof(int) * 10); //相当于(int*)malloc(sizeof(int) * 10)
int* newArray = (int*)realloc(arrRealloc, sizeof(int) * 20); //对内存大小进行更改
free(newArray); //释放内存
- realloc失败,即没有足够的空间可供扩展时,返回NULL,原来的内存大小不改变,不会被释放和移动。
- 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的,当然也可以为空。
四、示例程序
//错误操作示例
#include<stdio.h>
#include<stdlib.h>
int main(){
int* arrMalloc = (int*)malloc(sizeof(int) * 10);
if(!arrMalloc){
printf("Allocation Failed!");
exit(-1);
}
printf("malloc分配返回地址:%d\n",arrMalloc);
arrMalloc[0] = 1;
*(++arrMalloc) = 2; //错误操作
printf("第0个元素值:%d\n",arrMalloc[0]);
printf("第0个元素地址:%d\n",&arrMalloc[0]);
printf("第1个元素地址:%d\n",&arrMalloc[1]);
printf("操作过后arrMalloc地址:%d\n",arrMalloc);
free(arrMalloc);
arrMalloc = NULL;
return 0;
}
运行结果:
malloc分配返回地址:11080672
第0个元素值:2
第0个元素地址:11080676
第1个元素地址:11080680
操作过后arrMalloc地址:11080676
Process exited after 3.019 seconds with return value 3221226356
*(++arrMalloc) 操作改变了arrMalloc的值,后面free的时候程序异常退出。所以要注意在程序中不能改变malloc分配的返回地址。
//简单完整示例程序
/**********************
Author:Ice
Description:The usage of malloc() and realloc()
Date:2020/2/3
**********************/
#include<stdio.h>
#include<stdlib.h>
int main(){
int n;
scanf("%d",&n);
int* array = (int*)malloc(sizeof(int) * n); //使用malloc分配内存
if(!array){
printf("Allocation Failed!");
exit(-1);
}
int i;
for( i = 0; i < n; i++){
array[i] = i + 1;
printf("%d ",array[i]);
}
printf("\narray: %d\n", array);
int increment = 10;
int* newArray = (int*)realloc(array,(n + increment) * sizeof(int)); // 扩大内存,不用手动free(释放) array
if(!newArray){
printf("Allocation Failed!");
exit(-1);
}
for( i = n; i < n+increment; i++){
newArray[i] = i + 1;
printf("%d ",newArray[i]);
}
printf("\nnewArray: %d\n", newArray);
//打印出全部元素
for( i = 0; i < n + increment; i++){
printf("%d ",newArray[i]);
}
printf("\n");
free(newArray); //记得释放内存
newArray = NULL; //避免newArray成为野指针
return 0;
}
运行结果:
7
1 2 3 4 5 6 7
array: 136160
8 9 10 11 12 13 14 15 16 17
newArray: 136160
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Process exited after 3.933 seconds with return value 0
参考资料:
百度百科-realloc函数