【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命令实现数据收发。 那么,像对于一些复杂的使用场合:“车载蓝牙”、"智能手表"、“蓝牙音箱”等,我们不得不去了解底层…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...