欢迎来CILMY23的博客喔,本篇为【C语言】内存操作篇---动态内存管理----malloc,realloc,calloc和free的用法【图文详解】,感谢观看,支持的可以给个一键三连,点赞关注+收藏。
前言
在学完结构体后(结构体1:http://t.csdnimg.cn/ZkBHj结构体2:http://t.csdnimg.cn/rmAwJ)我们要进入新篇章了,内存操作中最关键的一节---动态内存管理,本篇博客将了解malloc,realloc,calloc和free的用法。
目录
一、为什么会有动态内存管理?
二、malloc和free
malloc的介绍和使用
空间回收
free的介绍和使用
三、realloc
realloc的介绍和使用
四、calloc
calloc的介绍和使用
一、为什么会有动态内存管理?
在过去我们向内存中申请空间有两种方式,一是创建变量,二是创建数组
#include<stdio.h>int main()
{int C = 23;//申请四个字节空间char c = 'C';//申请1个字节空间char CI[10] = "CILMY23";//申请10个字节空间return 0;
}
但是上述的开辟空间的方式有两个特点:
• 空间开辟大小是固定的。
• 数组在声明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整
我们申请的空间都很固定,没法灵活调整,但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组和变量的编译时开辟空间的方式就不能满足了。
C语言引入了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活了。
二、malloc和free
malloc可以在cplusplus网站查询:malloc - C++ Reference (cplusplus.com)
malloc函数原型如下:
void* malloc (size_t size);
malloc的函数介绍如下:
malloc 的功能如下:
malloc的介绍和使用
malloc函数是头文件stdlib中的,malloc函数是用来向内存申请空间的(在堆区申请),在函数原型中我们可以看到有一个形参size_t size,根据Allocates a block of size bytes of memory, returning a pointer to the beginning of the block,我们知道这个形参是计算空间大小后得出的结果,比如申请40个字节空间,size就等于40.那它最后会返回一个指针,指向这个空间的起始位置,那返回类型是void*,因为我并不知道这段空间会干什么,所以返回void*(不懂可以看http://t.csdnimg.cn/dshm8),当malloc失败后,会返回一个NULL。
使用如下:
#include<stdio.h>
#include<stdlib.h>int main()
{// 向内存空间申请40个字节//将void*转换成int*类型将其存入指针变量pint* p = (int *)malloc(10 * sizeof(int));int i = 0;//将i存入开辟的空间for (i = 0; i < 10; i++){*(p + i) = i;}//将空间中的数值打印for (i = 0; i < 10; i++){printf("%d ", *(p + i));}
}
结果如下:
图解如下:
那如果我们申请失败了呢?那我们就可以用perror来直接打印错误信息。
if (*p == NULL)
{perror("malloc");
}
空间回收
malloc是在堆区申请空间的,malloc的空间回收有两种方法,一是free回收,二是程序结束的时候,由操作系统回收 我们这里主要讲free回收,首先回顾一下内存的区域,主要由堆区栈区和静态区构成,堆区是动态分配区,像malloc这些,栈区是临时的参数,局部变量和形式参数,静态区主要是全局变量和静态变量。
free的介绍和使用
free函数的原型如下:
void free (void* ptr);
free函数介绍如下:
free的功能和使用案例如下:
free函数是用来释放动态开辟出来的空间,给到地址就能释放地址所指向的位置
free的使用:
#include<stdio.h>
#include<stdlib.h>int main()
{// 向内存空间申请40个字节//将void*转换成int*类型将其存入指针变量pint* p = (int *)malloc(10 * sizeof(int));if (*p == NULL){perror("malloc");}int i = 0;//将i存入开辟的空间for (i = 0; i < 10; i++){*(p + i) = i;}//将空间中的数值打印for (i = 0; i < 10; i++){printf("%d ", *(p + i));}free(p);p = NULL;
}
我们使用free(),因为我们将p所指向的空间释放了,那p就成了野指针,我们就需要处理野指针,所以将p置空。
总结:
malloc如果开辟成功,则返回⼀个指向开辟好空间的指针。
• 如果开辟失败,则返回⼀个NULL 指针,因此malloc的返回值⼀定要做检查。
• 返回值的类型是void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
• 如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。free函数只能用来释放动态开辟的内存。
• 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
• 如果参数 ptr 是NULL指针,则函数什么事都不做。
三、realloc
realloc函数可以在cplusplus网站查询:realloc - C++ Reference (cplusplus.com)
realloc的原型如下:
void* realloc (void* ptr, size_t size);
realloc的函数介绍如下:
realloc的功能和使用案例如下:
realloc的介绍和使用
realloc的参数有void* ptr, size_t size,size就是要调整后的空间大小,ptr则是要调整的空间起始地址。realloc 的调整分两种情况,一种是原地扩,也就是后面的空间足够,如下图所示,未分配的空间加已分配的橙色空间刚好够size,或者小于size,则realloc原地扩
第二种情况是未分配的黑色空间加已分配的橙色空间,超过size后的字节,那realloc会到新的一块未分配区域重新开辟一块空间,来分配原先的字节,并将原来的地址做拷贝,最后返回新的空间地址,并且旧空间会自动释放掉。
realloc的使用:
#include<stdio.h>
#include<stdlib.h>int main()
{int* p = (int*)malloc(10 * sizeof(int));int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//调整申请的堆上内存int* tmp = (int*)realloc(p, 40);if (tmp != NULL){p = tmp;tmp = NULL;}else{perror("realloc");}free(p);p = NULL;return 0;
}
总结:
• ptr 是要调整的内存地址
• size 调整之后新大小
• 返回值为调整之后的内存起始位置。
• 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
• realloc在调整内存空间的是存在两种情况:
◦ 情况1:原有空间之后有足够大的空间
◦ 情况2:原有空间之后没有足够大的空间
四、calloc
calloc函数可以在cplusplus网站查询:calloc - C++ Reference (cplusplus.com)
calloc的原型如下:
void* calloc (size_t num, size_t size);
calloc的函数介绍如下:
calloc的功能和使用案例如下:
calloc的介绍和使用
calloc的参数是两个,一个是num,一个是大小size,其中一个给数量,一个给大小。calloc和malloc函数最大区别就是,calloc会赋一个初值,每个初值都是0. 使用和malloc是差不多的
使用如下:
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)calloc(10 ,sizeof(int) );int i = 0;for (i = 0; i < 10; i++){printf("%d ", p[i]);}printf("\n");for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d ", p[i]);}free(p);p = NULL;
}
结果如下:
如果我们只是想开辟空间,我们只需要用malloc,而calloc是把开辟出来的空间赋了一个初值。
总结:
• 函数的功能是为num 个大小为size的元素开辟⼀块空间,并且把空间的每个字节初始化为0
• 与函数malloc 的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全 0
感谢各位同伴的支持,本期动态内存管理篇就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞关注+收藏,若有不足,欢迎各位在评论区讨论。