当前位置:网站首页>(C语言)动态内存管理
(C语言)动态内存管理
2022-08-05 05:17:00 【Captain林】
本篇文章计划用最简单的方式向大家介绍C语言动态内存管理这一问题
如果各位看官姥爷们觉得有用的话,不妨动动你们手指,点赞、评论、收藏哦!
目录
1.为什么需要动态内存分配
我们常见的内存开辟方式有:
int a = 20;//在栈空间上开辟四个字节
char arr[10] = { 0 };//在栈空间上开辟10个字节的连续空间上述内存开辟方式有两个特点:
1. 空间开辟大小是固定的。2. 数组必须指定数组的长度,以获取所需内存。
但是我们对于空间的需求,不仅仅是上述的情况。有时候我们需要根据情况来决定开辟空间的大小
此时动态内存的作用就凸显出来了
2.动态内存的介绍
2.1malloc和free
void* malloc(size_t size);这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
void free(void* ptr);C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收
话不多说,直接上代码
int main()
{
int arr[40] = {0};
int* prt = (int*)malloc(40);//申请空间
//检查
if (prt == NULL)
{
perror("malloc");//检查错误的函数,要使用双引号,检查的是开辟空间的malloc
return 1;
}
//初始化
int i = 0;
for (i = 0; i < 10; i++)
{
*(prt + 1) = i;
}
//释放空间
free(prt);//这里释放的是地址,因此不需要解引用
prt = NULL;
return 0;
}2.2calloc
C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配,其具体使用我们结合下面一个函数来讲解
- 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
void* calloc(size_t num, size_t size);2.3realloc
- realloc函数的出现让动态内存管理更加灵活。
- 当我们发现过去申请的空间太小或太大,那为了合理的使用内存,我们可以使用realloc 函数实现对动态开辟内存大小的调整。
void* realloc(void* ptr, size_t size);话不多说,让我们一起来看一下calloc和realloc代码的实现吧
int main()
{
//申请空间
//calloc需要两个参数(元素、每个元素类型的大小)
//且在申请之初就会初始化空间为0
int* ptr = (int*)calloc(10, sizeof(int));//ptr必须是指针
//检查
if (ptr == NULL)
{
perror("calloc");//打印错误
return 1;
}
//打印
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *(ptr + i));
}
//释放空间
//free(calloc);
//假设空间不够,需要扩容20个元素
//原内存空间不够会重新寻找一块空间,将原有内存剪切到新的大空间上,并且把原空间释放
int *p = (int*)realloc(ptr, 80);//20个整形需要80个字节
if (*p != NULL)//防止内存不够,返回空指针
{
ptr = p;
}
//扩容成功
free(ptr);
ptr = NULL;
return 0;
}3.常见的动态内存使用错误
3.1对空指针的解引用操作
即没有判空,在malloc等函数申请空间是有可能会申请到空指针;
解决方法:判空
3.2对动态空间进行越界访问
解决方法:弄清楚动态内存的边界
for (i = 0; i <= 10; i++)//原申请空间<10,超过10会出现越界访问
{
printf("%d ", *(ptr + i));
}3.3 对非动态开辟空间使用free
必须在动态开辟空间的起始位置进行释放,否则可能会造成内存泄露(只申请,不归还)
3.4使用free释放动态内存的一部分
3.5对同一静态内存的多次释放
3.6忘记释放空间
4.经典笔试题练手
4.1练习一
void GetMemory(char* p) //这里的指针p在函数结束之后就销毁了,没有将地址返回到Test函数中
{
p = (char*)malloc(100);
}
void Test(void) {
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}4.2练习二
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();//虽然str获取到了字符串的地址,但是由于上函数的销毁,原空间也不存在了,无法在进行访问
printf(str);
}4.3练习三
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void) {
char* str = NULL;
GetMemory(&str, 100);//如果不取地址将无妨修改str
strcpy(str, "hello");
printf(str);
//忘记释放空间
//free(str);
//str = NULL;
}4.4练习四
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
//str = NULL;//可以通过设置空指针避免此类问题
if (str != NULL)
{
strcpy(str, "world");//free已经将空间还给操作系统了,这里的修改是非法修改
printf(str);
}
}5.结语

看到这里,相信老铁们对动态内存管理的知识已经有了基本的了解。
我是计算机海洋的新进船长Captain_ldx,如果我的文章能对您有帮助的话,麻烦各位观众姥爷们点赞、收藏、关注我吧!如果你对我的文章有任何问题或者意见,欢迎在评论区给我留言。后期更多知识点将持续更新......
边栏推荐
- 【论文阅读-表情捕捉】ExpNet: Landmark-Free, Deep, 3D Facial Expressions
- 五、请求处理—Rest映射是怎样实现的?
- LeetCode刷题之第33题
- 网络信息安全运营方法论 (中)
- 2021电赛资源及经验总结
- Comparison and summary of Tensorflow2 and Pytorch in terms of basic operations of tensor Tensor
- Thread handler句柄 IntentServvice handlerThread
- 物联网-广域网技术之NB-IoT
- ECCV2022 | RU&谷歌提出用CLIP进行zero-shot目标检测!
- MySQL主从复制—有手就能学会的MySQL集群搭建教程
猜你喜欢
![[Pytorch study notes] 10. How to quickly create your own Dataset dataset object (inherit the Dataset class and override the corresponding method)](/img/71/f82e76085f9d8e6610f6f817e2148f.png)
[Pytorch study notes] 10. How to quickly create your own Dataset dataset object (inherit the Dataset class and override the corresponding method)

【论文精读】ROC和PR曲线的关系(The relationship between Precision-Recall and ROC curves)

读论文 - Unpaired Portrait Drawing Generation via Asymmetric Cycle Mapping

CVPR2020 - 自校准卷积
![[Database and SQL study notes] 10. (T-SQL language) functions, stored procedures, triggers](/img/b9/06b90160c962a25a3cc44731afb6dc.png)
[Database and SQL study notes] 10. (T-SQL language) functions, stored procedures, triggers

教你如何封装功能组件和页面组件

【数据库和SQL学习笔记】8.SQL中的视图(view)

LeetCode刷题之第74题

深度学习系列(一)简介、线性回归与成本函数

物联网:LoRa无线通信技术
随机推荐
6k+ star,面向小白的深度学习代码库!一行代码实现所有Attention机制!
LeetCode刷题之第61题
LeetCode刷题之第701题
【Kaggle项目实战记录】一个图片分类项目的步骤和思路分享——以树叶分类为例(用Pytorch)
常见的 PoE 错误和解决方案
LeetCode刷题之第23题
[After a 12] No record for a whole week
【ts】typeScript高阶:any和unknown
BroadCast Receiver(广播)详解
常用 crud 的思考和设计
MaskDistill-不需要标注数据的语义分割
三、自动配置源码分析
[Database and SQL study notes] 10. (T-SQL language) functions, stored procedures, triggers
ECCV2022 | RU&谷歌提出用CLIP进行zero-shot目标检测!
八、请求处理之自定义类型参数绑定原理
网工必用神器:网络排查工具MTR
It turns out that the MAE proposed by He Yuming is still a kind of data enhancement
十一、拦截器运行原理
【Pytorch学习笔记】10.如何快速创建一个自己的Dataset数据集对象(继承Dataset类并重写对应方法)
Jupyter notebook选择不同的Anaconda环境作为内核运行