柔性数组(C语言)

文章目录

  • 1. 柔性数组的定义
  • 2. 柔性数组的特点
  • 3. 柔性数组的使用
  • 4. 柔性数组的好处

也许你从来没有听说过 柔性数组这个概念,但是它确实是存在的。柔性数组是C语言中一种特殊的结构,它允许在结构体的末尾定义一个可变长度的数组。

1. 柔性数组的定义

柔性数组是在C99中的一种玩法,它有两种定义方式,当其中一种定义方式,编译器编译不通过的时候,可以换另一种方式。
方式一:

typedef struct st_type
{int i;int a[0];//柔性数组成员
}type_a;

方式二:

typedef struct st_type
{int i;int a[];//C99的玩法是:int a[]; 没有指定数组长度
}type_a;

2. 柔性数组的特点

  1. 结构中的柔性数组成员前面必须至少一个其他成员。

这是因为柔性数组的大小是不确定的,所以编译器需要知道其他成员的大小和偏移量。

  1. sizeof 返回的这种结构大小不包括柔性数组的内存。

这是因为柔性数组的大小是可变的,因此 sizeof 返回的是结构体的固定部分的大小。

  1. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
struct S
{int a;char data[]; // 柔性数组成员
};struct S* str = malloc(sizeof(struct S) + 20); // 20是柔性数组的最大长度

在这里插入图片描述

3. 柔性数组的使用

以下代码,演示了柔性数组的用法:

#include <stdio.h>
#include <stdlib.h>struct S
{int n;int data[]; // 柔性数组成员
};int main() {// 创建包含柔性数组的结构体,并分配足够大的内存struct S* s = malloc(sizeof(struct S) + 20); // 20是柔性数组的最大长度if (s == NULL){perror("malloc");return 1;}s->n = 10;for (int i = 0; i < 5; ++i){(s->data)[i] = i;}for (int i = 0; i < 5; ++i){printf("%d ", (s->data)[i]);}free(s); // 释放内存s = NULL;return 0;
}

上面这段代码的意思是:我想分配一个不定长的数组,于是我有一个结构体,其中有两个成员,一个是n,一个是data。其实上述结构也可以通过指针运算和动态内存分配来实现。关于动态内存分配的知识,可以参考之前写的一篇文章:动态内存管理(malloc calloc realloc free)— C语言

#include <stdlib.h>
#include <string.h>// 定义结构体,包含柔性数组
struct S
{int len; // 柔性数组的长度int* data; // 柔性数组成员
};int main() 
{// 定义结构体指针struct S* s = (struct S*)malloc(sizeof(struct S));s->len = 5;// 给柔性数组的部分分配内存s->data = (int*)malloc(5 * sizeof(int)); // 假设柔性数组存储5个整数// 初始化柔性数组for (int i = 0; i < s->len; i++) {s->data[i] = i;}// 访问柔性数组的元素printf("柔性数组的内容: ");for (int i = 0; i < s->len; i++) {printf("%d ", s->data[i]);}printf("\n");// 释放内存free(s);s = NULL;return 0;
}

看到这里,你会说,把data声明成一个指针,然后为它再分配一下内存好像也可以也能完成我们预期的效果,那为什么还要搞出来一个0长数组呢?有啥意义呢?答案很简单,就是搞出来柔性数组,其实就是我们想给一个结构体内的数据分配一个连续的内存!

4. 柔性数组的好处

通过上面的介绍,我们知道柔性数组的存在就是想给一个结构体内的数据分配一个连续的内存!那这样做有什么好处呢?
第一个是,方便内存释放。

如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以我们不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

在使用柔性数组的时候,空间是一次性开辟好的,释放空间的时候只需要释放一次;而我们在模拟实现柔性数组的时候,是先给结构体开辟了空间,然后在结构体内进行了二次内存分配,因此在释放空间的时候也需要释放两次,然而释放的顺序也是有讲究的,要先释放data指向的空间,在释放结构体的空间,如果顺序反了,会导致data指向的空间无法被主动释放,会导致内存泄露。

在这里插入图片描述

第二个是,这样有利于访问速度。

连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)

  1. 含柔性数组的结构体在开辟空间的时候,是一次性开辟好的,在内存中是一片连续的空间。
    在这里插入图片描述

  2. 模拟含柔性数组的结构体在内存中是这样开辟空间的:
    在这里插入图片描述
    这种在内存中开辟空间的方式,可能会导致内存碎片的问题。内存碎片是指未被使用的小块内存,它们可能夹在已分配内存的中间,导致内存浪费。
    在这里插入图片描述
    而数据在内存中连续存储时,碎片化的可能性较低,因为数据被一起分配并存储。

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !!!
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数学建模——平稳时间序列分析方法

目录 1、平稳性的Daniel检验 &#xff08;1&#xff09;Spearman相关系数假设检验 &#xff08;2&#xff09;时间序列平稳性的Danniel假设检验 案例 【模型分析】 1、原始数据at的平稳性检验 2、一阶差分序列的平稳性检验 3、二阶差分序列的平稳性检验 4、建立AR&#…

ChatGPT生产力|实用指令(prompt)

GPT已经成为一个不可或缺的科研生产力了&#xff0c;但是大多数人只知晓采用直接提问、持续追问以及细节展开的方式来查阅相关资料&#xff0c;本文侧重于探讨“限定场景限定角色限定主题”、“可持续追问细节展开”等多种方式来获取更多信息&#xff0c;帮人们解决更多问题。 …

二叉树的层序遍历

利用队列的先进先出&#xff0c;把根的节点的指针存到队列中&#xff0c;然后再出队列&#xff0c;在出队列时再把他的左右子树的节点指针带进去&#xff0c;循环到队列为空&#xff08;树也就遍历完了&#xff09; void LevelOrder(BTNode* root)//层序遍历 {Queue L;//定义…

Docker Compose命令讲解+文件编写

docker compose的用处是对 Docker 容器集群的快速编排。&#xff08;源码&#xff09; 一个 Dockerfile 可以定义一个单独的应用容器。但我们经常碰到需要多个容器相互配合来完成某项任务的情况&#xff08;如实现一个 Web 项目&#xff0c;需要服务器、数据库、redis等&#…

Unity角色或摄像机移动和旋转的控制脚本

该脚本挂载到需要被移动、旋转控制的物体身上&#xff0c;也可以之间挂在到摄像机上&#xff01; 挂载到摄像机上可以实现第一人称视角控制&#xff01; 挂载到物体身上&#xff0c;配合摄像机跟踪脚本可以实现&#xff0c;第三人称视角控制&#xff01; 第一人称视角 将角…

【微服务】微服务初步认识 - 微服务技术如何学习 · 认识微服务架构

微服务&#xff08;1&#xff09; 文章目录 【微服务】&#xff08;1&#xff09;1. 微服务相关技术栈2. 微服务学习路线3. 认识微服务架构3.1 单体架构3.2 分布式架构3.3 微服务(架构)3.4 微服务(架构)治理落实相关的SpringCloud、SpringCloudAlibaba和阿里巴巴的Dubbo提供的服…

【MySql】6- 实践篇(四)

文章目录 1. 为何SQL语句逻辑相同&#xff0c;性能却差异巨大1.1 性能差异大的SQL语句问题1.1.1 案例一:条件字段函数操作1.1.2 案例二:隐式类型转换1.1.3 案例三:隐式字符编码转换 2. 为何只查询一行的SQL执行很慢2.1 场景一:查询长时间不返回2.1.1 等MDL锁2.1.2 等 flush2.1.…

TCP/IP(八)TCP的连接管理(五)四次握手

一 tcp连接断开 每一个TCP报文的超时重传都由一个特定的内核参数来控制 ① 四次握手的过程 遗留&#xff1a; 谁先发送FIN包,一定是client吗? --> upload和download补充&#xff1a; 主动和被动断开连接的场景 "四次握手过程描述" F --> FIN --> F…

车载电子电器架构 —— 国产基础软件现在与未来

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

飞书应用机器人文件上传

背景&#xff1a; 接上一篇 flask_apscheduler实现定时推送飞书消息&#xff0c;当检查出的异常结果比较多的时候&#xff0c;群里会有很多推送消息&#xff0c;一条条检查工作量会比较大&#xff0c;且容易出现遗漏。   现在需要将定时任务执行的结果记录到文件&#xff0c;…

使用EasyDarwin+ffmpeg+EasyPlayerPro完成rtsp的推流操作和拉流操作

本文分享在做视频类测试过程中所用到的工具EasyDarwinffmpegEasyPlayerPro 首先说一下EasyDarwin,简单来讲&#xff0c;它就是个推流和拉流及系统消耗的监测软件&#xff0c;具体使用方法我会写在下方。 EasyDarwin 1、解压下载好的EasyDarwin压缩包&#xff0c;并找到EasyD…

后端:推荐 2 个 .NET 操作的 Redis 客户端类库

目录 Redis特点 Redis场景 1. StackExchange.Redis 2. FreeRedis &#x1f680; 快速入门 &#x1f3a3; Master-Slave (读写分离) &#x1f4bb; Pipeline (管道)示例 &#x1f30c; Redis Cluster (集群) Redis &#xff0c;是一个高性能(NOSQL)的key-value数据库,Re…

【TensorFlow2 之014】在 TF 2.0 中实现 LeNet-5

一、说明 在这篇文章中&#xff0c;我们将展示如何在 TensorFlow 中实现像 \(LeNet-5\) 这样的基础卷积神经网络。LeNet-5 架构由 Yann LeCun 于 1998 年发明&#xff0c;是第一个卷积神经网络。 数据黑客变种rs 深度学习 机器学习 TensorFlow 2020 年 2 月 29 日 | 0 …

GB28181平台简介

产品简介 LiveMedia视频中间件是支持部署到本地服务器或者云服务器的纯软件服务&#xff0c;也提供服务器、GPU一体机全包服务&#xff0c;提供视频设备管理、无插件、跨平台的实时视频、历史回放、语音对讲、设备控制等基础功能&#xff0c;支持视频协议有海康、大华私有协议…

竞赛 深度学习LSTM新冠数据预测

文章目录 0 前言1 课题简介2 预测算法2.1 Logistic回归模型2.2 基于动力学SEIR模型改进的SEITR模型2.3 LSTM神经网络模型 3 预测效果3.1 Logistic回归模型3.2 SEITR模型3.3 LSTM神经网络模型 4 结论5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 …

Idea创建springboot工程的时候,发现pom文件没有带<parent>标签

今天创建springboot工程&#xff0c;加载maven的时候报错&#xff1a; 这个问题以前遇到过&#xff0c;这是因为 mysql-connector-j 没有带版本号的原因&#xff0c;但是springboot的依赖的版本号不是都统一交给spring-boot-starter-parent管理了吗&#xff0c;为什么还会报错&…

华为云云耀云服务器L实例评测|华为云耀云服务器L实例评测用例(五)

六、华为云耀云服务器L实例评测用例&#xff1a; “兵马未动&#xff0c;粮草先行”&#xff0c;随着企业业务的快速发展&#xff0c;服务器在数字化建设体系至关重要&#xff0c;为了保证服务器的稳定性、可靠性&#xff0c;需要对服务器进行评测&#xff0c;以确保服务器能够…

kafka详解(三)

2.2 Kafka命令行操作 2.2.1 主题命令行操作 1&#xff09;查看操作主题命令参数 [aahadoop102 kafka]$ bin/kafka-topics.sh2&#xff09;查看当前服务器中的所有topic (配置了环境变量不需要写bin/) [aahadoop102 kafka]$ bin/kafka-topics.sh --bootstrap-server hadoop10…

Linux gcc和make学习

文章目录 GCCgcc的安装gcc的工作流程 makefilemakefile的规则工作原理自动生成makefile的变量自定义变量预定义变量自动变量 模式匹配函数wildcard函数patsubst函数 伪声明 GCC gcc全程是&#xff08;GNU compiler collection CNU编译器套件&#xff09;&#xff0c;是由GNU开发…

想要精通算法和SQL的成长之路 - 分割数组的最大值

想要精通算法和SQL的成长之路 - 分割数组的最大值 前言一. 分割数组的最大值1.1 二分法 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 分割数组的最大值 原题链接 首先面对这个题目&#xff0c;我们可以捕获几个关键词&#xff1a; 非负整数。非空连续子数组。 那么我…