今天看到一个有趣的知识点,在这里分享下。
可以直接 阅读原文

示例代码:

#include<stdio.h>
struct Test0
{int a;int b;char *c;
};
struct Test1
{int a;int b;char c[];
};
int main(void)
{printf("sizeof(struct Test0) = %zd\n",sizeof(struct Test0));printf("sizeof(struct Test1) = %zd\n",sizeof(struct Test1));return 0;
}

在64位机器上编译运行结果:

16
8

是不是感觉到不可思议。往下看。

对于Test0的结果是16,通常没有什么疑问,毕竟4(int)+4(int)+8(指针)= 16,但是对于后者的结构体占用空间为8字节,有的读者可能会有疑问。

柔性数组(flexible array)

实际上这是在C99中引入的柔性数组的特性。即结构体的最后一个成员,可以不完整类型(一种缺乏足够的信息去描述一个完整对象的类型)的数组,但它使得整个结构体的大小就像没有这个成员一样。但是呢,当用结构体通过这个名字访问这个成员时,就像访问一个普通数组成员一样。

如果数组最终一个元素都没有的话,那么访问这个数组将会是未定义行为了。

有什么好处?

内存申请和释放

假设分别使用两种类型的结构体,存储16字节的字符数据,需要申请内存。对于struct Test0:

strcut Test0 *t0 = malloc(sizeof(struct Test0));//为结构体申请内存
t0->c = malloc(sizeof(char) * 16);//为成员指向的数据申请内存

而对于struct Test1:

strcut Test1 *t1 = malloc(sizeof(struct Test1) + sizeof(char) * 16);

看出区别了吗?前者需要两次内存申请,而后者只需要一次。前者地址不连续(两次malloc),后者地址连续。而你访问成员c的时候,只需要下面这样就可以:

t1->c,和普通成员无异。

要判断它们的地址是否连续也非常简单,只需要分别打印b和c的地址就可以了。

和内存释放类似,前面需要单独释放成员c申请的内存,而后者可以一起释放。

数据拷贝

正由于前面的差别,导致数据拷贝时,更有区别。
对于struct Test0:

//memcpy(t0copy,t0,sizeof(struct Test0));//不可,这样直接t0copy的c和t0的c指向同一片内存区域。
t0copy.a = t0.a;
t0copy.b = t0.b;
memcpy(t0copy.c,t0.c,sizeof(char)*16);

这里无法一次拷贝,因为它的成员c是一个指针类型,我们需要的是一份完整拷贝,因此必须拷贝它指向的内存。

但是对于struct Test1:

memcpy(t0copy,t0,sizeof(strcut Test1) + sizeof(char) * 16);

在这里,由于柔性数组的内存,它的数据内容和结构体数据成员的地址是连续的,因此可以直接拷贝。

减少内存碎片

由于结构体的柔性数组和结构体成员的地址是连续的,即可一同申请内存,因此更大程度地避免了内存碎片。另外由于该成员本身不占结构体空间,因此,整体而言,比普通的数组成员占用空间要会稍微小点。

图解差别

c++ 之 柔性数组相关推荐

  1. 结构体中最后一个成员为[0]或[1]长度数组(柔性数组成员)的用法

    结构体中最后一个成员为[0]长度数组的用法:这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势:(1).不需要初始化,数组名直接就是所在的偏移:(2).不占任何空间,指针需要占 ...

  2. 动态内存分配与柔性数组

    什么时动态内存分配 一般我们写程序都是在栈区分配空间,如果我们想根据需求想随时存放随时释放数据,堆区可以实现根据需求想系统申请所需大小的空间. 建立内存的动态分配 内存的动态分配是通过系统提供的函数来 ...

  3. C/C++ 中的0长数组(柔性数组)

    C/C++ 中的0长数组(柔性数组) 在标准C和C++中0长数组如charArray[0]是不允许使用的,因为这从语义逻辑上看,是完全没有意义的. 但是,GUN中却允许使用,而且,很多时候,应用在了变 ...

  4. c99变长数组_你学过数组,那你知道柔性数组吗?

    1 引言 定长数组包 在平时的开发中,缓冲区数据收发时,如果采用缓冲区定长包,假定大小是 1k,MAX_LENGTH 为 1024.结构体如下: // 定长缓冲区struct max_buffer{ ...

  5. 写给过去的自己-No.2-数据结构篇-初尝柔性数组

    过去你的自己,你好.     照顾宝宝,写完第一篇就没什么时间,既然上次讲的就是数据结构,这次也讲点相关的.     其实接触柔性数组也是个比较奇妙的过程,你以后会遇到个学长,毕业后从事软件行业,在中 ...

  6. 3----结构体中使用柔性数组

    结构体中最后一个成员为[0]长度数组的用法:这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势:(1).不需要初始化,数组名直接就是所在的偏移:(2).不占任何空间,指针需要占 ...

  7. 2-结构体的最后一个成员的定义-C语言中的柔性数组-

    深入浅出C语言中的柔性数组 在日常的编程中,有时候需要在结构体中存放一个长度动态的字符串,一般的做法,是在结构体中定义一个指针成员,这个指针成员指向该字符串所在的动态内存空间,例如: [cpp] vi ...

  8. c判断char数组是否为空_你学过数组,那你知道柔性数组吗?

    1 引言 定长数组包 在平时的开发中,缓冲区数据收发时,如果采用缓冲区定长包,假定大小是 1k,MAX_LENGTH 为 1024.结构体如下: // 定长缓冲区struct max_buffer{ ...

  9. (四)C语言柔性数组、指针赋值

    一.柔性数组 今天看了公司的代码,发现一个很奇怪的问题,后来自己写了类似代码,我先把代码贴出来吧. #include<stdio.h> #include<string.h> # ...

  10. C语言程序设计 | 动态内存管理:动态内存函数介绍,常见的动态内存错误,柔性数组

    动态内存管理目录: 动态内存函数的介绍 常见的动态内存函数的错误 柔性数组 为什么会有动态内存管理呢 我们在日常使用中,创建一个数组,一个变量时都会开辟空间 如: int a; //在栈上开辟一个四字 ...

最新文章

  1. 简单ThreadPool实现
  2. 【教程】新手如何制作简单MAD和AMV,学不会那都是时辰
  3. 秒懂 CountDownLatch 与 CyclicBarrier 使用场景
  4. 收藏 | 2015年度大数据应用经典案例Top100
  5. Django+Echarts画图实例
  6. 限流算法(记录cyc大佬的专栏)
  7. 由对称性知定点一定在x轴上_线上优秀教学案例(九)|计算机科学与工程学院刘钊:“延期不延教”之“1+X课堂”...
  8. 两个问题,关于XP进程优化及SVSP虚拟存储平台
  9. python教程循环语句_Python教程:关于Python 循环语句
  10. 【英语学习】【医学】有机化学 - 烷的命名
  11. Hbase 中文参考指南 3.0 校对活动发车了~
  12. 嵌入式开发环境搭建:开发板tftp下载环境搭建
  13. 第十九:如何在Windows下把Allure2与Jenkins的集成生成自定义的测试报告(重点超详细)
  14. python pandas series_Python Pandas 系列Series
  15. bzoj2631:tree
  16. 利用python炒股talib_Python 通过 TALib 包构建股票自动技术分析
  17. Flutter 实现吹气球动画
  18. 如何在R里面安装做gif动图的gganimate包
  19. 终于稀里糊涂完成了模仿天猫整站ssm
  20. android 浏览器支持java,Android浏览器访问java web的方法

热门文章

  1. springboot集成LTS
  2. 相似度算法——Levenshtein(编辑距离)
  3. 程序员:1行代码修改开机密码、1张图片让电脑死机
  4. 欧冠 十六强 罗马 VS 波尔图
  5. 关于Ubuntu ssh远程连接报错和无法root登录的解决方法
  6. linux主题文件夹,linux精彩桌面 gnome桌面主题安装实例_linux教程
  7. mysql的rand()随机数函数
  8. 游戏制作之路(55)模拟风
  9. 嵌入式lua之多线程操作移植四 lua线程结束垃圾回收
  10. VC GetDlgItem