谈柔性数组在结构体中的作用

简介: 可能你从来没有听过柔性数组这个概念,但是它确实是存在的。在C99中,结构体中最后一个成员允许是大小未知的数组,这就叫做【柔性数组】成员。

该文章将介绍柔性数组是什么,有什么作用以及如何使用柔性数组,帮助你更好的理解结构体中的细节。


1.柔性数组


可能你从来没有听过柔性数组这个概念,但是它确实是存在的。


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


比如:


struct Stu
{
  int n;
  char c;
  int arr[];这个就是柔性数组成员
};


有些编译器会报错无法编译可以改成


struct Stu
{
  int n;
  char c;
  int arr[0];
};


2.柔性数组的特点:


  • 结构体中的柔性数组成员前面必须至少要有一个其他成员。
  • sizeof返回的这个结构体大小不包含柔性数组的内存
  • 包含柔性数组的结构体要用malloc()函数进行内存的动态分配,并且分配的大小应该大于结构体的大小,以适应柔性数组的预期大小


例如:


struct Stu
{
  int n;
  int arr[];柔性数组
};
int main()
{
  printf("%d", sizeof(struct Stu));
  //这个结构体大小不包含柔性数组的内存,相当于这个给结构体中只有int n;成员,大小也就是4
  return 0;
}


3.柔性数组的使用


struct S
{
  int a;
  char arr[];//不设置大小--柔性数组,结构体中最后一个,前面至少要求一个成员
  //这个结构体大小是除柔性数组以外的成员计算得到大小
  //柔性数组的空间使用需要malloc开辟
};
int main()
{//使用malloc函数给结构体变量开辟内存,sizeof(struct S)是为结构体中除柔性数组外成员分配空间,而后面的则是为柔性数组开辟空间
  //最后都把开辟的空间转换为结构体类型,用结构体指针来接收
  struct S*p=(struct S*)malloc(sizeof(struct S) + 10 * sizeof(char));
  if (p == NULL)//判断一下
  {
    perror("malloc");
    return 1;
  }
  p->a = 100;//访问变量
  int i = 0;
  for (i = 0; i < 10; i++)//给数组分配了10个整形的空间
  {
    p->arr[i] = '6';//使用这块空间
  }
  for (i = 0; i < 10; i++)
  {
    printf("%c ", p->arr[i]);//打印出来
  }
  //想要给柔性数组增容 -----p指向的是原先的空间大小的指针,要想开辟更大的空间,在原基础上加就可以了
  struct S*ptr=(struct S*)realloc(p,sizeof(struct S) + 20 * sizeof(char));
  if (ptr != NULL)//还是要判断一下
  {
    p = ptr;
  }
  else
  {
    perror("realloc");
    return 1;
  }
  //释放
  free(p);
  p = NULL;
  return 0;
}//


这样的柔性数组arr相当于先获得10个整形大小的连续空间,后来又增容到20个整形的连续空间。


4.柔性数组的优势


上面的代码就是将结构体中一个数组的大小可以随意变化。也可以这样写:


struct S
{
  int a;
  int* arr;//成员是指针不是柔性数组
  //用malloc使这个指针指向一块大小可以是自己改变的
};
int main()
{
  struct S *p = (struct S*)malloc(sizeof(struct S));//给结构体变量申请一块空间,用结构体指针接收
  p->a = 100;//访问结构体成员
  p->arr = (int*)malloc(10 * sizeof(int));//给指针arr指向的地方申请10个整形空间
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    p->arr[i] = '6';//使用malloc为arr开辟的空间
  }
  for (i = 0; i < 10; i++)
  {
    printf("%c ", p->arr[i]);
  }
  //增容
  int *ptr=(int*)realloc(p->arr, 20 * sizeof(int));
  if (ptr == NULL)//判断一下
  {
    perror("realloc");
    return 1;
  }
  free(p->arr);//必须先释放arr开辟的空间再释放p开辟的空间,从里到外释放
  p->arr = NULL;
  free(p);
  p = NULL;
  return 0;
}


上面代码1和代码2都可以完成相同的功能,但代码1的实现有两个好处:


第一个好处是:方便内存释放


可以明显的看出来代码2比代码1,多开辟空间也多释放空间。


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


第二个好处是:有利于提高访问速度


频繁的开辟空间会形成大量的内存碎片而连续的内存有益于提高访问速度,减少内存碎片。


如果想了解更多的知识这里有陈皓大佬的一篇文章里面也是讲的柔性数组,供参考

C语言结构体里的成员数组和指针

相关文章
|
存储 缓存 算法
淘宝购物车扩容与性能优化(下)
淘宝购物车扩容与性能优化(下)
444 3
|
机器学习/深度学习 自然语言处理 程序员
NLP:Transformer的简介(优缺点)、架构详解、案例应用之详细攻略
NLP:Transformer的简介(优缺点)、架构详解、案例应用之详细攻略
NLP:Transformer的简介(优缺点)、架构详解、案例应用之详细攻略
|
3月前
|
Ubuntu Unix Linux
详细指导:Ubuntu镜像下载及系统安装全过程
安装Ubuntu系统并配置引导文件后,您已经成功地将Ubuntu添加到了您的计算机的多重启动选项中。至此,整个安装与配置过程已经全部完成。
|
5月前
|
运维 监控 Oracle
说一说死锁的 4 种排查工具
我是下假 期待与你的下一次相遇 ~
181 1
|
机器学习/深度学习 传感器 自动驾驶
未来之路:大模型技术在自动驾驶的应用与影响
本文深入分析了大模型技术在自动驾驶领域的应用和影响,万字长文,慢慢观看~ 文中首先概述了大模型技术的发展历程,自动驾驶模型的迭代路径,以及大模型在自动驾驶行业中的作用。 接着,详细介绍了大模型的基本定义、基础功能和关键技术,特别是Transformer注意力机制和预训练-微调范式。 文章还介绍了大模型在任务适配性、模型变革和应用前景方面的潜力。 在自动驾驶技术的部分,详细回顾了从CNN到RNN、GAN,再到BEV和Transformer结合的技术迭代路径,以及占用网络模型的应用。 最后,文章重点讨论了大模型如何在自动驾驶的感知、预测和决策层面提供赋能,突出了其在该领域的重要性和影响力。
2349 56
|
存储 调度 块存储
十二年磨一剑:三代架构演进,打造高性能、低成本的块存储!
上周,全球计算机存储顶会USENIX FAST 2024 在美国加州圣克拉拉召开,继去年获得国内首个FAST最佳论文奖后,凭借在分布式块存储上的创新,阿里云新作再次斩获FAST大会最佳论文奖。这也是国内唯一一家连续两年获得FAST最佳论文奖的科技公司。
106800 105
|
Kubernetes 负载均衡 安全
【技术揭秘】阿里云容器服务Ingress高级玩法:如何轻松实现客户端原始IP透传,提升应用安全性与用户体验!
【8月更文挑战第17天】本文介绍如何在阿里云容器服务中配置Ingress以透传客户端原始IP地址。通过Ingress可实现HTTP负载均衡等功能。需在Ingress定义文件中添加特定注解,如`nginx.ingress.kubernetes.io/real-ip-header: X-Real-IP`。创建并应用Ingress配置后,后端服务可通过读取`X-Real-IP`头获取真实IP。此举有助于安全审计及流量分析。
557 2
|
SQL 缓存 关系型数据库
MySQL主从同步如何操作?
随着业务增长,单台MySQL服务器难以应对高并发访问和潜在的故障风险。主从同步(Master-Slave)通过读写分离提升数据库处理能力,具备多项优势:读写分离减轻主数据库压力、支持一主多从增强扩展性与高可用性、以及数据备份确保容灾恢复。MySQL利用binlog实现主从数据同步,记录所有写操作,不包含查询。binlog有三种格式:Statement(基于SQL语句)、Row(基于行更改)、Mixed(结合前两者优点)。主从复制涉及三个关键线程:主库的binlog dump thread和从库的I/O thread与SQL thread。
530 0
MySQL主从同步如何操作?
|
关系型数据库 MySQL 数据库
MySQL SELECT查询实战:练习题精选,提升你的数据库查询技能
MySQL SELECT查询实战:练习题精选,提升你的数据库查询技能
|
运维 数据安全/隐私保护 网络协议
【网络建设与运维】2024年河北省职业院校技能大赛中职组“网络建设与运维”赛项例题(十)
【网络建设与运维】2024年河北省职业院校技能大赛中职组“网络建设与运维”赛项例题(十)
【网络建设与运维】2024年河北省职业院校技能大赛中职组“网络建设与运维”赛项例题(十)