C语言内存之旅:从静态到动态的跨越
大家好,这里是小编的博客频道
小编的博客:就爱学编程
很高兴在
CSDN
这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!
本文目录
- 引言
- 正文
- 一 动态内存管理的必要性
- 二 动态内存管理的关键函数
- 1.`malloc`函数
- 2.`calloc`函数
- 3.`realloc`函数
- 4.`free`函数
- 三 动态内存管理中的错误和最佳实践
- 1.内存泄漏
- 2.野指针
- 3.内存越界
- 四 动态内存管理的高级主题
- 内存分配器
- 内存池
- 垃圾收集
- 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!
引言
动态内存管理是程序设计中用于在程序运行时分配和释放内存的机制。这种管理方式允许程序根据实际需要动态地调整内存使用,从而更有效地利用系统资源。所以就让小编来对动态内存管理做一个详细的介绍。
那接下来就让我们开始遨游在知识的海洋!
正文
首先让我们来了解一下动态内存管理的必要性。
一 动态内存管理的必要性
在静态内存分配中,内存的分配和释放由编译器自动管理,通常发生在栈(stack)上。例如,局部变量的分配和释放就是静态的,它们的生命周期仅限于函数调用的开始和结束。
动态内存管理的必要性主要体现在以下几个方面:
-
可变大小的数据结构:对于一些数据结构,如动态数组、链表、树、图等,其大小在编译时无法确定,需要在运行时根据实际需要进行分配。
-
优化内存使用:动态内存管理可以根据程序的实际需求分配内存,避免浪费,提高内存使用效率。
-
跨函数或代码块的数据生命周期:有些数据需要在多个函数或代码块中使用,其生命周期超出了局部作用域,动态内存管理可以满足这种需求。
知道了动态内存管理的必要性,我们就迎来了动态内存管理最重要的核心内容:二 动态内存管理的关键函数。
二 动态内存管理的关键函数
在C和C++语言中,动态内存管理主要通过以下几个标准库函数实现。
1.malloc
函数
malloc
是 C 语言中用于动态内存分配的函数,它允许程序在运行时申请一块指定大小的内存空间。这个函数的特点是它不初始化内存内容,即保留之前使用过的数据。
函数原型:
void* malloc(size_t size);
-
size
参数是要申请的内存大小,单位是字节。 -
返回值是
void*
类型,指向分配的内存块的起始地址。如果分配失败,返回NULL
。
示例代码:
#include <stdio.h>
#include <stdlib.h>int main() {int* dynamicArray = (int*)malloc(5 * sizeof(int)); // 分配5个int大小的内存if (dynamicArray == NULL) {printf("Memory allocation failed.\n");return 1;}// 使用分配的内存for (int i = 0; i < 5; ++i) {dynamicArray[i] = i;}// 打印数组内容for (int i = 0; i < 5; ++i) {printf("%d ", dynamicArray[i]);}printf("\n");// 使用完毕后释放内存free(dynamicArray);return 0;
}
在上述示例中,我们分配了足够存放5个整数的内存空间,并检查了malloc
返回的指针是否为NULL
,以确保内存分配成功。
2.calloc
函数
calloc
函数与malloc
类似,但它会将分配的内存初始化为零。这对于需要清零的数组或结构体非常有用。
函数原型:
void* calloc(size_t num, size_t size);
-
num
参数是元素的数量。 -
size
参数是每个元素的大小,单位是字节。 -
返回值是
void*
类型,指向分配并初始化为零的内存块的起始地址。如果分配失败,返回NULL
。
示例代码:
#include <stdio.h>
#include <stdlib.h>int main() {int* dynamicArray = (int*)calloc(5, sizeof(int)); // 分配5个int大小的内存,并初始化为0if (dynamicArray == NULL) {printf("Memory allocation failed.\n");return 1;}// 使用分配的内存for (int i = 0; i < 5; ++i) {printf("%d ", dynamicArray[i]); // 将打印5个0}printf("\n");// 使用完毕后释放内存free(dynamicArray);return 0;
}
在上述示例中,我们分配了足够存放5个整数的内存空间,并且这些整数都被初始化为0。
3.realloc
函数
realloc
函数用于调整之前通过malloc
或calloc
分配的内存块的大小。如果调整后的内存块变大,新增加的部分内容是未定义的;如果变小,超出新大小的数据可能会被截断。
函数原型:
void* realloc(void* ptr, size_t new_size);
-
ptr
参数是之前分配的内存块的指针。 -
new_size
参数是新的内存大小,单位是字节。 -
返回值是
void*
类型,指向调整后的内存块的起始地址。如果调整失败,返回NULL
。
示例代码:
#include <stdio.h>
#include <stdlib.h>int main() {int* dynamicArray = (int*)malloc(3 * sizeof(int)); // 初始分配3个int的空间if (dynamicArray == NULL) {printf("Memory allocation failed.\n");return 1;}// 假设我们需要更多的空间dynamicArray = (int*)realloc(dynamicArray, 6 * sizeof(int)); // 调整为6个int的空间if (dynamicArray == NULL) {printf("Memory reallocation failed.\n");return 1;}// 使用调整后的内存for (int i = 0; i < 6; ++i) {dynamicArray[i] = i;}// 打印数组内容for (int i = 0; i < 6; ++i) {printf("%d ", dynamicArray[i]);}printf("\n");// 使用完毕后释放内存free(dynamicArray);return 0;
}
在上述示例中,我们首先分配了足够存放3个整数的内存空间,然后使用realloc
将其扩展到足够存放6个整数的空间。
4.free
函数
free
函数用于释放之前通过malloc
、calloc
或realloc
分配的内存。释放内存后,指针不再有效,不应再被使用。
函数原型:
void free(void* ptr);
• ptr
参数是之前分配的内存块的指针。
示例代码:
#include <stdio.h>
#include <stdlib.h>int main() {int* dynamicArray = (int*)malloc(5 * sizeof(int)); // 分配5个int大小的内存if (dynamicArray == NULL) {printf("Memory allocation failed.\n");return 1;}// 使用分配的内存for (int i = 0; i < 5; ++i) {dynamicArray[i] = i;}// 打印数组内容for (int i = 0; i < 5; ++i) {printf("%d ", dynamicArray[i]);}printf("\n");// 释放内存free(dynamicArray);dynamicArray = NULL; // 避免野指针return 0;
}
在上述示例中,我们分配了内存,并在使用完毕后通过free
释放了它。释放后,我们将指针设置为NULL
,以避免产生野指针。
这些函数是动态内存管理的基础,它们使得程序能够灵活地处理内存,适应不同的运行时需求。正确使用这些函数对于避免内存泄漏和其他内存相关的问题至关重要。希望这些介绍能够满足宝子们对动态内存管理详细了解的需求。
三 动态内存管理中的错误和最佳实践
1.内存泄漏
内存泄漏发生在程序分配了内存但未能释放它,导致程序在运行过程中占用越来越多的内存。为了避免内存泄漏,可以遵循以下最佳实践:
-
确保每次
malloc
都配对相应的free
:每次使用malloc
分配内存后,必须在不再需要该内存时调用free
。 -
使用智能指针(C++):智能指针如
std::unique_ptr
和std::shared_ptr
可以自动管理内存,减少内存泄漏的风险。 -
自定义内存管理策略:在性能要求高或特定环境下,开发者可能需要实现自定义的内存管理策略,如内存池。
2.野指针
野指针是指指向已经被释放内存的指针。使用野指针可能导致程序崩溃或数据损坏。为了避免野指针,可以采取以下措施:
-
释放内存后将指针设置为
NULL
:这是一个好习惯,可以避免意外地使用已经释放的内存。 -
使用工具检测内存错误:使用如 Valgrind 这样的工具可以帮助检测内存泄漏和野指针等错误。
3.内存越界
内存越界是指访问分配的内存之外的区域,这可能导致程序崩溃或数据损坏。为了避免内存越界,可以采取以下措施:
-
仔细检查数组索引和内存块边界:在访问数组或内存块时,始终检查索引或指针是否超出范围。
-
使用安全编码实践:如初始化指针为
NULL
,使用边界检查等。
四 动态内存管理的高级主题
内存分配器
一些高级应用可能需要自定义内存分配器,以优化特定类型的内存分配模式。自定义内存分配器可以减少内存碎片,提高内存分配和释放的效率。
内存池
在性能敏感的应用中,使用内存池可以减少内存分配和释放的开销。内存池预先分配一大块内存,并在需要时从池中分配小块内存,释放时返回到池中,而不是直接释放到操作系统。
垃圾收集
在一些高级语言中(如Java和C#),垃圾收集器自动管理内存,减少了程序员的负担。垃圾收集器通过跟踪对象的引用来确定哪些内存可以被释放。
结论
- 动态内存管理是程序设计中的一个重要组成部分,它为程序提供了灵活性和效率,允许程序在运行时根据需要分配和释放内存。然而,这也带来了内存泄漏等风险,因此需要开发者谨慎管理内存,遵循最佳实践,以确保程序的稳定性和性能。
以上是对动态内存管理的详细介绍,包括其基本概念、必要性、技术细节、应用场景以及相关的错误和最佳实践。希望这个介绍能够满足宝子们对动态内存管理详细了解的需求。如果宝子们有其他问题或需要进一步的解释,请随时告诉小编。
快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!
相关文章:

C语言内存之旅:从静态到动态的跨越
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一 动态内存管理的必要性二 动态…...
研1如何准备才能找到大厂实习?
研1如何准备才能找到大厂实习? 写在前面 2024已经走向尾声,迎来了我的2025,这一年我有许多难忘的回忆和经验想要分享给大家,希望对您能有所帮助和启发,希望准备找工作的同学可以少走一些弯路。 我深知目前就业压力大…...

游戏为什么失败?回顾某平庸游戏
1、上周玩了一个老鼠为主角的游戏,某平台喜1送的, 下载了很久而一直没空玩,大约1G,为了清硬盘空间而玩。 也是为了拔掉心中的一根刺,下载了而老是不玩总感觉不舒服。 2、老鼠造型比较写实,看上去就有些讨…...

QT 使用QTableView读取数据库数据,表格分页,跳转,导出,过滤功能
文章目录 效果图概述功能点代码分析导航栏表格更新视图表格导出表格过滤 总结 效果图 概述 本案例用于对数据库中的数据进行显示等其他操作。数据库的映射,插入等功能看此博客框架:数据模型使用QSqlTableModel,视图使用QTableView࿰…...

【前端】CSS学习笔记(1)
目录 CSS的简介CSS的概念语法 CSS的引入方式内联样式(行内样式)内部样式外部样式(推荐) 选择器全局选择器元素选择器类选择器ID选择器合并选择器后代选择器子选择器相邻兄弟选择器通用兄弟选择器伪类选择器:link:visited:hover:ac…...

Ubuntu离线docker compose安装DataEase 2.10.4版本笔记
1、先准备一个可以正常上网的相同版本的Ubuntu系统,可以使用虚拟机。Ubuntu系统需要安装好docker compose或docker-compose 2、下载dataease-online-installer-v2.10.4-ce.tar在线安装包,解压并执行install.sh进行安装和启动 3、导出docker镜像 sudo d…...

C 语言雏启:擘画代码乾坤,谛观编程奥宇之初瞰
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。* 这一课主要是让大家初步了解C语言,了解我们的开发环境,main函数,库…...
npm操作大全:从入门到精通
引言 在现代前端开发中,npm(Node Package Manager)是不可或缺的工具。无论是安装依赖、管理项目,还是发布自己的包,npm都扮演着重要的角色。本文将带你从npm的基础操作开始,逐步深入到高级用法,…...

AI绘画入门:探索数字艺术新世界(1/10)
引言:AI 绘画的兴起与现状 在科技飞速发展的当下,AI 绘画如同一场艺术领域的风暴,正以惊人的速度席卷而来,彻底改变着我们对艺术创作的认知。近年来,AI 绘画相关的话题屡屡登上热搜,从社交媒体上各种 AI 生…...

Linux应用编程(五)USB应用开发-libusb库
一、基础知识 1. USB接口是什么? USB接口(Universal Serial Bus)是一种通用串行总线,广泛使用的接口标准,主要用于连接计算机与外围设备(如键盘、鼠标、打印机、存储设备等)之间的数据传输和电…...

项目-03-封装echarts组件并使用component动态加载组件
目录 需求场景代码补充说明1. typeComponentMap 讲解2. 为什么要给Echarts实例DOM添加id3. 为什么要在 onMounted 里添加 nextTick4. 为什么要监听props.option 需求 由于需要多次用到echarts,需要封装一个echarts组件动态加载echarts组件 场景代码 场景…...
使用 Blazor 和 Elsa Workflows 作为引擎的工作流系统开发
开发一个完整的工作流系统使用 Blazor 和 Elsa Workflows 作为引擎,可以实现一个功能强大的工作流管理和设计系统。下面将提供详细的步骤和代码实现,展示如何在 Blazor 中开发一个基于 Elsa Workflows 的工作流系统。 项目概述 我们的工作流系统将包含以…...

Node.js 完全教程:从入门到精通
Node.js 完全教程:从入门到精通 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,允许开发者在服务器端使用 JavaScript。它的非阻塞 I/O 和事件驱动架构使得 Node.js 非常适合于构建高性能的网络应用。本文将详细介绍 Node.js 的安装、基本语…...
elasticsearch 数据导出/导入
例子: 导出命令: elasticdump --inputhttps://elastic:elasticsearchlocalhost:9100/company --outputcompany.json --typedata --no-verify 注意,本地docker搭建,禁用自签证书验证,先设置环境变量 export NODE_TL…...

什么是三高架构?
大家好,我是锋哥。今天分享关于【什么是三高架构?】面试题。希望对大家有帮助; 什么是三高架构? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 “三高架构”通常是指高可用性(High Availability)、高性能ÿ…...

Docker 单机快速部署大数据各组件
文章目录 一、Spark1.1 NetWork 网络1.2 安装 Java81.3 安装 Python 环境1.4 Spark 安装部署 二、Kafka三、StarRocks四、Redis五、Rabbitmq六、Emqx6.1 前言6.2 安装部署 七、Flink八、Nacos九、Nginx 一、Spark 1.1 NetWork 网络 docker network lsdocker network create -…...

CSS笔记基础篇01——选择器、文字控制属性、背景属性、显示模式、盒子模型
黑马程序员视频地址: 前端Web开发HTML5CSS3移动web视频教程https://www.bilibili.com/video/BV1kM4y127Li?vd_source0a2d366696f87e241adc64419bf12cab&spm_id_from333.788.videopod.episodeshttps://www.bilibili.com/video/BV1kM4y127Li?vd_source0a2d3666…...
pytest全局配置文件pytest.ini
pytest.ini 改变 pytest 的默认行为,一般放在项目的根目录,不能包含中文符号。不管是主函数模式运行,命令行模式运行,都会去读取这个全局配置文件。 [pytest] ;配置命令行参数,用空格进行分隔。addopts 中的选项会被命…...

PyTest自学-认识PyTest
1 PyTest自学-认识PyTest 1.1 PyTest可以用来做什么? PyTest是一个自动化测试框架,支持单元测试和功能测试,有丰富的插件,如,pytest-selemium, pytest-html等。 1.2 安装pytest 使用pip install -U pytest。 1.3 py…...

【专题】为2025制定可付诸实践的IT战略规划报告汇总PDF洞察(附原数据表)
原文链接:https://tecdat.cn/?p39055 在当今瞬息万变的商业环境中,制定有效的 IT 战略规划对于企业的成功与可持续发展至关重要。本报告深入探讨了制定 IT 战略规划的关键活动,旨在为企业和决策者提供全面且实用的指导。 Gartner的《为202…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...