前言:本篇文章介绍了如何正确利用malloc、calloc、realloc函数的动态开辟我们要使用的内存,还有在进行动态内存开辟的时候常见的一些错误
为什么会存在内存开辟?
首先,我们回忆一下到目前为止我们掌握的的内存开辟方式有哪些:
int a = 0;//在栈区连续开辟4个字节的空间
int arr[10] = { 0 };//在栈区连续开辟40个字节的空间
上述的内存开辟方式有两个特点:
- 内存开辟的大小是固定的
- 数组在声明时必须指定数组的长度,它开辟的内存在编译时候进行分配
malloc、free、calloc、realloc函数介绍
malloc
函数原型
void *malloc( size_t size );
函数功能
这个函数向内存申请一块连续可用,大小为size个字节的空间。如果开辟成功,则返回开辟好空间的起始地址;如果开辟失败,则返回一个NULL指针,因此要对malloc函数的返回值一定要做检查。如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。
函数使用
int *p = NULL;
p = (int *)malloc(10);//开辟一个大小为10个字节的空间
//对malloc的返回值进行检查
if (p == NULL)
{
perror("use malloc");
exit(EXIT_FAILURE);
}
//...
//使用这块空间
free
函数原型
void free( void *memblock );
函数功能
C语言提供了一个函数
free
,专门用来释放和回收的起始地址为memblock
动态开辟的内存块。如果参数memblock
指向的空间不是动态开辟的,那free函数的行为是未定义的;如果参数memblock
是NULL指针,则函数什么事都不做。
函数使用
int *p = NULL;
p = (int *)malloc(10 * sizeof(int));//开辟一个大小为10个整型的空间
//对malloc的返回值进行检查
if (p == NULL)
{
perror("use malloc");
exit(EXIT_FAILURE);
}
//...
//使用这块空间
free(p);//使用完这块空间一定要记得释放,否则会形成内存泄露
p = NULL;//这里很有必要
注意:malloc实际开辟的空间比我们开辟的空间要大,因为需要有一些空间来记录开辟空间的大小方便使用free函数。所以我们在用malloc开辟空间时尽量大一些,太小感觉没有必要。
calloc
函数原型
void *calloc( size_t num, size_t size );
函数功能
函数的功能是开辟num个大小为size的空间,并且把空间的每个字节初始化为0。如果开辟成功,则返回开辟好空间的起始地址;如果开辟失败,则返回一个NULL指针。这个函数与malloc的区别只在calloc会在返回地址之前把申请的空间的每个字节初始化为0。
函数使用
int *p = NULL;
p = (int *)malloc(10 * sizeof(int));//开辟一个大小为10个整型的空间
//p所指向的那块空间全部初始化为0
//对malloc的返回值进行检查
if (p == NULL)
{
perror("use malloc");
exit(EXIT_FAILURE);
}
//...
//使用这块空间
free(p);//使用完这块空间一定要记得释放,否则会形成内存泄露
p = NULL;
realloc
函数原型
void *realloc( void *memblock, size_t size );
参数介绍
- memblock:要调整那块空间的起始地址
- size: 调整后空间的大小
返回值介绍
- 情况一:原来的那块空间后边有足够的空间来进行调整,realloc函数直接在原来的空间后边追加空间,原来空间的数据依然存储在原来的空间,返回值也依然是原来空间的起始地址
- 情况二:原来的那块空间后边没有足够的空间来进行调整,realloc函数会重新找一块空间,将原来空间的值放进去,然后自动释放原来的空间,返回值为新开辟空间的起始地址
注意:由于以上两种情况,在使用realloc函数调整大小的时候一定要对realloc函数的返回值进行检查,然后在将返回值赋值给维护动态内存开辟那个指针,否则如果realloc函数没有调整成功,则原来的那块空间的起始地址也找不到了,会出现内存泄露的问题
函数功能
有时我们发现以前申请的空间不够用或者是太大了,为了合理的使用内存,我们一定要对开辟好的内存大小进行灵活的调整。realloc函数就可以做到对已经动态开辟好的内存大小进行调整,realloc函数的出现让动态内存管理变得更加灵活。
函数使用
int *p = NULL;
p = (int *)malloc(100);//堆空间上开辟一个大小为100个字节的空间
if (p == NULL)
{
perror("use malloc");
exit(EXIT_FAILURE);
}
//扩展容量
int *ptr = NULL;
ptr = realloc(p, 200);//调整动态开辟内存大小为200个字节
if (ptr == NULL)
{
perror("use malloc");
exit(EXIT_FAILURE);
}
else
{
p = ptr;
//参数检查无误后,将新地址赋值给维护动态开辟内存的指针
}
free(p);//使用完之后释放空间
p = NULL;
动态内存开辟常见错误
- 动态开辟内存后不进行释放,造成内存泄漏
- 对动态开辟的内存进行多次释放
- 对动态开辟的内存进行部分释放,不能对维护动态内存开辟的指针进行处理
- 释放并非动态开辟的内存是非法的
- 对动态开辟的内存进行越界访问
- 对空指针进行解引用操作
- 对已经释放的内存进行二次访问