【C语言进阶】C语言动态内存管理:深入理解malloc、calloc与realloc

news2024/9/20 7:51:27

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C语言 “ 登神长阶 ”
🤡往期回顾🤡:C语言自定义类型
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀C语言动态内存管理

  • 📒1. 动态内存分配
  • 📚2. 动态内存函数的介绍
    • 🌞malloc和free
    • 🌙calloc
    • ⭐realloc
  • 📜3. C/C++程序的内存开辟
  • 📖4. 总结


前言:在C语言的世界里,动态内存管理是一项既强大又复杂的特性,它赋予了程序员在程序运行时动态地分配和释放内存资源的能力。这一特性是C语言灵活性和高效性的重要基石,同时也是初学者踏入C语言高级编程领域时必须跨越的一道门槛

动态内存管理之所以重要,是因为它允许程序根据实际需要调整内存使用,从而能够处理大小在编译时无法确定的数据结构,如可变长度的字符串、链表、树等。然而,这种灵活性也伴随着风险:不当的内存分配和释放可能导致内存泄漏、野指针等严重问题,进而影响程序的稳定性和安全性

因此,掌握C语言的动态内存管理技术,对于每一个希望深入理解C语言并编写出健壮、高效程序的开发者来说,都是必不可少的。本文将带领读者从基础概念出发,逐步深入探索C语言中的内存分配函数(如malloc、calloc、realloc)和内存释放函数(如free)的使用方法,以及如何通过合理的内存管理策略来避免常见的内存问题

让我们一起踏上这段探索C语言动态内存管理奥秘的征程吧!


📒1. 动态内存分配

C语言中的动态内存分配是编程中一个非常重要的概念,它允许程序在运行时根据需要分配和释放内存空间,而不是在编译时就固定下来。这种灵活性对于处理大小未知或变化的数据结构(如链表、树、图等)尤为重要

// 我们学过的内存开辟的方式
int val = 20;//在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间

这两种方式:

  • 空间开辟大小是固定的
  • 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配

有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了,这时候就只能试试动态存开辟了


📚2. 动态内存函数的介绍

动态内存函数是C语言中管理堆区内存的重要工具。通过malloc、calloc和realloc函数,程序可以在运行时根据需要动态地分配内存。使用完毕后,应通过free函数释放内存,以避免内存泄漏

// 头文件
#include<stdlib.h>

🌞malloc和free

malloc介绍

malloc可以向堆区申请一块连续的内存空间,空间大小为size字节

void* malloc (size_t size);

malloc文档

在这里插入图片描述

注意事项:

  • 如果开辟成功,则返回一个指向开辟好空间的指针
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定
  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器
  • 使用完毕后,应通过free函数释放内存,避免内存泄漏

free介绍

C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的

void free (void* ptr);

free文档

在这里插入图片描述

注意事项:

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的
  • 如果参数 ptr 是NULL指针,则函数什么事都不做
  • free函数只释放内存,不修改ptr的值。因此,为了避免野指针问题,通常会在free后将ptr置为NULL

代码示例 (C语言):

#include<stdio.h>
#include<stdlib.h>

int main()
{
	// 申请一块内存
	int* ptr = (int*)malloc(sizeof(int) * 10);
	if (ptr != NULL) //判断ptr指针是否为空
	{
		for(int i = 0; i < 10; i++)
		{
			(ptr[i]) = i;
		}
	}

	free(ptr); //释放ptr所指向的动态内存
	ptr = NULL;

	return 0;
}

注意事项:

  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
  • 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
  • 由于 calloc 需要对每个字节进行初始化,因此它比 malloc 慢一些,特别是在分配大量内存时。然而,如果你需要分配后立即清零的内存,calloc 可能是一个更好的选择

🌙calloc

calloc 函数是 C 语言标准库中的一个函数,用于动态内存分配。与 malloc 函数类似,calloc 也用于在堆(heap)上分配内存空间,但它以不同的方式处理内存初始化

void* calloc (size_t num, size_t size);

calloc文档

在这里插入图片描述
代码示例 (C语言):

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int* ptr = (int*)calloc(10,sizeof(int));
	if (ptr != NULL)
	{
		// 使用开辟的空间
		// ...
	}

	free(ptr);
	ptr = NULL;

	return 0;
}

在这里插入图片描述

如果我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务


⭐realloc

realloc 函数是 C 语言标准库中的一个非常有用的函数,用于动态地调整之前通过 malloc、calloc 或 realloc 函数分配的内存块的大小。

  • 如果调整成功realloc 会返回指向新内存块的指针,这个新内存块包含了原始数据(在可能的情况下),并且大小已经调整为新的大小
  • 如果调整失败realloc 会返回 NULL 指针,并且原始的内存块不会被释放,因此调用者有责任在失败时释放原始内存以避免内存泄漏
void* realloc (void* ptr, size_t size);

realloc文档

在这里插入图片描述

  • ptr 是要调整的内存地址
  • size 调整之后新大小
  • 返回值为调整之后的内存起始位置
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 的空间

realloc在调整内存空间的是存在两种情况:

  • 情况1:原有空间之后有足够大的空间
    要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化

  • 情况2:原有空间之后没有足够大的空间
    原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址

在这里插入图片描述
代码示例 (C语言):

// 情况1:原有空间之后有足够大的空间
int main()
{
	int* ptr = (int*)malloc(sizeof(int) * 10);
	if (ptr != NULL)
	{
		// ...
	}

	int* a = (int*)realloc(ptr, 30);

	free(a);
	a = NULL;

	return 0;
}

在这里插入图片描述

代码示例 (C语言):

// 情况2:原有空间之后没有足够大的空间
int main()
{
	int* ptr = (int*)malloc(sizeof(int) * 10);
	if (ptr != NULL)
	{
		// ...
	}

	int* a = (int*)realloc(ptr, 300000);

	free(a);
	a = NULL;

	return 0;
}

在这里插入图片描述


📜3. C/C++程序的内存开辟

在这里插入图片描述
C/C++程序内存分配的几个区域:

  • 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
    束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
    分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
    回地址等
  • 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
    配方式类似于链表
  • 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放
  • 代码段:存放函数体(类成员函数和全局函数)的二进制代码

📖4. 总结

在探索C语言动态内存管理的旅程即将结束时,我们不难发现,这一领域不仅是编程技能中的一块重要基石,更是深入理解计算机系统与资源管理的一把钥匙。通过掌握malloc、calloc、realloc和free等函数的使用,我们学会了如何在程序运行时根据需要动态地分配和释放内存空间,这为编写高效、灵活且可维护的代码提供了无限可能

然而,正如任何强大工具都伴随着责任一样,动态内存管理也要求我们具备高度的责任心与严谨性。内存泄漏、野指针、重复释放等问题若处理不当,不仅会影响程序的性能,更可能导致程序崩溃或数据损坏。因此,在享受动态内存管理带来的便利时,我们更应时刻铭记其背后的风险与挑战,通过良好的编程习惯和严格的代码审查来确保内存的安全与高效使用

“动态内存管理是C语言编程中的一把双刃剑,它既赋予了我们创造无限可能的力量,也要求我们以严谨和负责的态度去驾驭它。愿每一位编程爱好者都能在这条路上越走越远,用智慧和汗水书写属于自己的编程传奇。”

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2124436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线路及接口基础知识

目录 一、常见视频接口 一、常见视频接口

电话外呼系统对比普通电销有什么区别

电话外呼系统与普通电销在多个方面存在显著差异&#xff0c;这些差异主要体现在效率、成本、智能化程度、数据管理和客户体验等方面。以下是具体的对比分析&#xff1a; ### 一、效率差异 * **电话外呼系统**&#xff1a; - **高效性**&#xff1a;可以同时拨打大量电话&…

刚开始学精益六西格玛管理方法?这份指南建议收藏

精益六西格玛管理方法&#xff0c;作为两大管理哲学的完美结合&#xff0c;正逐渐成为众多企业转型升级的利器。对于刚开始接触这一领域的你来说&#xff0c;掌握精益六西格玛管理的精髓并有效应用于实践中&#xff0c;无疑是一项既具挑战性又极具价值的任务。本文&#xff0c;…

[Linux#48][网络] 令牌环网 | IPv4 | socket 套接字 | TCP | UDP | 网络字节序列

目录 1.网络 1.0 令牌环网&#xff08;了解&#xff09; 1.1 IP 地址 1.3 网络通信的基本脉络 IPv4地址解释 2.Socket 编程预备 2.1 端口号 2.2 传输层协议 2.3 网络字节序列 库函数定义 函数说明 1.网络 1.0 令牌环网&#xff08;了解&#xff09; 相同令牌时&am…

Nest.js 实战 (十三):实现 SSE 服务端主动向客户端推送消息

前言 假如系统又一个这样的业务场景&#xff1a;已登录的用户发起流程或者发布消息之后&#xff0c;需要弹窗通知其他已登录的用户&#xff0c;我们应该如何实现&#xff1f; 在设计实时通信场景时&#xff0c;我们面临的主要挑战是如何有效地通知所有已登录的用户有关新流程…

关于 PreparedStatement

Mysql 层面的语法也支持 prepare 这个确实第一次见 PREPARE prepares a statement for execution (see Section 13.5.1, “PREPARE Statement”).EXECUTE executes a prepared statement (see Section 13.5.2, “EXECUTE Statement”).DEALLOCATE PREPARE releases a prepared…

半天玩转大模型技术之RAG

引 言 当前大模型在金融行业最广泛的应用之一就是知识问答&#xff0c;而支撑该应用的技术正是当下火热的检索增强生成&#xff08;Retrieval Augmented Generation&#xff09;技术&#xff0c;简称 RAG。因企业具体的业务往往需要注入特定的知识&#xff0c;比如ChatBI中企业…

Google出了一个黑科技,可以把书变成真人多角色对话的音频,效果真的很牛!

大家有没有想过,像读书、查资料这种事情,如果可以用听的,效率会不会更高?我想大部分人都曾有过这种念头。尤其是在这信息爆炸的时代,手头上有大量的书籍、论文等资源,但我们根本没时间一页一页地去翻。对吧?这时,Google Illuminate 的出现,简直像是为我们解了燃眉之急…

力扣: 赎金信

文章目录 需求分析及编码结尾 需求 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次…

kubernetes中的微服务Service(ClusterIP、NodePort、LoadBalancer)

目录 一 、什么是微服务 二 、微服务的类型 三、 ipvs模式 3.1 ipvs模式配置方式 四、微服务类型详解 4.1 clusterip 4.2 ClusterIP中的特殊模式headless 4.3 nodeport 4.4 loadbalancer 4.5 metalLB 4.6 externalname 五 Ingress-nginx 5.1 ingress-nginx功能 5.2…

【大模型专栏—入门篇】CUDA入门与AutoDL“炼丹”

大模型专栏介绍 &#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文为大模型专栏子篇&#xff0c;大模型专栏将持续更新&#xff0c;主要讲解大模型从入门到实战打怪升级。如有兴趣&#xff0c;欢迎您的阅读。 &#x1f4…

PointNet++改进策略 :模块改进 | SWA| PVT,融入Transformer的点云与体素的模块同时提升模型精度和效率

目录 介绍PVT原理PVT的核心思想和结构PVT模块结构体素分支点分支 代码实现 论文题目&#xff1a;PVT: Point-Voxel Transformer for Point Cloud Learning发布期刊&#xff1a;International Journal of Intelligent Systems通讯地址&#xff1a;杭州电子科技大学&伦敦大学…

善于善行——贵金属回收

在当今社会&#xff0c;贵金属回收已成为一项日益重要的产业。随 着科技的不断进步和人们对资源可持续利用的认识逐渐提高&#xff0c;贵金属回收的现状也备受关注。 目前&#xff0c;贵金属回收市场呈现出蓬勃发展的态势。一方面&#xff0c;贵金属如金、银、铂、钯等在众多领…

【C语言】结构体超详细全讲解 (代码+万字文字+画图讲解)

目录 1.什么是结构体类型 2.结构体变量的创建 3.结构体变量的初始化 4.结构体的特殊声明 5.typedef重定义结构体变量&#xff08;两种方式&#xff09; 6.结构体自引用 7.创建结构体指针变量 8.结构体内容的访问 8.1直接访问&#xff1a; 8.2 结构体指针访问 9.结构体内…

IPD推行成功的核心要素(二十二)IPD流程持续优化性地推出具备商业成功潜力的产品与解决方案

产品开发是非常复杂的。随着创新环境的快速发展&#xff0c;大部分研发型企业普遍会面临着这些核心问题&#xff1a;如何快速响应市场的变化&#xff1f;如何推出更有竞争力的产品&#xff1f;如何在竞争中脱颖而出&#xff1f;因此&#xff0c;往往随着企业的规模化发展&#…

深度优先搜索(DFS)在图的运行过程

深度优先搜索(DFS)在图的运行过程 深度优先搜索算法(DFS)C语言实现运行DFS并记录结果节点发现时间和完成时间:图a是一个有向图,为了清晰起见,我们首先假设图a的具体结构如下(节点和边的集合): 图a: 节点集合: {A, B, C, D, E, F} 边集合: {(A, B), (A, C), (B, D),…

带你了解Android Jetpack库中的依赖注入框架:Hilt

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 Hilt概述 Hilt是Google推出的一种用于Android的依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;框架&#xff0c;构建于…

Java 学习中使用文件、网络连接等资源时,未正确关闭资源,导致资源泄漏应该怎么办?

在Java编程中&#xff0c;处理文件、网络连接、数据库连接等资源时&#xff0c;如果没有正确关闭资源&#xff0c;就会发生资源泄漏。资源泄漏会导致系统性能下降、内存占用增加&#xff0c;甚至可能导致程序崩溃&#xff0c;特别是在高负载的系统中。 一、什么是资源泄漏&…

【C+继承】

继承 1.继承的概念及定义2.基类和派生类对象赋值转换3.继承中的作用域4.派生类的默认成员函数5.继承与友元6.继承与静态成员7.复杂的菱形继承及菱形虚拟继承8.继承的总结和反思 1.继承的概念及定义 ->继承的概念 继承的本质&#xff1a;就是继承的父类的成员 ->继承的…

《哈利波特:魔法觉醒》仅16个月欧美停服,引来“阴谋论”

易采游戏网9月11日消息&#xff1a;2022年&#xff0c;当网易宣布将与华纳兄弟合作推出《哈利波特&#xff1a;魔法觉醒》时&#xff0c;全球玩家一片欢腾。不仅在中国市场掀起了一股狂潮&#xff0c;也迅速进入了欧美市场&#xff0c;吸引了无数哈迷和卡牌游戏爱好者。令人始料…