【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命令实现数据收发。 那么,像对于一些复杂的使用场合:“车载蓝牙”、"智能手表"、“蓝牙音箱”等,我们不得不去了解底层…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...


