动态内存开辟函数malloc,calloc,realloc和free
我们在向内存申请空间时,一般有如下几种方式:
//第一种: int main() { int a=10;//申请4个字节,一小块一小块申请 } //第二种 int main() { int arr[10];//申请40个字节,一大块一大块申请 }
这两种方式开辟的空间是固定的,不能变化的。但是对于空间的需求,不仅仅是上述情况,有时候我们需要的空间大小在运行程序的时候才知道。
接下来介绍动态内存函数malloc,calloc,realloc和free,以满足我们对内存的需要。
动态申请的内存在内存的堆区
注意:他们都是库函数,使用时需要引用头文件<stdlib.h> !!!
1.malloc和free函数
首先介绍动态内存开辟函数malloc和free
函数原型为:void *malloc(size_t size)
参数:需要开辟的空间大小,单位字节。
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针(这块空间的首地址)。
- 如果开辟成功,则返回一个指向开辟好空间的指针
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回类型是void*,所以这个函数不知道开辟空间的类型,具体使用时强制类型转换成需要的类型。
free函数是与malloc,calloc,realloc匹配使用的函数,在程序结束时用来释放开辟的空间,防止内存泄漏。
函数原型为:void free( void *p );
意思是释放p所指向的空间。
注意:free必须释放的是动态开辟出来的空间!!
以下是他们的使用方法:
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "errno.h" int main() { int arr[10]={0}; int *p=(int*)malloc(40);//向堆区开辟了40个字节 //int *p(int*)malloc(INT_MAX+1);//开辟失败时 //判断,检查,防止开辟失败 if(p==NULL) { printf("%S\n",strerror(errno));//提示错误信息 return 1;//结束运行 } //使用 int i=0; for(i=0;i<13;i++) { *(p+i)=i; } //打印 for (i = 0; i < 13; i++) { printf("%d ", *(p + i)); } //释放 free(p); //此时只是释放了开辟的40个字节,但是变量p内仍然保留原地址,如果这时有人使用了p,这时p是十分危险的,这是一个野指针!!所以要把p置空。 p=NULL; return 0; }
开辟成功时运行结果是:
开辟失败时运行的结果是:
2.calloc函数
接下来介绍另一个动态内存开辟函数calloc
函数原型为:void *calloc(size_t num,size_t size)
参数是:开辟类型的个数,开辟类型的大小。
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针(这块空间的首地址)。
- 功能是为num个大小为size的元素开辟一块空间,并且空间里每个字节自动初始化为0。
- 与函数malloc的区别只在于calloc会在返回地址之前把申请空间里的每个字节初始化为0。
如果开辟成功,则返回一个指向开辟好空间的指针
如果开辟失败,则返回一个NULL指针,因此calloc的返回值也要做检查。
返回类型是void*,所以这个函数不知道开辟空间的类型,具体使用时强制类型转换成需要的类型。
使用方法如下:
#include "stdio.h" #include "stdilb.h" #include "string.h" #include "errno.h" //开辟10个整型空间 int *p=(*int)calloc(10,sizeof(int)); //检查判断 if(p==NULL) { printf("%s\n",strerror(errno)); return 1; } //使用 int i=0; for(i=0;i<10;i++) { *(p+i)=i; } //打印 for(i=0;i<10;i++) { printf("%d ",*(p+i)); } //使用完后要释放 free(p); p=NULL; return 0;
成功开辟运行后的结果是:
验证其开辟空间后自动初始化为0的代码是:
int main() { int* p = (int*)calloc(10, sizeof(int)); if (p == NULL) { printf("%s\n", strerror(errno)); return 1; } int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } free(p); p = NULL; return 0; }
运行后的结果是:
3.realloc函数
最后介绍动态内存调整函数realloc
函数原型:void realloc(void ptr,size_t size)
参数:ptr是要调整的内存地址,size是调整之后的新大小
如果调整成功,则返回一个指向调整后空间的指针
如果调整失败,则返回一个NULL指针,因此calloc的返回值也要做检查。
返回类型是void*,所以这个函数不知道开辟空间的类型,具体使用时强制类型转换成需要的类型。
- 返回值为调整之后的内存起始位置
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
- realloc在调整内存空间时存在两种情况:
如上图所示,
情况1为在调整内存空间大小时后面的内存被占用,此时不会再向后调整以致覆盖被占用的内存,而是会重新寻找一块大小合适的内存进行调整,这时ptr指向的是调整后新内存的地址,并且原空间里的数据会自动复制到新空间,原空间也会自动销毁。
情况2是在调整内存空间大小时后面的内存足够,此时直接调整即可。
使用方法如下:
int main() { int* p = (int*)malloc(40); if (p == NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i + 1; } //扩容 int* ptr = (int*)realloc(p, 80);//不要直接使用p接收,防止调整失败 if (ptr != NULL) { p = ptr; } for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } free(p); p = NULL; return 0; }
调整成功后的运行结果是: