动态内存开辟函数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;
}
调整成功后的运行结果是: