一分钟 帮你搞懂什么是柔性数组!

news2024/11/16 1:31:30

文章目录

  • 什么是柔性数组?
  • 柔性数组的特点
  • 柔性数组的使用
  • 模拟实现柔性数组的功能
  • 柔性数组的优势

什么是柔性数组?

柔性数组这个概念相信大多数人博友都没有听说过,但是它确实存在。

在C99中,结构(结构体)的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。

比如:

struct S
{
	int n;
	int arr[];//柔性数组成员
};

或者是:

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

柔性数组的特点

一、结构中柔性数组成员前面必须至少有一个其他成员

比如,当你创建含有柔性数组成员的结构体时,结构体成员不能单单只有一个柔性数组成员:

struct Er
{
	int arr[];
};//error

除了柔性数组成员之外,结构体成员中应该至少再包含一个其他非柔性数组成员。

二、sizeof返回的这种结构大小不包括柔性数组的内存

所以,当你用sizeof来计算一个含有柔性数组成员的结构体大小时,计算出的结果不包括柔性数组成员在内。

比如:

#include <stdio.h>
struct S
{
	int n;
	int arr[];//柔性数组成员
};
int main()
{
	printf("%d\n", sizeof(struct S));
	//结果为4
	return 0;
}

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

比如,对于该结构体:

struct S
{
	int n;
	int arr[];//柔性数组成员
};

你想用他的柔性数组成员存放5个整型元素,那么你应该这样开辟空间:

#include <stdio.h>
#include <stdlib.h>
struct S
{
	int n;
	int arr[];//柔性数组成员
};
int main()
{
	//开辟
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
	return 0;
}

在这里插入图片描述

柔性数组的使用

我们可以利用柔性数组实现以下功能:

1.要求:用结构体将数字100和0~4五个数字进行封装。

2.要求改为:用结构体将数字100和0~9十个数字进行封装。

#include <stdio.h>
#include <stdlib.h>
struct S
{
	int n;
	int arr[];//柔性数组成员
};
int main()
{
	//开辟动态内存空间
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
	ps->n = 100;//将结构体中第一个元素赋值为100
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
		//将柔性数组中下标为i的元素赋值为i
	}
	//调整所开辟的动态内存空间的大小
	struct S* ptr = realloc(ps, sizeof(struct S) + 10 * sizeof(int));
	if (ptr != NULL)//开辟成功
	{
		ps = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
		//将柔性数组中下标为i的元素赋值为i
	}
	//释放开辟的动态内存空间
	free(ps);
	ps = NULL;
	return 0;
}

注意:柔性数组的使用与动态开辟内存的知识密不可分。

模拟实现柔性数组的功能

其实,我们若不借用柔性数组也能实现以上功能:

#include <stdio.h>
#include <stdlib.h>
struct S
{
	int n;
	int* arr;
};
int main()
{
	//开辟动态内存空间
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	ps->arr = (int*)malloc(5 * sizeof(int));
	ps->n = 100;//将结构体中第一个元素赋值为100
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
		//将柔性数组中下标为i的元素赋值为i
	}
	//调整所开辟的动态内存空间的大小
	int* ptr = (int*)realloc(ps->arr, 10 * sizeof(int));
	if (ptr != NULL)//开辟成功
	{
		ps->arr = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
		//将柔性数组中下标为i的元素赋值为i
	}
	//释放开辟的动态内存空间
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
	return 0;
}

柔性数组其实也就是结构体中的一个数组,准确来说,是一个空间大小可以自由变换的数组,那么我们在结构体中定义一个指针,使指针指向的空间可以自由变换(即指针指向的是动态开辟的内存),也就达到了这个效果。

注意: 这里释放动态内存空间时,需要先释放ps->arr指向的动态内存空间,再释放ps指向的动态内存空间。 如果我们先释放的是ps指向的动态内存空间,那么ps->arr所指向的空间就再也找不到了。

柔性数组的优势

一、方便内存释放

我们可以看到,用柔性数组解决这个问题的时候,我们只需要释放一次动态内存。而模拟实现柔性数组的时候,我们需要释放两次动态内存,最重要的是这两次释放内存的顺序还不能颠倒,如若颠倒了释放顺序就会导致有一块动态开辟的内存空间不能得到释放,最终导致内存泄漏。

二、有益于提高访问速度,也有益于减少内存碎片

其实第一种用柔性数组解决问题的时候,内存中开辟的空间是连续的:

在这里插入图片描述

而第二种模拟实现柔性数组的方法,在开辟内存的时候差不多是这样的:

在这里插入图片描述

看似在分配内存的时候连续还是不连续好像没什么影响,但是你是否知道有一个概念叫内存碎片

越多的不连续内存分配会产生越多的内存碎片,内存碎片越多,我们对内存的利用率就越低下,所以我们应该尽量避免不连续的内存分配。

其次,CPU在向存储器中提取数据时,会遵循局部性原理

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

所以,将相关联的数据存储在一起(即连续存储),会提高CPU的访问速度。

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

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

相关文章

【雕爷学编程】Arduino动手做(121)---夏普粉尘传感器模块

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

EMC学习笔记(十一)过孔

过孔 1.过孔模型1.1 过孔的数学模型1.2 对过孔模块的影响因素 2.过孔对信号传导与辐射发射影响2.2 过孔对阻抗控制的影响2.2 过孔数量对信号质量的影响 1.过孔模型 从过去设计的一些PCB板效果来看&#xff0c;过孔对于低频&#xff0c;低速信号的影响是很小的&#xff0c;但是…

Android 窗口实现原理

一、基本概念 1、窗口显示架构图 多窗口的核心原理其实就是分栈和设置栈边界2、Android的窗口分类 Android应用程序窗口,这个是最常见的&#xff08;拥有自己的WindowToken)譬如&#xff1a;Activity与Dialog Android应用程序子窗口&#xff08;必须依附到其他非子窗口才能存…

深度学习-第T11周——优化器对比实验

深度学习-第T11周——优化器对比实验 深度学习-第T11周——优化器对比实验一、前言二、我的环境三、前期工作1、导入数据集2、查看图片数目3、查看数据 四、数据预处理1、 加载数据1、设置图片格式2、划分训练集3、划分验证集4、查看标签 2、数据可视化3、检查数据4、配置数据集…

6月份读书学习好文记录

看看CHATGPT在最近几个月的发展趋势 https://blog.csdn.net/csdnnews/article/details/130878125?spm1000.2115.3001.5927 这是属于 AI 开发者的好时代&#xff0c;有什么理由不多去做一些尝试呢。 北大教授陈钟谈 AI 未来&#xff1a;逼近 AGI、融进元宇宙&#xff0c;开源…

06-浏览器渲染原理

什么是渲染&#xff1f; render&#xff0c;HTML字符串 --渲染--> 像素信息 URL地址是一个字符串&#xff0c;HTML、css、js都在里面 可以把渲染想象成一个函数&#xff0c;上代码&#xff1a; function render (html) {/* 第一行第二行*/return pixels; } 渲染时间点 …

【深入浅出 Spring Security(十二)】使用第三方(Github)授权登录

使用第三方&#xff08;Github&#xff09;授权登录 一、OAuth2 简单概述二、OAuth2 四种授权模式之授权码模式三、Github 授权登录准备工作创建 Spring Boot 项目Vue 测试代码测试效果 &#xff08;Github授权登录的具体操作在目录第三“章”&#xff09; 一、OAuth2 简单概述…

Spring Boot 优雅集成 Spring Security 5.7(安全框架)与 JWT(双令牌机制)

Spring Boot 集成 Spring Security &#xff08;安全框架&#xff09; 本章节将介绍 Spring Boot 集成 Spring Security 5.7&#xff08;安全框架&#xff09;。 &#x1f916; Spring Boot 2.x 实践案例&#xff08;代码仓库&#xff09; 介绍 Spring Security 是一个能够为基…

【CSDN创作纪念日】——博客小梦的“256”鸭~

博客小梦的创作纪念日&#x1f60e; 前言&#x1f64c;与CSDN的相遇浑水摸鱼的日常CSDN上的小小收获收获了 一群热爱编程&#xff0c;热爱创作的CSDN挚友创作上的小荣誉 憧憬未来 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭…

【Spring】— Spring MVC简单数据绑定(一)

目录 Spring MVC数据绑定1.数据绑定概述2.简单数据绑定2.1 绑定默认数据类型2.2 绑定简单数据类型 Spring MVC数据绑定 1.数据绑定概述 在执行程序时&#xff0c;Spring MVC根据客户端请求参数的不同将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中。这种将…

基于VMD-LSTM-IOWA-RBF的碳排放混合预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

第J3-1周:DenseNet算法 实现乳腺癌识别

目录 一、理论基础1.前言2.设计理念3.网络结构4.与其他算法效果对比 二、 前期准备1. 设置GPU2. 导入数据3. 划分数据集 三、搭建网络模型1. DenseLayer模块2. DenseBlock模块3. Transition模块4. 构建DenseNet5. 构建densenet121 四、 训练模型1. 编写训练函数2. 编写测试函数…

I/O多路复用+高性能网络模式

前言&#xff1a; 本篇文章将介绍客户端-服务端之间从最简单的Socket模型到I/O多路复用的模式演变过程&#xff0c;并介绍Reactor和Proactor两种高性能网络模式 文章内容摘自&#xff1a;小林Coding I/O多路复用高性能网络模式 . 传统Socket模型传统Socket模型的性能瓶颈多进程…

【Java基础学习打卡12】Java入门程序

目录 前言一、Java程序开发运行流程二、Java程序源代码编写三、Java程序源代码编译四、Java程序运行五、Java入门程序问题总结 前言 本文首先介绍Java程序开发运行基础流程&#xff0c;然后先进行程序源代码编写&#xff0c;然后对Java程序代码进行编译&#xff0c;最后要运行…

Python学习笔记(1)--环境搭建,开发工具PyCharm 安装及初步使用

传送门>B站黑马python入门教程 目录 1.Python环境安装搭建安装python基础包验证安装文件 2.hello world3.开发工具PyCharm 安装及初步使用安装基础设置 1.Python环境安装搭建 安装python基础包 首先,打开python 官网 https://www.python.org/ 下载windows版 下载后进行安装 …

Triton教程 --- 解耦后端和模型

Triton教程 — 解耦后端和模型 Triton系列教程: 快速开始利用Triton部署你自己的模型Triton架构模型仓库存储代理模型设置优化动态批处理速率限制器模型管理自定义算子 解耦后端和模型 Triton 可以支持为一个请求发送多个响应或为一个请求发送零个响应的后端和模型。 解耦的…

论文笔记--Prompt Consistency for Zero-Shot Task Generalization

论文笔记--Prompt Consistency for Zero-Shot Task Generalization 1. 文章简介2. 文章概括3 文章重点技术3.1 Prompt-based zero-shot task generalization3.2 Prompt Consistency Training3.3 如何防止遗忘和退化&#xff1f; 4. 文章亮点5. 原文传送门 1. 文章简介 标题&am…

【numpy模块上}——数据分析01

目录索引 介绍&#xff1a;用处与特点&#xff1a;构成&#xff1a;导包&#xff1a;创建数组&#xff1a; numpy常用方法&#xff1a;常用属性查看&#xff1a;*获取秩的大小&#xff1a;**获取数组形状&#xff1a;**获取元素个数&#xff1a;**获取元素类型&#xff1a;**获…

行为型设计模式10-解释器模式

&#x1f9d1;‍&#x1f4bb;作者&#xff1a;猫十二懿 ❤️‍&#x1f525;账号&#xff1a;CSDN 、掘金 、个人博客 、Github &#x1f389;公众号&#xff1a;猫十二懿 解释器模式 1、解释器模式介绍 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为设…

Kafka系列之:对源连接器的的Exactly-Once支持

Kafka系列之&#xff1a;对源连接器的的Exactly-Once支持 一、背景二、目标三、公共接口四、连接器 API 扩展五、REST API验证六、新指标七、计划变更八、任务计数记录九、重新平衡的准备十、源任务启动十一、领导者访问配置主题十二、用于隔离事务生产者的管理 API十三、解决了…