【柔性数组与局部性原理】

news2024/9/21 2:49:50

柔性数组概念

  • 柔性数组特点

  • 局部性原理

柔性数组概念

对于柔性数组,也许你之前从未听说过,柔性数组,顾名思义,就是数组,它的柔性柔在元素个数可以动态变化,
即柔性数组是未知大小的,数组大小可以动态变化的。
在结构体中,最后一个元素允许是未知大小的数组,这个数组就叫柔性数组成员。

下面直接举例子来说明柔性数组。

struct S
{
	int n;
	int arr[]; 
};

这就是一个柔性数组,柔性数组是在结构体中是未知大小的。

struct S
{
	int n;
	int arr[0]; 
};

上面这种写法也可以。

在这里插入图片描述
当我们进行编译时,编译通过。

柔性数组特点:

下面举例说明柔性数组的特点:

假设需要动态开辟一块内存空间,我们可以这样操作:

typedef struct S
{
	int n;
	int arr[];
};

当我们计算这个柔性数组的大小时,结果如下:
在这里插入图片描述
看到结果是4,可能你会疑惑,别着急,这就是柔性数组的第一个特点:

特点1:sizeof计算结构体大小时,不包括柔性数组的大小

所以计算上面的结构体的大小时,仅计算n大小,在进行结构体内存对齐后,结果是4 。

特点2:柔性数组成员之前必须至少有一个其他成员。

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

什么意思呢?举个例子:

typedef struct S
{
	int n;
	int arr[0]; 
}S;

int main()
{
	struct S s = { 0 };
	struct S* ps = (S*)malloc(sizeof(S) + 5 * sizeof(int));

	return 0;
}

看上面的代码:当我们动态申请一块内存时,申请的空间需要大于结构体本身的大小。
在后面增加适当的空间以适应柔性数组的大小。

下面举实际例子来说明柔性数组的一些好处:

typedef struct S
{
	int n;
	int arr[0]; 
}S;

int main()
{
	struct S s = { 0 };
	struct S* ps = (S*)malloc(sizeof(S) + 5 * sizeof(int));
	if (ps == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	ps->n = 100;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}

}

在内存中申请一块空间,这块空间在内存中是连续的。

在这里插入图片描述
然后将n 和arr分别赋值
在这里插入图片描述
如果想使用的空间不够,那就重新申请空间

struct S*ptr=realloc(ps, 44);

44 = 24(原结构体大小) + 20(5*int)

也就是再开辟五个int类型的空间

int main()
{
	struct S s = { 0 };
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
	if (ps == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	ps->n = 100;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}

	struct S*ptr=realloc(ps, 44);

	if (ptr != NULL)
	{
		ps = ptr;
	}

	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//释放
	free(ps);
	ps = NULL;
	return 0;
}

然后进行赋值,再打印出来,整个完整代码如上:
结果如下:

在这里插入图片描述

使用柔性数组动态开辟内存,这块空间是连续的。

下面来看另一种开辟内存的方法:

struct S
{
	int n;
	int* arr;
};

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	ps->arr = malloc(sizeof(int) * 5);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}

	//加大内存,调整大小
	int *ptr=  realloc(ps->arr, 10 * sizeof(int));
	if (ptr != NULL)
	{
		ps->arr = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
	}

	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	free(ps->arr);//free要有先后顺序
	free(ps);
	ps = NULL;
	return 0;
}

看不懂代码?请看下图:

在这里插入图片描述
首先申请了第一块空间结构体指针ps,该指针指向了上面的S结构体,第二次申请的空间是 ps所指向的结构体成员指针arr,为这个arr成员申请了一块空间,然后增加空间。

在两次申请的过程中,两块空间ps 和 arr所指向的空间 都是在堆区上,结构体是在栈区上,所以释放的时候,只释放申请出来的两块空间,不需要释放结构体空间。

对比两段代码,可以看出不同点:

在第一段代码中,申请的空间是连续的,第二段代码中,申请的空间是不连续的。

第一段代码申请的空间只需free一次,第二段代码申请的空间需要free两次,并且free的先后顺序有要求,需要先释放arr指向的空间,再释放ps。如果释放顺序相反,会导致arr指向的空间就失踪了, 也就是没人能知道arr指向的空间在哪。

所以,在这里使用柔性数组的好处有:

1.方便释放空间。

2.利于内存访问

第二点如何理解?

下面引出局部性原理的概念:

局部性原理

局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。

意思是:当我们访问一块空间时,接下来有 80%的可能性会访问它周边的数据。

来看下面:

在这里插入图片描述

一个存储器层次结构图如上:

直接画出主要的布局:
在这里插入图片描述
cpu在访问空间时,首先会在寄存器中读取数据,如果寄存器中没有那块需要读取的空间,就会去高速缓存中寻找,如果高速缓存中也没有这块内存区域,它就会去硬盘中寻找。

这样层层往下寻找。
如上图:
假如需要读取的空间是连续的,那么这块空间放在寄存器中时,cpu先读取一小部分空间,根据局部性原理:cpu有80%的几率读取周围的空间,这样就能够提高访问效率。
这就是使用柔性数组的好处

假如读取的空间是不连续的,而是碎片式的访问。这样读取效率就会降低。
所以,柔性数组的好处在于:
1.方便释放空间。

2.利于内存访问

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

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

相关文章

Elasticsearch:使用 Node.js 将实时数据提取到 Elasticsearch 中(二)

在我的上一篇文章 “Elasticsearch&#xff1a;使用 Node.js 将实时数据提取到 Elasticsearch 中&#xff08;一&#xff09;”&#xff0c;我详细描述了如何如何使用 Node.js 来采集地震数据。在今天的文章中&#xff0c;我们来详细描述如何对数据可视化。我们还将创建一个 we…

推荐七个Python效率工具!让你事半功倍

为了提高效率&#xff0c;我们在平时工作中常会用到一些Python的效率工具&#xff0c;Python作为比较老的编程语言&#xff0c;它可以实现日常工作的各种自动化。为了更便利的开发项目&#xff0c;这里给大家推荐几个Python的效率工具。 1、Pandas-用于数据分析 Pandas是一个强…

UEditorPlus v2.8.0发布 颜色自定义,文档功能完善

UEditor是由百度开发的所见即所得的开源富文本编辑器&#xff0c;基于MIT开源协议&#xff0c;该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器&#xff0c;主要做了样式的定制&#xff0c;更符…

vim使用教程图文教程(超详细)

1. 三种模式 vim编辑器有三种模式&#xff1a;命令模式、编辑模式、末行模式。 「命令模式」&#xff1a;可以进行删除、复制、粘贴等快捷操作。「编辑模式」&#xff1a;可以编辑文件内容。「末行模式」&#xff1a;可以通过命令操作文件&#xff0c;比如搜索、保存、退出等…

【C语言】字符串小练习(每日小细节012)

前言&#xff1a; 欢迎打开这篇博客&#xff0c;从今天开始&#xff0c;每天和大家分享一个C语言小细节&#xff0c;不久之后还会追加C 一些常常被忽视的小细节和思想统一的编程题目是这个专栏的核心哦 虽然简单但千万别在细节处失分&#xff01;&#xff01;&#xff01;&…

【Linux编辑神器:vim】

目录 1. vim的基本概念 2. vim的基本操作 3. vim正常模式命令集 4. vim底行模式命令集 5. 简单vim配置 6 总结 什么是Vi/Vim? vi/vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本&#xff0c;它不仅兼容vi的所有指令&#xff0…

【算法】关于双指针的奇技淫巧(一):对撞指针

一、对撞指针 对撞指针由两个指针组成&#xff0c;分别指向数据的头部和尾部&#xff1a; 两个指针分别从两头移动&#xff0c;寻找符合答案的位置后停下。对撞指针主要应用于有序数组的求和&#xff0c;我们使用一个题目进行说明&#xff1a; 示例如下&#xff1a; 根据题目可…

元数据管理Datahub基本介绍和特点

目录1. 基本介绍2. 功能特色2.1 支持不同平台的元数据同步和搜索2.2 血缘关系2.3 查询数据集的统计信息2.4 实时治理2.5 Datahub的权限管理2.6 使用Domains、Glossary Terms、tags对数据Entity进行管理2.7 在Web界面对元数据进行管理1. 基本介绍 Datahub是现代数据栈的元数据管…

TypeScript(一)TypeScript下载安装,编译运行的三种方式:tsc命令行/webpack搭建环境/tsc-node库

什么是TypeScript? TypeScript是拥有类型的JavaScript超集&#xff0c;它可以编译成普通、干净、完整的JavaScript代码。 简单理解&#xff1a;TypeScript就是加强版的JavaScript TypeScript环境搭建 搭建前准备 TypeScript最终会被编译成JavaScript代码&#xff0c;那么我…

JavaSE笔记——函数式编程(类库)

文章目录前言一、基本类型二、重载解析三、FunctionalInterface四、默认方法五、Optional总结前言 前面知道了如何编写 Lambda 表达式&#xff0c;下面将详细阐述另一个重要方面&#xff1a;如何使用 Lambda 表达式。即使不需要编写像 Stream 这样重度使用函数式编程风格的类库…

find_package()的使用

find_package()命令是用来查找依赖包的&#xff0c;理想情况下&#xff0c;一句find_package()把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到&#xff0c;后续只管用就好了。但实际中往往CMake失败就是出在find_package()的失败上&#xff08;这里不考…

朝花夕拾 - 2023 莽一年

Hello 2023&#xff0c;我来了~今年&#xff0c;又是一个怎样的楚门世界&#xff0c;我要如何在里面撒泼&#xff0c;期待~一 回收 2022 不及格答卷 回首 2022&#xff0c;那真的不堪回首&#xff0c;细节太多了&#xff0c;没做好没把握住~但是&#xff0c;不管 2022 过得怎样…

Qt6 中如何使用 qsb

【写在前面】 Qt 5 的图形体系结构非常依赖 OpenGL 作为底层 3D 图形 API。但过去 8 年来随着 Metal 和 Vulkan 的推出&#xff0c;市场发生了巨大变化。现在&#xff0c;Qt 6 加入了大量不同平台的图形 API&#xff0c;以确保用户可以在所有平台上以最高性能运行 Qt。 在 Qt Q…

【类和对象(完结)】

目录 1. 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit关键字 2. static成员 2.1 概念 2.2 特性 3. 友元 3.1 友元函数 3.2 友元类 4. 内部类 5.匿名对象 6.拷贝对象时的一些编译器优化 7. 再次理解类和对象 8.总结 1. 再谈构造函数 1.1 构造函数体…

技术分享| 如何使用Prometheus实现系统进程监控

如何监控线上正在运营的系统&#xff1f;如何得知系统目前是正常还是异常&#xff1f; Prometheus是这么一套数据监控解决方案。它能让运维及开发人员随时掌控系统的运行状态&#xff0c;快速定位出现问题的位置&#xff0c;快速排除故障。只要按照 Prometheus的方式来做&#…

力扣刷题记录——258. 各位相加、263.丑数、268.丢失的数字

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《258. 各位相加、263.丑数、268.丢失的数字》。 目录 25…

第三十五讲:神州无线局域网基础知识

1. IEEE 802.11协议 802.11无线标准家族包括802.11a/b/g/n/ac五个标准理论上可以提供高达每秒1Gbit的数据传输能力标准定义了如何使用免授权2.4 GHz 和 5GHz 频带的电磁波进行信号传输。 802.11无线标准家族 802.11a 802.11b 802.11g 802.11n 802.11ac 工作频段 5GHz 2…

内存访问为什么要分段?

内存分段是处理器为访问内存而设计的机制&#xff0c;称为内存分段机制。 简单的内存知识 内存结构&#xff08;连续且地址依次升高&#xff09; 访问方式 内存是随机读写设备&#xff0c;即访问其内部任何处&#xff0c;不需要从头开始找&#xff0c;只要直接给出其地址便可。…

【项目启动】IDEA新建项目同步到Github

文章目录SSH秘钥检查GitHub创建项目IDEA创建项目IDEA同步GitHubSSH秘钥检查 目前&#xff0c;github不支持https形式的远程同步方式&#xff0c;如果使用https形式进行同步会报以下错误&#xff1a; remote: Support for password authentication was removed on August 13, 2…

C# WinForm CAD文件显示(dxf,dwg显示)

找遍全网很难找到开源dxf显示控件(C# winform)&#xff0c;大部分控件都需要收费&#xff0c;对于做软件开发很麻烦 C# WPF倒是有nefdxfZoomableCanvas可以实现&#xff0c;确实很方便&#xff0c;这个在github&#xff1a;https://github.com/shao200/WpfDxfViewer上也能找到开…