C语言进阶——动态内存管理

news2025/1/21 12:11:15

目录

一.   为什么存在动态内存分配

二.   动态内存函数

1.malloc

2.free

3.calloc

4.realloc 

三.   常见的动态内存错误


一.   为什么存在动态内存分配

在此之前,我们为数组开配空间都是这样的

int nums[10]={0};

但这样会有很大的局限性

1. 空间开辟大小是固定的。

2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。

这时候就只能试试动态内存开辟了



二.   动态内存函数

1.malloc

说白了,就是在堆区开辟一块大小为size字节的连续的空间 ,然后以指针形式返回这块空间的地址

而具体在使用时,例如开辟一个大小为5的整形数组,往往遵循以下的形式

int* nums=(int*)malloc(5*sizeof(int));

可以看到,由于malloc函数返回的是void*指针类型,所以我们需要进行强制类型转换,而后面的size,我们采用的是开辟数组大小*类型大小,这样也更容易理解

而当开辟失败时(可能是开辟空间过大,堆区没有这么大的空间了),则返回NULL指针,因此,在使用malloc开辟空间后,在使用这个数组之前,我们需要先进行检查

int* nums=(int*)malloc(5*sizeof(int));
if(nums==NULL)
{
    printf("malloc fail\n");
    exit(-1);
}

而还有一点就是,若是size的大小为0,这种情况是未定义的,如何处理取决于编译器,因此我们要避免这种情况发生。

而若是想要使用这块空间,就像数组的数组名一样使用

int main()
{
	int* nums = (int*)malloc(5 * sizeof(int));
    if(nums==NULL)
    {
        printf("malloc fail\n");
        exit(-1);
    }
	for (int i = 0; i < 5; i++)
	{
		nums[i] = i + 1;
		*(nums + i) = i + 1;
	}
	return 0;
}

这两种方法都是可以的。

同样,我们可以开辟一个指针数组,进而可以模拟一个二维数组

int main()
{
	int** nums = (int**)malloc(5 * sizeof(int*));
	if (nums == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	for (int i = 0; i < 5; i++)
	{
		nums[i] = (int*)malloc(5 * sizeof(int));
		if (nums[i] == NULL)
		{
			printf("malloc fail\n");
			exit(-1);
		}
	}
	return 0;
}

当然,这只是模拟的二维数组,每个一维数组在内存中都不是连续的,而真正的二维数组是连续的,但两者在使用上并没有太多差异


2.free

都已经开辟了,在不使用的情况下如果不把他释放就会一直占用堆区的空间,导致内存泄漏,而动态开辟的空间又不会随着域的结束而结束,这时我们便需要一个函数来主动释放

就是把动态开辟返回的指针作为参数,就能实现释放了

有两点需要注意: 

如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

如果参数 ptr 是NULL指针,则函数什么事都不做


3.calloc

说简单点,与malloc只是有写法上的不同,是将大小和类型大小分开传参

还有一点不同的是,会将所有元素初始化为0,其他特性与malloc类似


4.realloc 

说简单点,就是将开辟的空间扩增或者缩小

缩小没啥好说的,原地缩就行了,而扩增时,若是原本空间后面没有足够的空间,便会另找一块足够大的空间来存储。而若是没有这块空间,也一样会返回NULL,因此,我们不能拿原数组直接来接受返回值,而是定义一个新的指针来接受,并将其赋给原数组,若是NULL就不赋给原数组,因此也不会对原数组产生影响

而在赋给原数组后,若是重新开辟的空间(而不是在原数组的基础上扩容),那么原数组原本所在的位置会被自动销毁。

int main()
{
	int* nums = (int*)calloc(5 , sizeof(int));
	int* p = (int*)realloc(nums, 100 * sizeof(int));
	if (p == NULL)
	{
		printf("realloc fail\n");
		exit(-1);
	}
	nums = p;
	return 0;
}

大概就是这样

而我们也可以在调试时监视一下

 

   可以看到,这就是重新开辟空间的情况



三.   常见的动态内存错误

对NULL指针的解引用操作

对动态开辟空间的越界访问

对非动态开辟内存使用free释放

使用free释放一块动态开辟内存的一部分

对同一块动态内存多次释放

动态开辟内存忘记释放(内存泄漏)
 

上述错误我们在上面或多或少的都提到了,这就就不展开讲了(懒)
 

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

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

相关文章

十三、Gtk4-TfeTextView函数

TfeTextView相关函数在这一章节介绍 1 tfetextview.h 头文件tfetextview.h提供了: TfeTextView的类型&#xff0c;是TFE_TYPE_TEXT_VIEW。G_DECLARE_FINAL_TYPE的扩展包含了一些有用的宏。定义了open-response信号的常量。tfetextview.c的公共函数被声明。 因此&#xff0c…

「布道人生」第一期:阿里云DevOps资深专家章屹

本期嘉宾——章 屹 阿里云 DevOps 资深专家。2012 年加入阿里巴巴&#xff0c;十年如一日专注在 DevOps 领域的理论、咨询、解决方案和产品技术工作上。作为 CIO 学院和阿里云大学的讲师&#xff0c;为众多大型企业管理高层讲授 DevOps 课程&#xff0c;探讨通过 DevOps 提升企…

drawCell | 不会画细胞结构图就用这个R包吧~ Super Nice!~

1写在前面 我们在paper中经常需要画到细胞结构图&#xff0c;新手ppt一点一点画&#xff0c;高手可能会用AI手搓&#xff0c;土豪直接使用BioRender。&#x1f912; 今天给大家大家分享一个代码画细胞结构图的R包&#xff0c;如果你觉得自己不会写代码&#xff0c;不想看了&…

python基础篇之元组、字典(增删改查)

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主lqj_本人擅长微信小程序,前端,vue,等方面的知识https://blog.csdn.net/lbcyllqj?spm1000.2115.3001.5343 哔哩哔哩欢迎关注&…

震旦ad188复印机报机器故障维修召唤c0211

故障现象: 手送走纸的机器出现嗒嗒的异响,走几张还会跳0211,经常出现卡纸等现象,或者报C0211; 故障分析: 维修召唤C0211可能是感光鼓和载体寿命到期࿰

云原生|Java二级高速缓存架构设计

为什么使用缓存 缓存&#xff0c;主要有两个用途&#xff1a;提高服务性能和并发。 缓存是提高服务响应速度最快的方式之一。 我们设计缓存的目的是减少用户直接访问磁盘、访问网络带来的性能损耗&#xff0c;把磁盘、网络请求的内容存在在内存中&#xff0c;提升应用程序的…

【Doris】Doris数据库最新版安装方法,详细图文教程

环境安装 Doris 作为一款开源的 MPP 架构 OLAP 数据库&#xff0c;能够运行在绝大多数主流的商用服务器上。为了能够充分运用 MPP 架构的并发优势&#xff0c;以及 Doris 的高可用特性&#xff0c;我们建议 Doris 的部署遵循以下需求&#xff1a; Linux 操作系统版本需求Linu…

研讨会回顾 | UI自动化测试现场演示

2022年12月6日&#xff0c;龙智与软件测试自动化“领导者”SmartBear联合举办了主题为“如何通过自动化测试实现降本、增效与提质”的在线研讨会。此次研讨会中&#xff0c;龙智技术工程师邱洁玉现场演示了使用UI自动化测试的过程&#xff0c;并简要介绍了API的自动化测试。 软…

时钟频率与时间单位的换算

1. 频率、时间 各自的单位的关系 频率&#xff1a; 1GHz 1000MHz、1MHz 1000KHz、1KHz 1000Hz 1GHz 103MHz 106KHz 109Hz 时间&#xff1a; 1s 1000ms、1ms 1000μs、1μs 1000ns [注]&#xff1a;s (秒)、ms (毫秒)、μs (微秒)、ns (纳秒)。 2. 时间 和 频率 的换…

jsp税务管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 税务管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开 发&#xff0c;数据库为Mysql&#xff0c;使用ja…

【SpringCloud10】OpenFeign服务接口调用

1.概述 1.1OpenFeign是什么 官网 Feign是一个声明式WebService客户端&#xff0c;使用Feign能让编写Web Service客户端更加简单。 它的使用方法是定义一个服务接口然后在上面添加注解&#xff0c;Feign也支持可拔插式的编码器和解码器&#xff0c;Spring Cloud对Feign进行了…

设计模式-JDBC中的桥接模式

一、首先看整个brige模式的结构图。如下&#xff1a;Abstraction — 抽象化角色&#xff1a;定义抽象的接口&#xff0c;包含一个对实现化角色的引用Refined Abstraciotn — 扩展抽象化角色&#xff1a;抽象化角色的子类&#xff0c;实现父类中的业务方法&#xff0c;并通过组合…

录屏专家怎么用?录屏软件使用教程(附下载)

想要更好地录制电脑屏幕可以使用电脑录屏专家&#xff0c;但有很多人在安装录屏专家之后&#xff0c;不知道如何使用。录屏专家怎么用&#xff1f;怎样使用录屏专家录制电脑屏幕&#xff1f;下面小编给您分享录屏软件使用的教程&#xff08;附安装教程&#xff09;&#xff0c;…

RabbitMQ实战:性能和安全

本系列是「RabbitMQ实战&#xff1a;高效部署分布式消息队列」书籍的总结笔记。 前两篇介绍了RabbitMQ在可用性、监控方面的考虑&#xff0c;这是基础保障&#xff0c;因为在某些场景下是不容许丢失消息的&#xff0c;但它和性能往往是对立的&#xff0c;需要根据业务场景做取舍…

JSP SSM众包网站系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 JSP SSM众包网站系统 是一套完善的系统源码&#xff0c;对理解JSP java SrpingMVC mybiats 框架 MVC编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档&#xff0c;系统主要采用B/S模式开发。 研究的基本内容…

JUC并发编程学习笔记——CAS个人理解

1. CAS引出 1.1 悲观锁 顾名思义&#xff0c;就是比较悲观的锁&#xff0c;总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都会上锁&#xff0c;这样别人想拿这个数据就会阻塞直到它拿到锁&#xff08;共享资源每次只…

什么是 HTTP?

什么是 HTTP&#xff1f; 超文本传输协议 (HTTP) 是万维网的基础&#xff0c;用于通过超文本链接加载网页。HTTP 是应用程序层协议&#xff0c;旨在在联网设备之间传输信息&#xff0c;并在网络协议栈的其他层之上运行。HTTP 上的典型流涉及客户端计算机向服务器发出请求&…

2023CUPT第十四题 射流的折射 思路与解法

文章未完首先声明一点&#xff0c;这个题我还没想好最后的答案&#xff0c;欢迎交流&#xff08;备注&#xff1a;博主今年不参加CUPT 博主去做电子设计大赛了&#xff01;有电赛谁还玩CUPT啊&#xff09;声明2&#xff1a;博主没有学过流体力学所以。。声明3&#xff1a;博主的…

[oeasy]python0045_转化为10进制数_int_integrate_integer_entire_整数

转化为10进制 回忆上次内容 上这次总结了四种进制 函数名对应单词进制类型数字事例前缀bin()binary20b11000010boct()octal80o1410ohex()hexadecimal160x610x?decimal1097无 十进制数 可以转化 为 其他进制 的 字符串状态 那反过来 其他进制形态的字符串 可以转化回 10进制…

Qt 自带标题处理方法思路

目录 需求 相关方法也有两种 1.只需要继承QAbstractNativeEventFilter类&#xff0c;从写放nativeEventFilter&#xff0c;并调用安装函数installNativeEventFilter 2.第二种是Qt提供的继承QWidget 重写bool nativeEvent(const QByteArray &eventType, void *message, …