【C语言进阶】动态内存管理

👦个人主页:@Weraphael
✍🏻作者简介:目前是C语言学习者
✈️专栏:C语言航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注
目录
- 一、动态内存分配的由来
- 二、动态内存函数的介绍
- 2.1 malloc函数
- 2.2 free函数
- 2.3 calloc函数
- 2.4 realloc函数
- 三、常见的动态内存错误
- 3.1 对NULL指针的解引用操作
- 3.2 对动态开辟空间的越界访问
- 3.3 对非动态开辟内存使用free释放
- 3.4 使用free释放一块动态开辟内存的一部分
- 3.5 对同一块动态内存多次释放
- 3.6 动态开辟内存忘记释放
一、动态内存分配的由来
我们已经张伟的内存开辟方式有:
int a = 3;//在内存空间开辟4个字节
char a[10] = {0};//在内存开辟10个字节且连续的空间
但是上述的开辟空间的方式有两个特点:
- 空间开辟大小是固定的
- 数组再声明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
但是对于空间的需求,不仅仅是上述的情况。因为有时候我们需要的空间大小在程序运行的时候才知道,那么以上的方式就不能满足了。而动态内存分配恰好能在需要时随时开辟,不需要的时候随时释放,且分配的大小就是程序要求的大小。
二、动态内存函数的介绍
2.1 malloc函数

解读:
malloc函数会向内存申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好的空间的指针
- 如果开辟失败,则返回一个
NULL指针(空指针),因此malloc函数的返回值一定要做检查
*返回值是void*,表示的是无具体类型的指针,这说明malloc函数并不知道开辟空间的类型,具体是在使用的时候让使用者来决定- 如果参数
size为0,malloc的行为是标准未定义的,取决用编译器
【malloc函数实例】
strerror讲解传送门 -> 点击此处
#include <stdio.h>
#include <stdlib.h> //malloc函数所需头文件
#include <errno.h> //errno所需头文件
#include <string.h>//strerror所需头文件int main()
{//假设向内存申请40个字节,用来存放整型int* p = (int*)malloc(40);//判断返回值是否为空指针if (p == NULL){//说明开辟内存空间失败了,那就显示为什么失败了printf("%s\n", strerror(errno));return 1;}//否则返回值就不为空指针//假设存放数据1~10for (int i = 0; i < 10; i++){*(p + i) = 1 + i;}//打印for (int i = 0; i < 10; i++){printf("%d ", *(p + i));}return 0;
}

2.2 free函数
在
malloc函数实例中,代码会存在隐患。malloc函数既然在内存中申请了空间,用完了就应该还给操作系统。所以C语言提供了另外一个函数free,专门用做动态内存的释放和回收的。

解读:
free函数是用来释放内存块free函数无返回值- 参数
ptr是指向先前使用 malloc、calloc 或 realloc 分配的内存块的指针。- 如果参数
ptr指向的空间不是动态开辟的,那么free函数的行为就是未定义的- 如果参数
ptr是NULL指针,则函数不会做任何事。
【free函数实例(完善malloc函数实例)】
#include <stdio.h>
#include <stdlib.h> //malloc函数所需头文件
#include <errno.h> //errno所需头文件
#include <string.h>//strerror所需头文件int main()
{//假设向内存申请40个字节,用来存放整型int* p = (int*)malloc(40);//判断返回值是否为空指针if (p == NULL){//说明开辟内存空间失败了,那就显示为什么失败了printf("%s\n", strerror(errno));return 1;}//否则返回值就不为空指针//假设存放数据1~10for (int i = 0; i < 10; i++){*(p + i) = 1 + i;}//打印for (int i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放申请的内存free(p);p = NULL;return 0;
}
释放完空间后,
p = NULL的原因:
我们可以通过F10调试来观察
释放前:我们将数据1~10存放到内存了
释放后:我们发现,p在释放后还指向释放前的空间
所以,为了防止日后非法访问,我们就将p=NULL
2.3 calloc函数
C语言还提供一个函数
calloc,calloc函数也用来动态内存分配

解读:
- 参数
num是开辟元素的个数- 参数
size是每个元素的大小calloc与malloc区别在于calloc会在返回地址之前把申请的空间的每个字节初始化为0
【calloc函数实例】
calloc会将申请的空间全部初始化为0
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>int main()
{//向内存申请10个元素,每个元素都是int类型int* p = calloc(10, sizeof(int));//判断p是否为空指针if (p == NULL){printf("%s\n", strerror(errno));return 1;}//否则不是空指针for (int i = 0; i < 10; i++){printf("%d ", *(p + i));}//用完释放空间freefree(p);p = NULL;return 0;
}

2.4 realloc函数
realloc函数的出现让动态内存管理更加灵活- 有时候会发现过去申请的空间太小了,有时候又会觉得申请的空间过大,那为了合理的使用内存,就要对内存的大小做灵活的调整。使用
realloc函数就的功能就是调整动态开辟内存大小

解读:
- 参数
ptr是要调整的内存地址- 参数
size为调整之后的新大小- 返回值为调整之后的内存的起始地址
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动带新的空间
realloc函数在调整内存空间的时候存在两种情况:
- 当原有空间之后有足够大的空间,要扩展内存就直接在原有内存之后直接追加空间,原来空间的数据不发生变化,返回的是原来的地址
- 当原有空间之后没有足够大的空间,扩展的方法:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新内存的地址
【realloc函数实例】
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>int main()
{//假设向内存申请20个字节来存放5个整型int* p = (int*)malloc(20);//判断p是否为空指针if (p == NULL){printf("%s\n", strerror(errno));return 1;}//否则p就不是空指针//接下来就将5个整型全部赋值成1for (int i = 0; i < 5; i++){*(p + i) = 1;}//那么接下来假设我还要再开辟5个空间(realloc)int* ptr = (int*)realloc(p, 40);if (ptr != NULL)//说明扩容成功{p = ptr;}//打印10个整型for (int i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放空间(free)free(p);p = NULL;return 0;
}

三、常见的动态内存错误
3.1 对NULL指针的解引用操作
#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(40);*p = 20;free(p);p = NULL;return 0;
}
- 若
p = NULL,对于空指针解引用可能会导致程序异常终止或拒绝服务。
3.2 对动态开辟空间的越界访问
#include <stdio.h>
#include <stdlib.h>int main()
{//向内存申请10个整型的空间int* p = (int*)malloc(10 * sizeof(int));if (p == NULL){return 1;}for (int i = 0; i <= 10; i++){*(p + i) = i;}free(p);p = NULL;return 0;
}
- 当指针指向的范围超过数组的范围时,p就是野指针,而野指针是没有访问权限的地址,会造成非法访问
3.3 对非动态开辟内存使用free释放
#include <stdio.h>
#include <stdlib.h>int main()
{int a = 10;int* p = &a;free(p);p = NULL;return 0;
}
- 这个就是
free函数的概念,free的参数指向的空间一定是动态开辟的,比如:malloc、realloc和calloc。而这里的p指向的是一个变量的地址
3.4 使用free释放一块动态开辟内存的一部分
#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(40);p++;free(p);p = NULL;return 0;
}
- 要知道不管是
前置++还是后置++,它都是会有副作用的。p++后,p就会指向p++的位置,然后使用free释放只会释放p后面的内存空间,只释放了一部分
3.5 对同一块动态内存多次释放
#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(40);if (p == NULL){return 1;}free(p);free(p);return 0;
}
- 对一次
free回收了p申请的内存空间,此时的p就是野指针,而野指针是没有访问地址的权限,若再一次使用free来回收内存空间,可能会造成非法访问
3.6 动态开辟内存忘记释放
#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(40);if (p == NULL){return 1;}*p = 20;return 0;
}
- 使用完内存空间后,并没有释放(free)内存空间,会导致内存泄漏
相关文章:
【C语言进阶】动态内存管理
👦个人主页:Weraphael ✍🏻作者简介:目前是C语言学习者 ✈️专栏:C语言航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&a…...
第一批因ChatGPT坐牢的人,已经上路了
大家好,我是 Jack。 ChatGPT 的火爆有目共睹,有人靠着它赚了第一桶金,也有人靠着它即将吃上第一顿牢饭。 任何一件东西的火爆,总会给一些聪明人带来机会。 艾尔登法环火的时候,一堆淘宝卖魂的;羊了个羊火…...
Eclipse下Maven的集成
Eclipse下Maven的集成 2.1指定本地maven环境 参考:Eclipse的Maven创建_叶书文的博客-CSDN博客_eclipse创建maven项目 指定用本地maven指定maven仓库设置和地址2.2创建maven项目 1.新建 2.目录设置 3.坐标设置(随便写就行) 4.目录结构 2.3配置…...
Elasticsearch7学习笔记(尚硅谷)
文章目录一、ElasticSearch概述1、ElasticSearch是什么2、全文搜索引擎3、ElasticSearch 和 Solr3.1 概述3.2 比较总结二、Elasticsearch入门1、Elasticsearch安装1.1 下载使用1.2 数据格式2、索引操作3、文档操作(了解)3.1 创建文档3.2 文档查询3.3 文档…...
前端学习第一阶段-第7章 品优购电商项目
7-1 品优购项目介绍及准备工作 01-品优购项目导读 02-网站制作流程 03-品优购项目规划 04-品优购项目搭建 05-品优购项目-样式的模块化开发 06-品优购项目-favicon图标制作 07-品优购项目-TDK三大标签SEO优化 7-2 首页Header区域实现 08-品优购首页-快捷导航shortcut结构搭建 0…...
cocos2dx 4.0 - cpp - pc版 环境搭建
开发环境vs2022 cocos2dx4.0 python2.7.18 cmake3.25安装教程(环境搭建)安装VS2022-Community, 勾选c进行安装安装cmake3.25, 勾选环境变量进行安装安装python2.7.18, 勾选环境变量进行安装下载cocos2dx4.0并解压配置cocos2dx:运行cmd,进入…...
剑指 Offer 53 - I. 在排序数组中查找数字 I
原题链接 难度:easy\color{Green}{easy}easy 题目描述 统计一个数字在排序数组中出现的次数。 示例 1: 输入: nums [5,7,7,8,8,10], target 8 输出: 2示例 2: 输入: nums [5,7,7,8,8,10], target 6 输出: 0提示: 0<nums.length<1050 <…...
华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】
最近更新的博客 华为OD机试 - 热点网络统计 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试 - 查找单入口空闲区域 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试 - 好朋友 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试 - 找出同班小朋友 | 备考思路,刷题要点…...
PowerShell Install Office 2021 Pro Plus Viso Professional
前言 微软Office在很长一段时间内都是最常用和最受欢迎的软件。从小型创业公司到大公司,它的使用比例相当。它可以很容易地从微软的官方网站下载。但是,微软只提供安装程序,而不提供完整的软件供下载。这些安装文件通常比较小。下载并运行后,安装的文件将从后端服务器安装M…...
KubeSphere实战
文章目录一、KubeSphere平台安装1、Kubernetes上安装KubeSphere1.1 安装docker1.2 安装Kubernetes1.3 前置环境之nfs存储1.4 前置环境之metrics-server1.5 安装KubeSphere2、Linux单节点部署KubeSphere3、Linux多节点部署KubeSphere(推荐)二、KubeSphere实战1、多租户实战2、中…...
Linux 简介
Linux 内核最初只是由芬兰人林纳斯托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。 Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。 …...
java面试题-泛型异常反射
泛型1.什么是泛型?Java是一种强类型语言,数据类型在编译时必须确定。如果我们想要在代码中使用不同类型的数据,那么就需要为每种类型分别写出相应的代码。这样会导致代码冗长、重复,也不便于维护。为了解决这个问题,Ja…...
详细解读ChatGPT:如何调用ChatGPT的API接口到官方例子的说明以及GitHub上的源码应用和csdn集成的ChatGPT
文章目录1. 解读ChatGPT1.1 词语解释1.2 功能解读2. GitHub上ChatGPT的应用源码3. 调用ChatGPT的API4. 官方例子说明5. 集成ChatGPT自ChatGPT出来到如今,始终走在火热的道路上,如今日活用户破亿,他为何有如此大的魅力,深受广大用户…...
九龙证券|最新评级情况出炉,机构扎堆这一板块!聚氨酯龙头获得最多关注
本周算计254家上市公司获组织“买入型”评级。 电子板块评级组织扎堆 证券时报数据宝计算,2月13日至17日,A股市场53家组织算计进行347次评级,254家上市公司获“买入型”评级(包含买入、增持、强烈推荐、推荐)。 从申…...
考研复试机试 | C++ | 尽量不要用python,很多学校不支持
目录1.1打印日期 (清华大学上机题)题目:代码:1.2改一改:上一题反过来问题代码:2.Day of Week (上交&&清华机试题)题目:代码:3.剩下的树(清…...
ChatGPT时代,别再折腾孩子了
今天这篇完全是从两件事儿有感而发。昨天在文印店,在复印机上看到装订好的几页纸,我瞥了一眼,是历史知识点:隋朝大运河分为四段,分别是___ ___ ___ ___,连接了五大河___ ___ ___ ___ ______ 年ÿ…...
万字干货 | 荔枝魔方基于云原生的架构设计与实践
近年来,荔枝集团在国内和海外的业务迅速发展,业务数据规模也是成几何式地增长,海量数据的计算分析场景、业务智能算法应用需求随之而生,为了快速地满足业务发展的需要,我们面临着诸多的技术挑战。技术挑战工程问题资源…...
#科研筑基# python初学自用笔记 第九篇 面向对象编程
面向对象编程 Object Oriented Programming ,简称OOP,是一种程序设计思想,这种思想把对象作为程序的基本单元。类是抽象的,对象是具体的,一种类包括其特定的数据或属性,以及操作数据的函数(方法…...
Python快速上手系列--邮件发送--详解篇
本章就来一起学习一下跑完自动化脚本后如何自动的发送邮件到指定的邮箱。zmail操作:1. 导包 import zmail2. 邮件内容,包含:主题(subject)、正文(content_text)、附件(attachments)3. 发件人信息,包含:发件人账号&…...
【Bluetooth开发】蓝牙开发入门
BLE 蓝牙设备在生活中无处不在,但是我们也只是将其作为蓝牙模块进行使用,发送简单的AT命令实现数据收发。 那么,像对于一些复杂的使用场合:“车载蓝牙”、"智能手表"、“蓝牙音箱”等,我们不得不去了解底层…...
YOLO12入门必看:从上传图片到JSON结果输出完整操作流程
YOLO12入门必看:从上传图片到JSON结果输出完整操作流程 1. 引言:为什么你需要了解YOLO12? 如果你正在寻找一个既快又准的目标检测工具,那么YOLO12的出现,可能就是你一直在等的那个答案。 想象一下这样的场景&#x…...
TTL门电路在现代数字设计中的应用:从基础到OC门实战
TTL门电路在现代数字设计中的应用:从基础到OC门实战 在数字电路设计的工具箱里,TTL(晶体管-晶体管逻辑)门电路就像瑞士军刀一样经典而实用。尽管CMOS技术如今占据主流,但TTL在特定场景下依然展现出独特的优势。特别是在…...
dupeguru文件类型过滤终极指南:轻松管理重复文件的秘密武器
dupeguru文件类型过滤终极指南:轻松管理重复文件的秘密武器 【免费下载链接】dupeguru Find duplicate files 项目地址: https://gitcode.com/gh_mirrors/du/dupeguru 你是否曾经面对电脑中堆积如山的重复文件感到头疼?想要只清理图片却误删了重要…...
BilibiliDown:从技术视角重新定义B站视频下载体验
BilibiliDown:从技术视角重新定义B站视频下载体验 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bi…...
Swin2SR多帧超分:视频序列的时空信息融合
Swin2SR多帧超分:视频序列的时空信息融合 1. 引言 你有没有遇到过这样的情况:从监控录像中截取的关键画面模糊不清,或者老视频中的珍贵片段分辨率太低,无法看清细节?传统单帧超分技术往往力不从心,因为它…...
保姆级教程:在Windows上用VSCode和nRF5340 Audio DK板跑通第一个蓝牙例程
从零开始:WindowsVSCode环境下的nRF5340 Audio DK蓝牙开发实战 在嵌入式开发领域,Nordic Semiconductor的nRF5340 Audio DK开发板因其强大的双核架构和出色的蓝牙音频性能而备受瞩目。但对于刚接触这款开发板的工程师来说,从环境配置到成功运…...
WeChatExporter:微信聊天记录永久保存的5个实用技巧
WeChatExporter:微信聊天记录永久保存的5个实用技巧 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 问题:为什么你的微信数据需要专业备份方案&am…...
从OpenJDK到GraalVM:JDK21安装后,你还可以试试这些高性能Java运行时
从OpenJDK到GraalVM:JDK21安装后,你还可以试试这些高性能Java运行时 当你完成JDK21的基础安装后,Java生态的探索才刚刚开始。现代Java开发早已不再局限于传统JVM,越来越多的创新运行时正在重塑性能边界。本文将带你深入GraalVM、L…...
打造高效离线文字识别系统:Umi-OCR插件深度应用指南
打造高效离线文字识别系统:Umi-OCR插件深度应用指南 【免费下载链接】Umi-OCR_plugins Umi-OCR 插件库 项目地址: https://gitcode.com/gh_mirrors/um/Umi-OCR_plugins 在数字化办公与信息处理领域,离线OCR技术正成为保护数据隐私与提升处理效率的…...
AI绘画效率翻倍:WuliArt Qwen-Image Turbo极速生成实战测评
AI绘画效率翻倍:WuliArt Qwen-Image Turbo极速生成实战测评 1. 极速AI绘画新体验 作为一名长期使用各类AI绘画工具的技术爱好者,我一直在寻找一个能在个人电脑上流畅运行的高效文生图解决方案。直到最近体验了WuliArt Qwen-Image Turbo,这款…...


