【C 语言内功修炼】柔性数组的奥秘
1. 柔性数组的定义
也许你从来没有听说过 柔性数组(flexible array)这个概念,但是它确实是存在的。
C99 中,结构中的最后一个元素允许是 未知大小 的数组,这就叫做『柔性数组』成员。
例如:
上面这种写法,有些编译器会报错无法编译;
可以改成:
2. 柔性数组的特点
(1)结构中的柔性数组成员前面 必须至少一个其他成员。
(2)sizeof 返回的这种结构大小 不包括柔性数组的内存。
(3)包含柔性数组成员的结构用 malloc 函数进行内存的动态分配,并且分配的内存应该 大于 结构的大小,以适应柔性数组的预期大小。
📝 代码示例
🌟 运行结果
可以看到使用 sizeof 求结构体的大小,是不包括 柔性数组的内存;
3. 柔性数组的使用
假设对包含柔性数组的结构体来开辟空间
📝 代码示例
sizeof(struct S2)
开辟了 4 个字节,是给 n 的;后面的 40 是给 arr 开辟的;
现在我们来使用开辟的这 44 Byte 的空间
🌟 运行结果
假设这块儿空间不够的话,还可以用 realloc 进行增容👇
现在就能理解:结构体的最后一位成员能进行变长或变短的可能性
4. 柔性数组的优势
这时候,有人可能会想到:我在结构体定义一个指针,对指针指向的空间进行动态开辟不就完事了吗?
📝 代码示例
我们来看一下这段代码的内存布局:
首先 malloc 在 堆区 上申请了一块儿空间,里面有整型 n 和指针 arr,指针 arr 使用 malloc 开辟的空间也在 堆区 上;
那么再对比一下 柔性数组 的布局图,到底应该用哪一种呢?
其实 柔性数组 的方案聪设计上来说更 优 一些,虽然使用起来比较陌生;
为什么呢?
首先包含 柔性数组成员的结构体 如果用 malloc 来维护空间的话,只需要用一次 malloc 就可以把 n 和 arr 都开辟出来了,用 free 释放的话,也只需要一次就够了;
而对于 指针 的话,malloc 和 free 都使用了两次,开辟和释放的次数多,容易出错;
还有就是 malloc 开辟的次数过多,容易导致 内存碎片的问题
假设有下面这样一块内存空间,如果我开辟了一次,就使用了一整块;
如果我开辟两次的话,空间与空间就会形成缝隙;
如果我多次在内存中开辟的话,空间与空间就会形成更多的缝隙;
这种缝隙如果不利用的话,就被称为 内存碎片,你开辟的次数越多,那么内存碎片就越多,内存碎片的利用率不高的话,那么内存的利用率也会不高;
总结:
(1)优点一:方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。
用户调用 free 可以释放结构体,但是用户并不知道这个结构体内的成员也需要 free,所以你不能指望用户来发现这个事。
如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次 free 就可以把所有的内存也给释放掉。
(2)优点二:有利于访问速度
连续的内存有益于提高访问速度,也有益于减少内存碎片。
版权声明: 本文为 InfoQ 作者【Albert Edison】的原创文章。
原文链接:【http://xie.infoq.cn/article/6f1da2c291b1fb5f361dcb87d】。文章转载请联系作者。
评论