C语言之动态内存管理(malloc calloc realloc)

C语言之动态内存管理

文章目录

  • C语言之动态内存管理
    • 1. 为什么要有动态内存管理
    • 2. malloc 和 free
      • 2.1 malloc
      • 2.2 free
      • 2.3 例子
    • 3. calloc 和 realloc
      • 3.1 calloc
      • 3.2 realloc
    • 4. 常见的动态内存错误
      • 4.1 对NULL指针的解引⽤操作
      • 4.2 对动态开辟空间的越界访问
      • 4.3 对⾮动态开辟内存使⽤free释放
      • 4.4 使⽤free释放⼀块动态开辟内存的⼀部分
      • 4.5 对同⼀块动态内存多次释放
      • 4.6 动态开辟内存忘记释放(内存泄漏)
    • 5. 总结

1. 为什么要有动态内存管理

我们已经掌握的内存开辟⽅式有:

#include <stdio.h>int main()
{int val = 20;int arr[10] = { 0 };return 0;
}

上述的开辟空间的⽅式有两个特点
• 空间开辟大小是固定的

•数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整

所以C语⾔引⼊了动态内存开辟,让程序员⾃⼰可以申请和释放空间

2. malloc 和 free

mallocfree函数都是在stdlib.h头文件中声明的

2.1 malloc

C语言中提供了一个动态内存开辟的函数:

void* malloc (size_t size);

其中size为要开辟的内存空间的大小,单位为字节

这个函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针

•如果开辟成功,则返回一个指向开辟好的内存空间的指针
•如果开辟失败,则返回一个NULL指针
•返回类型为void *,因为malloc函数不知道要开辟什么类型的内存空间,只知道要开辟的大小
•如果参数为0,malloc函数的行为标准是未定义的,取决于编译器

2.2 free

C语言还提供了一个的函数,专门用来做动态内存的释放和回收的:

void free (void* ptr);

ptr为要释放内存空间的指针

•如果参数ptr指向的内存空间不是动态开辟的,那么free函数的行为是未定义的
•如果参数ptrNULL,则函数什么都不做

如果不对malloc calloc realloc 开辟的空间进行释放,即使出了作用域也不会销毁,有可能导致内存泄漏

释放的方式
1. free
2. 直到程序结束,由操作系统释放

2.3 例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)malloc(10 * sizeof(int)); //开辟40个字节的空间//判断是否为NULL指针if (p == NULL){perror("malloc fail\n"); //perror为错误信息打印return 1;}//使用int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;//*p = i;   //如果使用这种方法,p指针向后走了,在下面打印时,就找不到首元素的地址了//p++;}//打印for (i = 0; i < 10; i++){printf("%d ", *(p + i));}free(p);  //释放p = NULL; //将指针置NULL,如果不置NULL,下面解引用p时,p就是野指针return 0;
}

代码运行结果:>
0 1 2 3 4 5 6 7 8 9

malloc开辟空间时,是不会给空间初始化的,如果直接打印,会打印出随机值

3. calloc 和 realloc

3.1 calloc

C语⾔还提供了⼀个函数叫 calloccalloc 函数也⽤来动态内存分配

void* calloc (size_t num, size_t size);

num为要开辟的元素个数
size为开辟元素的元素大小,单位为字节

calloc为开辟num个大小为size元素的内存空间,并且将内存中每个字节初始化为0
calloc的使用方法和malloc一样,主要区别在于calloc会初始化元素

例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)calloc(10 ,sizeof(int));//判断是否为NULL指针if (p == NULL){perror("calloc fail\n");return 1;}int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}return 0;
}

代码运行结果:>
0 0 0 0 0 0 0 0 0 0

3.2 realloc

C语言中有一个函数用来调整动态内存开辟后的大小

void* realloc (void* ptr, size_t size);

ptr为要调整的内存地址
size为调整后的内存大小

realloc函数的出现让动态内存管理更加灵活
• 当我们发现我们使用malloc calloc realloc申请的内存空间不够时,我们可以使用realloc进行扩容

•返回值为调整之后的内存的起始位置(不一定是原内存地址)
•如果开辟失败则返回一个NULL
•如果开辟成功则分以下两个情况:

情况1:原有空间之后有⾜够⼤的空间
情况2:原有空间之后没有⾜够⼤的空间

在这里插入图片描述

情况1:在原有内存后边直接追加空间,原来的空间的数据不变
情况2:原有内存之后的空间不足以最加空间,那么realloc会在堆区中找到一块足够开辟新大小的空间,将旧空间中的数据拷贝到新空间,并且将旧空间释放,同时返回新空间起始位置的地址

realloc的用法除了为开辟的内存进行扩容,也可以和malloc一样

例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)malloc(10 * sizeof(int));//判断是否为NULL指针if (p == NULL){perror("malloc fail\n");return 1;}int* tmp = (int*)realloc(p, 100*sizeof(int));if (tmp != NULL){p = tmp;}else{perror("relloc fail\n");return 1;}//使用//..........free(p);p = NULL;return 0;
}

在这里插入图片描述
这次的运行结果就是情况2(开辟100个字节的大小时,可能会出现),当后面的空间不够时, realloc就会找一块新的空间
在这里插入图片描述
这次只开辟了40个字节的空间,属于情况1,后面的空间足够时, realloc会直接在后面追加空间

4. 常见的动态内存错误

4.1 对NULL指针的解引⽤操作

#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(40);*p = 20; //如果malloc开辟空间失败,p可能是NULL,此时p为野指针return 0;
}

在VS2022中,编译器会进行提示,我们得对可能出现NULL的情况进行处理
在这里插入图片描述

在使用malloc calloc realloc开辟空间时,最好对返回值进行判断,当不为NULL再使用

4.2 对动态开辟空间的越界访问

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}int i = 0;for (i = 0; i <= 10; i++)  //只有10个元素的空间,却访问了第11个元素,访问越界了{*(p + i) = i;}free(p);p = NULL;return 0;
}

在这里插入图片描述

4.3 对⾮动态开辟内存使⽤free释放

#include <stdio.h>
#include <stdlib.h>int main()
{int a = 10;int* p = &a;free(p);return 0;
}

在这里插入图片描述

当用free释放了不是由malloc calloc realloc开辟的空间时,就会报错

4.4 使⽤free释放⼀块动态开辟内存的⼀部分

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int a = 10;int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}//使用//......p++;free(p);p = NULL;return 0;
}

在这里插入图片描述
当用free释放了开辟空间的一部分时,就会报错

4.5 对同⼀块动态内存多次释放

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int a = 10;int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}//使用//......free(p);free(p);p = NULL;return 0;
}

在这里插入图片描述
对一块动态开辟的内存进行多次free释放

在上述代码中如果free释放NULL,则没有问题,因为free的参数为NULL时,则什么都不做

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int a = 10;int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}//使用//......free(p);p = NULL;free(p);p = NULL;return 0;
}

4.6 动态开辟内存忘记释放(内存泄漏)

#include <stdio.h>
#include <stdlib.h>void test()
{int* p = (int*)malloc(100);if (p != NULL){*p = 20;}
}
int main()
{test();while (1); //死循环,让程序不结束return 0;
}

当动态开辟的内存不释放时,就会一存在,在上述代码中,调用了test函数,开辟了100个字节的空间,同时赋值,出函数时,p被销毁了,但是开辟的空间并没有被销毁,没人可以使用,也没人可以释放,就会导致内存泄漏

5. 总结

一丶
在使用malloc calloc realloc开辟的空间时,要对其进行判断,当不为NULL的再进行使用
二丶
当不使用动态开辟的内存时,将其free释放,同时将指针置NULL,防止可能出现的内存泄露和野指针
三丶
不对不是动态开辟的空间free,不连续对动态开辟的空间free,同时free动态开辟的空间时,要给开辟的起始地址,不能free部分空间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/206889.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

女装品牌网站建设的作用如何

服装是任何人都需要的必备品&#xff0c;尤其是女装&#xff0c;由于女性群体爱美追求时尚的心理更高&#xff0c;因此市场中有大量女装品牌以及大量消费者&#xff0c;其规模非常高&#xff0c;众多大小品牌林立及消费征集下&#xff0c;商家们经营也并不太容易&#xff0c;企…

Themis: Fast, Strong Order-Fairness in Byzantine Consensus

目录 笔记后续的研究方向摘要引言秩序井然 Themis: Fast, Strong Order-Fairness in Byzantine Consensus CCS 2023 笔记 后续的研究方向 摘要 我们介绍了Themis&#xff0c;这是一种将交易的公平排序引入&#xff08;许可的&#xff09;拜占庭共识协议的方案&#xff0c;最…

参加百度Apollo技术沙龙—感受自动驾驶的魅力

2023年12月2日下午2点&#xff0c;我有幸参加了百度Apollo技术沙龙&#xff0c;这是一个围绕Apollo新版本Beta的全面升级展开的深度交流活动。作为一名工程师&#xff0c;我深感荣幸能够与众多同行和专家一同探讨自动驾驶技术的快速发展 在这次沙龙中&#xff0c;我了解到Apo…

vue的data

类型&#xff1a;Object | Function 限制&#xff1a;组件的定义只接受 function。 详细&#xff1a; Vue 实例的数据对象。Vue 会递归地把 data 的 property 转换为 getter/setter&#xff0c;从而让 data 的 property 能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个…

DC电源模块与节能环保的关系

BOSHIDA DC电源模块与节能环保的关系 随着全球能源危机的加剧&#xff0c;环保节能已经成为世界各国政府和企业发展的主要方向。在电子行业中&#xff0c; DC电源模块的出现为环保节能做出了贡献。DC电源模块是一种电源供应器件&#xff0c;可将高电压转换为低电压&#xff0c;…

柏林噪声C++

柏林噪声 随机噪声 如上图所示随机噪声没有任何规律可言&#xff0c;我们希望生成有一些意义的局部连续的随机图案 一维柏林噪声 假设希望生成一段局部连续的随机曲线&#xff0c;可以采用插值的方式&#xff1a;在固定点随机分配y值&#xff08;一般是整数点&#xff09;&a…

【数据分析实战】酒店行业华住集团门店分布与评分多维度分析

文章目录 1. 写在前面2. 数据集展示3. 多维度分析3.1 门店档次多元化&#xff1a;集团投资战略观察3.1.1 代码实现3.1.2 本人浅薄理解 3.2 门店分布&#xff1a;各省市分布概览3.2.1 代码实现3.2.2 本人浅薄理解 3.3 门店分级评分&#xff1a;服务水平的多维度观察3.3.1 代码实…

F5怎么样?从负载均衡到云原生的进阶之路

从Web时代开始至云原生时代的应用服务交付的市场&#xff0c;技术与人的变化就是关注的焦点。从单纯的Web负载均衡到复杂的企业应用交付&#xff0c;从单体应用到分布式、微服务架构&#xff0c;F5为企业技术架构更好、更优、更安全的运行做出了极大的努力。那么F5怎么样&#…

题目:分糖果(蓝桥OJ 2928)

题目描述&#xff1a; 解题思路&#xff1a; 本题采用贪心思想 图解 题解&#xff1a; #include<bits/stdc.h> using namespace std;const int N 1e6 9; char s[N];//写字符串数组的一种方法,像数组一样***int main() {int n, x;cin >> n >> x;for(int …

CSS新手入门笔记整理:元素类型相互转换

元素类型 块元素&#xff08;block&#xff09; 独占一行&#xff0c;排斥其他元素跟其位于同一行&#xff0c;包括块元素和行内元素。块元素内部可以容纳其他块元素和行内元素。可以定义 width&#xff0c;也可以定义 height。可以定义 4 个方向的 margin。 行内元素&#xf…

使用navicat(或者其他数据库管理工具)、powerdesigner导出数据字典

适合先有数据库结构&#xff0c;后需要导出数据字典的情况&#xff0c;多数在发开完成交文档或者用户有库的情况下 有条件的话推荐用powerdesigner导出&#xff0c;比较好看 如果用powerdesigner导出的注释不对&#xff0c;是因为数据库的编码不对 1、使用navicat导出 在该数…

代码随想录算法训练营第45天| 70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数

JAVA代码编写 70. 爬楼梯&#xff08;进阶版) 卡码网&#xff1a;57. 爬楼梯&#xff08;第八期模拟笔试&#xff09; 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬至多m (1 < m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f…

菜鸟学习日记(python)——推导式

python中的推导式是一种独特的数据处理方式&#xff0c;可以从一个数据序列去构建另一个新的数据序列的结构体。 它包括以下推导式&#xff1a; 列表&#xff08;list&#xff09;推导式字典&#xff08;dict&#xff09;推导式集合&#xff08;set&#xff09;推导式元组&am…

Multi-Cell Downlink Beamforming: Direct FP, Closed-Form FP, Weighted MMSE

这里写自定义目录标题 Direct FPClosed-Form FPthe Lagrangian functionthe Lagrange dual function: maximizing the Lagrangianthe Lagrange dual problem: minimizing the Lagrange dual functionClosed-Form FP Weighted MMSE原论文 Lagrange dual5.1.1 The Lagrangian5.1.…

阿里云服务器经济型、通用算力型、计算型、通用型、内存型实例区别及选择参考

当我们通过阿里云的活动购买云服务器会发现&#xff0c;相同配置的云服务器往往有多个不同的实例可选&#xff0c;而且价格差别也比较大&#xff0c;例如同样是4核8G的配置的云服务器&#xff0c;经济型e实例活动价格只要1500.48/1年起&#xff0c;通用算力型u1实例要1795.97/1…

nvidia安装出现7-zip crc error解决办法

解决办法&#xff1a;下载network版本&#xff0c;重新安装。&#xff08;选择自己需要的版本&#xff09; 网址&#xff1a;CUDA Toolkit 12.3 Update 1 Downloads | NVIDIA Developer 分析原因&#xff1a;local版本的安装包可能在下载过程中出现损坏。 本人尝试过全网说的…

无公网IP环境如何SSH远程连接Deepin操作系统

文章目录 前言1. 开启SSH服务2. Deppin安装Cpolar3. 配置ssh公网地址4. 公网远程SSH连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 前言 Deepin操作系统是一个基于Debian的Linux操作系统&#xff0c;专注于使用者对日常办公、学习、生活和娱乐的操作体验的极致&#xff0…

Python---time库

目录 时间获取 时间格式化 程序计时 time库包含三类函数&#xff1a; 时间获取&#xff1a;time() ctime() gmtime() 时间格式化&#xff1a;strtime() strptime() 程序计时&#xff1a;sleep() perf_counter() 下面逐一介绍&#…

H3.3K27M弥漫性中线胶质瘤的反义寡核苷酸治疗

今天给同学们分享一篇实验文章“Antisense oligonucleotide therapy for H3.3K27M diffuse midline glioma”&#xff0c;这篇文章发表在Sci Transl Med期刊上&#xff0c;影响因子为17.1。 结果解读&#xff1a; CRISPR-Cas9消耗H3.3K27M恢复了H3K27三甲基化&#xff0c;并延…

在AWS Lambda上部署标准FFmpeg工具——Docker方案

大纲 1 确定Lambda运行时环境1.1 Lambda系统、镜像、内核版本1.2 运行时1.2.1 Python1.2.2 Java 2 启动EC23 编写调用FFmpeg的代码4 生成docker镜像4.1 安装和启动Docker服务4.2 编写Dockerfile脚本4.3 生成镜像 5 推送镜像5.1 创建存储库5.2 给EC2赋予角色5.2.1 创建策略5.2.2…