保姆级教学 - C语言 之 动态内存管理

 

🌈 个人主页:白子寰
🔥 分类专栏:魔法指针,进阶C++,C语言,C语言题集,C语言实现游戏👈 希望得到您的订阅和支持~
💡 坚持创作博文(平均质量分79.9+),分享更多关于深度学习、C/C++领域的优质内容!(希望得到您的关注~) 

目录

为什么会有动态内存的分配

 malloc 和 free

动态内存开辟的函数:malloc函数

动态内存的释放和回收:free函数 

calloc 和 realloc

动态内存分配:calloc函数

让动态内存管理更加灵活:realloc函数

 relloc调整空间成功的两种情况

 常见动态内存的错误

1)对NULL指针的解引用操作

错误示范

正确使用

2)对内存开辟空间的越界访问

错误示范

正确使用

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

错误示范

正确使用

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

错误示范

正确使用

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

错误示范

正确使用

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

错误示范

正确使用

 柔性数组

柔性数组的介绍

涉及到柔性数组的特点

代码①段

​编辑 

代码②段

两段代码的区别


 

为什么会有动态内存的分配

看下面代码:

①创建一个整型叫a并初始化赋值为10 

②创建一个10个元素的数组,并全部初始化为0

int main()
{
	int a = 10;         //在栈区空间开辟了四个字节
	int arr[10] = { 0 };//在栈区空间连续开辟了10*4=40个字节

	return 0;
}

于是我们发现上述开辟空间有两个特点

①开辟空间大小是固定的;

②数组开辟空间是连续有长度的,且确定了空间大小不能改


 

 malloc 和 free

malloc和free函数都需要包含头文件:include<stdlib.h>

动态内存开辟的函数:malloc函数

函数原型:void* malloc(size_t size);

作用:malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针

注:返回值为void*,malloc函数开辟空间的类型由使用者自己决定

动态内存的释放和回收:free函数 

函数原型:void* free(*ptr)

作用:free函数释放动态开辟的内存

注:

①如果ptr指向的空间不是开辟动态内存的,则free函数的行为是未定义的

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

#include<stdlib.h>
int main()
{
	//int* p = (int*)malloc(10 * sizeof(int));

	if (p == NULL)
	{
		perror("malloc");
		return 1;//如果是空指针,返回1,下面代码不再执行
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		//赋值
		*(p + i) = i;
	}

	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}

	//释放空间
	free(p);
	p = NULL;//为了避免p成为野指针,最后要把p设置为空指针

	return 0;
}

 


calloc 和 realloc

动态内存分配:calloc函数

函数原型:void* calloc(size_t num,size_t size);

calloc和malloc函数的区别是:calloc函数可以把开辟的每一个值初始化为0

calloc和malloc函数的共同点是:能调整空间

让动态内存管理更加灵活:realloc函数

函数原型:void*(void* ptr,size_t size);

其中ptr是要调整内存地址,size是调整之后的新大小

作用:对动态开辟内存大小做灵活的调整

int main()
{
	int* p = (int*)calloc(10, sizeof(int));

	if (p == NULL)
	{
		perror("malloc");
		return 1;//如果是空指针,返回1,下面代码不再执行
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));//打印出来10个都是0,说明calloc函数是初始化值为0
	}

	int* ptr = (int*)realloc(p, 12);
	if (ptr == NULL)
	{
		perror("realloc");//realloc调整空间失败返回NULL
		return 1;
	}
	else
	{
		p = ptr;
	}
	//释放空间
	free(p);
	p = NULL;//为了避免p成为野指针,最后要把p设置为空指针

	return 0;
}

 relloc调整空间成功的两种情况

 


 常见动态内存的错误

1)对NULL指针的解引用操作

错误示范

正确使用

int main()
{
	int* p = (int*)malloc(10 * sizeof(int));

	//对p判断是否为空指针
	if (p == NULL)
	{
		perror("malloc");
		return 1;//如果是空指针,返回1,下面代码不再执行
	}

	//使用
	*p = 20;

	//释放空间
	free(p);
	p = NULL;//为了避免p成为野指针,最后要把p设置为空指针

	return 0;
}

 

2)对内存开辟空间的越界访问

错误示范

正确使用

开辟内存空间多少,使用的时候就要对应多少


 

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

错误示范

p取非动态内存,然后p在非动态内存使用free释放

正确使用

free函数原型:void* free(*ptr)

作用:free函数释放动态开辟的内存

如果ptr指向的空间不是开辟动态内存的,则free函数的行为是未定义的


 

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

错误示范

p 不再指向动态内存的起始位置

正确使用

free函数释放时p要指向动态内存的起始位置

 


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

错误示范

正确使用

开辟动态内存使用完后一定要释放,并把p设置为空指针


 

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

错误示范

正确使用

忘记释放不再使⽤的动态开辟的空间会造成内存泄漏


 柔性数组

柔性数组的介绍

概念:在C99中,结构中的最后一个元素允许是未知大小的数组,这就叫【柔性数组】成员

我们先来看一段代码

struct st
{
	int i;
	int arr[0];//柔性数组成员
};

int main()
{
	printf("%zd\n", sizeof(struct st));
	return 0;
}

这段代码输出什么?

答案:

为什么?

涉及到柔性数组的特点

1)sizeof返回的结构大小不包括柔性数组的内存

2)结构中的柔性数组成员前面必须至少一个成员

以上两点都很好的解释上面👆的代码

3)包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小

让我们接着讨论第三个特点

让我们想想,为什么要用柔性数组?


 

 我们来看👇下面代码,代码有点长,每一段代码我注释了,供大家食用

代码①段

#include<stdlib.h>
//结构体
struct st
{
	char ch;
	int i;
	int arr[0];
};

int main()
{
	//printf("%zd\n", sizeof(struct st));//8
	//结构体指针+malloc函数开辟空间
	struct st* p = (struct st*)malloc(sizeof(struct st) + 10 * sizeof(int));
	                                //               8  + 10 * 4 = 48
	//判断p是否为空指针
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}

	//给结构体的成员赋值
	p->i = 66;
	p->ch = 'b';
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p->arr[i] = i;
	}

	//数组空间不够,realloc函数使用
	struct st* ptr = realloc(p, sizeof(struct st) + 15 * sizeof(int));
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		p = ptr;
	}

	//继续使用
	for (i = 10; i < 15; i++)
	{
		ptr->arr[i] = i;
	}

	//打印输出
	for (i = 0; i < 15; i++)
	{
		printf("%d ", ptr->arr[i]);
	}
	printf("\n");
	printf("%d\n%c\n", ptr->i, ptr->ch);
	
	//释放空间
	free(ptr);
	ptr = NULL;

	return 0;
}

控制台结果显示

 

🆗,我们接着讨论为什么叫柔性数组?


 

代码②段

//结构体
struct st
{
	char ch;
	int i;
	int *arr;
};

int main()
{
	//printf("%zd\n", sizeof(struct st));//12
	//结构体指针+malloc函数开辟空间
	struct st* p = (struct st*)malloc(sizeof(struct st));
	                                
	//判断p是否为空指针
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}

	//给结构体的成员赋值
	p->i = 66;
	p->ch = 'b';
	p->arr = (int*)malloc(10 * sizeof(int));

	if (p->arr == NULL)
	{
		perror("malloc.2");
		return 1;
	}

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p->arr[i] = i;
	}

	//数组空间不够,realloc函数使用
	int* ptr = (int*)realloc(p->arr, 15 * sizeof(int));
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		p->arr = ptr;
	}

	//继续使用
	for (i = 10; i < 15; i++)
	{
		p->arr[i] = i;
	}

	//打印输出
	for (i = 0; i < 15; i++)
	{
		printf("%d ", p->arr[i]);
	}
	printf("\n");
	printf("%d\n%c\n", p->i, p->ch);


	//释放空间
	free(p->arr);
	p->arr = NULL;

	free(p);
	p = NULL;

	return 0;
}

 

两段代码的区别

 

 


 

 ①段代码的两个优点

①方便内存释放

②利于访问速度


 

 ***********************************************************分割线*****************************************************************************
完结!!!
感谢浏览和阅读。

等等等等一下,分享最近喜欢的一句话:

“不要取轻信别人定义的你们自己,只有你们可以自己定义你们自己”。

我是白子寰,如果你喜欢我的作品,不妨你留个点赞+关注让我知道你曾来过。
你的点赞和关注是我持续写作的动力!!! 
好了划走吧。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

shell常用通配符

目录 介绍 示例 * ? [a,b,...] / [ab...] [^a,b,...] / [^ab...] [x1-x2] {"xxx","xxx","xxx",...} {x1..x2} 介绍 示例 * 匹配0或多个字符 ls的-d选项可以只列出当前目录下的文件,而不会列出他们包含的内容: ? 只匹配任意一个字符 …

MySQL基础(DDL,DML,DQL)

目录 一DDL 1.1数据库操作 1.1.1查询所有数据库&#xff1a; 1.1.2创建数据库 1.1.3 使用数据库 1.1.4 删除数据库 1.2表操作 1.2.1表操作 1.2.1.1创建表 1.2.1.1.1约束 1.2.1.1.2 数据类型 1.2.1.1.2.1 数值类型 1.2.1.1.2.2 字符串类型 1.2.1.1.2.3日期类型 1.…

Linux源码包安装

目录 一、transmission源码包安装 二、 nginx源码包安装 一、transmission源码包安装 1、下载编译环境所需的软件包依赖 2、下载transmision源码包到用户主目录下 https://github.com/transmission/transmission/releases/download/4.0.5/transmission-4.0.5.tar.xz 3、解压…

支持度和置信度

支持度和置信度是数据挖掘和关联规则挖掘领域中常用的两个指标&#xff0c;用于衡量项集之间的关联程度。 支持度&#xff08;Support&#xff09;&#xff1a;支持度是指某个项集在数据集中出现的频率&#xff0c;即该项集在数据集中出现的次数与总事务数之比。支持度用来衡量…

Qt 利用共享内存实现一次只能启动一个程序(单实例运行)

Qt 利用共享内存实现一次只能启动一个程序 文章目录 Qt 利用共享内存实现一次只能启动一个程序摘要利用共享内存实现一次只能启动一个程序示例代码 关键字&#xff1a; Qt、 unique、 单一、 QSharedMemory、 共享内存 摘要 今天接着在公司搞我的屎山代码&#xff0c;按照…

数学建模(层次分析法 python代码 案例)

目录 介绍&#xff1a; 模板&#xff1a; 例题&#xff1a;从景色、花费、饮食&#xff0c;男女比例四个方面去选取目的地 准则重要性矩阵&#xff1a; 每个准则的方案矩阵&#xff1a;​ 一致性检验&#xff1a; 特征值法求权值&#xff1a; 完整代码&#xff1a; 运行结…

基于ssm新生报到系统论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对新生报到信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

containerd源代码分析: 整体架构

本文从代码的大的整体组织上来熟悉containerd项目 containerd项目总的说是一个cs模式的原生控制台程序组。containerd作为服务端来接收处理client的各种请求&#xff0c;如常用的拉取推送镜像&#xff0c;创建查询停止容器&#xff0c;生成快照&#xff0c;发送消息等。client/…

About Online Taxis

About Online Taxis 关于网络预约出租汽车&#xff08;网约车&#xff09; 1&#xff09;网络预约出租汽车 驾驶员证&#xff08;人证&#xff09; 2&#xff09;网络预约出租汽车 运输证&#xff08;车证&#xff09; 民之苦已久......

【PHP】通过PHP安装数据库并使数据初始化

一、前言 有些CMS在部署的时候不用使用数据库工具&#xff0c;而是通过数据库安装页面就能完成数据库创建和数据填充&#xff0c;所以自己就想动手做一个这样的功能&#xff0c;这样在给别人安装系统的时候就不用再那么麻烦了&#xff0c;直接一键安装解决了。 二、效果图 输…

jupyter notebook使用教程

首先是打开jupyter notebook 下载安装好之后&#xff0c;直接在命令行中输入‘jupyter notebook’即可跳转到对应页面 还可以进入想要打开的文件夹&#xff0c;然后再文件夹中打开中断&#xff0c;执行‘jupyter notebook’命令&#xff0c;就能够打开对应文件界面的jupyter …

iOS模拟器 Unable to boot the Simulator —— Ficow笔记

本文首发于 Ficow Shen’s Blog&#xff0c;原文地址&#xff1a; iOS模拟器 Unable to boot the Simulator —— Ficow笔记。 内容概览 前言终结模拟器进程命令行改权限清除模拟器缓存总结 前言 iOS模拟器和Xcode一样不靠谱&#xff0c;问题也不少。&#x1f602; 那就有病治…

时序预测 | Matlab基于BiTCN-LSTM双向时间卷积长短期记忆神经网络时间序列预测

时序预测 | Matlab基于BiTCN-LSTM双向时间卷积长短期记忆神经网络时间序列预测 目录 时序预测 | Matlab基于BiTCN-LSTM双向时间卷积长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab基于BiTCN-LSTM双向时间卷积长短期记忆神经网络时…

PSO-CNN-SVM,基于PSO粒子群优化算法优化卷积神经网络CNN结合支持向量机SVM数据分类(多特征输入多分类)-附代码

PSO-CNN-SVM&#xff0c;基于PSO粒子群优化算法优化卷积神经网络CNN结合支持向量机SVM数据分类 下面是一个大致的步骤&#xff1a; 数据准备&#xff1a; 准备训练集和测试集数据。对数据进行预处理&#xff0c;包括归一化、标准化等。 设计CNN模型&#xff1a; 设计合适的CNN…

vue.config.js配置项

vue.config.js配置项 vue-cli3 脚手架搭建完成后&#xff0c;项目目录中没有 vue.config.js 文件&#xff0c;需要手动创建 创建vue.config.js vue.config.js(相当于之前的webpack.config.js) 是一个可选的配置文件&#xff0c;如果项目的 (和 package.json 同级的) 根目录中存…

基于OrangePi Zero2的智能家居项目(准备阶段)

一、需求及项目准备&#xff08;前期准备&#xff09; 1、各类的需求 以及复习巩固的东西 2、系统框架图 3、硬连接线 3.1硬件准备 USB充电头&#xff08;当前实测可用&#xff1a;5V/2.5A)x1、USB转TYPE-Cx1、SU-03Tx1、烟雾报警模块x1、4路继 电器x1、 OLEDx1、 电磁锁x1&a…

【C语言】多文件编程以及static关键字

1、多文件编程 把函数声明放在头文件xxx.h中&#xff0c;在主函数中包含相应头文件在头文件对应的xxx.c中实现xxx.h声明的函数 a、主文件 #include<stdio.h> #include "MyMain.h"//需要包含头文件&#xff0c;头文件包含我们自定义的函数int main(){int num…

JWT的实现及其适用场景

官方文档 一、什么是JWT JWT&#xff08;全称JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于作为JSON对象在各方之间安全地传输信息。此信息是经过数字签名的&#xff0c;因此可以验…

分页多线程处理大批量数据

1.业务场景 因为需要从一个返利明细表中获取大量的数据&#xff0c;生成返利报告&#xff0c;耗时相对较久&#xff0c;作为后台任务执行。但是后台任务如果不用多线程处理&#xff0c;也会要很长时间才能处理完。 另外考虑到数据量大&#xff0c;不能一次查询所有数据在内存…

LaTeX论文汇报ppt模板

在 LaTeX 的 beamer 类中&#xff0c;您可以使用不同的主题和模板来创建适合论文汇报的演示文稿。以下是一个使用了比较正式的 Madrid 主题的模板&#xff0c;您可以基于这个模板进行定制和扩展&#xff0c;以满足您论文汇报的需求。当需要在ppt输入中文的时候需要将第一行中的…