目录摘要一语法规则1书写规则2柔性数组特点二优点1柔性数组的使用2指针替换柔性数组3柔性数组的优点摘要本博客旨在介绍何为柔性数组以及其的书写语法规则最后对比指针实现的方式来体现柔性数组的优点.....一语法规则1书写规则也许你从来没有听说过柔性数组flexible array这个概念但是它确实是存在的在C99 中结构中的最后⼀个元素允许是未知大小的数组这就叫做『柔性数组』成员。所以柔性数组是结构体的一个成员变量书写规则结构中的柔性数组成员前面必须至少还存在一个其他成员变量struct st_ty1pe { int i; int a[0];//柔性数组成员 };若上述写法编译器报错⽆法编译则可以改成下面写法(去掉[ ]中数字)struct st_type { int i; int a[];//柔性数组成员 };2柔性数组特点柔性数组的特点•sizeof 返回的这种结构大小不包括柔性数组的内存。•用 malloc() 为含柔性数组成员的结构体动态分配内存时分配的大小应大于结构体本身的大小以容纳柔性数组的预期长度。typedef struct st_type { int i; int a[0];//柔性数组成员 }type_a; int main() { printf(%d\n, sizeof(type_a));//输出的是4 return 0; }解释柔性数组之所以叫柔性就是因为其的大小是可变的所以sizeof当然无法精确计算出柔性数组的大小只能计算其他结构体成员变量的大小此外柔性数组要想发挥出自己的作用是必须和内存函数互相结合的如果不用malloc、calloc、free等内存函数柔性数组就毫无用处甚至会导致程序崩溃⚠️错误的用法完全没有用内存函数配合struct FlexArray { int len; int data[]; // 柔性数组 }; int main() { struct FlexArray arr; // 错误如何为 data 分配内存 arr.data[0] 10; // 危险data 没有实际内存空间 return 0; }解释sizeof(struct FlexArray)只包含int len的大小。data没有空间。访问arr.data[0]会写入未知内存导致段错误总结没有内存函数柔性数组就没有栖身的内存空间只是一个无法使用的幽灵字段只有通过malloc/realloc一次性分配头部数据区的连续内存柔性数组才能真正成为一个长度可变、管理方便、缓存友好的动态数组。所以要想给柔性数组开辟空间必须结合内存函数二优点1柔性数组的使用代码逻辑利用结构体中的柔性数组成员结合malloc和realloc实现一个可动态扩容的数组最开始柔性数组存放1 2 3 4 5然后扩容再存放6,7,8,9,10最后打印观看~#include stdio.h #include stdlib.h // 定义结构体 S struct S { int n; // 普通成员变量 int arr[]; // 柔性数组成员不占结构体大小用于后续动态扩展 }; int main() { // 1. 动态分配内存 // 这里分配了结构体本身的大小 20字节足够存5个int struct S* ps (struct S*)malloc(sizeof(struct S) 20); if (ps NULL) return 1; // 检查分配是否成功 ps-n 100; // 初始化普通成员 int i 0; // 2. 使用初始分配的空间前5个元素 for (i 0; i 5; i) { ps-arr[i] i 1; // 赋值 1, 2, 3, 4, 5 } // 3. 扩容内存 // 原空间不够用了需要再加40字节总共能存10个int // 注意这里总大小 结构体大小 20(旧) 40(新加) struct S* tmp (struct S*)realloc(ps, sizeof(struct S) 40); // 检查 realloc 是否成功 if (tmp NULL) { perror(realloc); return 1; } // 更新指针指向新内存块 ps tmp; // 4. 使用扩容后的空间后5个元素 for (i 5; i 10; i) { ps-arr[i] i 1; // 赋值 6, 7, 8, 9, 10 } // 5. 输出结果 // 验证数据是否连续且正确 for (i 0; i 10; i) { printf(%d , ps-arr[i]); } // 6. 释放内存 free(ps); ps NULL; return 0; }解释malloc申请空间的时候多申请一点结构体内被常规的成员变量占据空间之后剩余的空间都属于柔性数组可以直接以下标的形式进行使用空间当柔性数组需要更大空间时则增容即可最后free释放结构体指针则会将整个结构体变量包括其中的柔性数组一起释放~2指针替换柔性数组我们也可以用指针来替换柔性数组虽然实现方式差不多但是相比柔性数组而言指针的方式更繁琐也更容易出问题没有柔性数组省事指针实现如下#include stdio.h #include stdlib.h // 修改后的结构体使用指针代替柔性数组 struct S_Ptr { int n; int* arr; // 这是一个指针通常占 4 或 8 字节 }; int main() { // 1. 分配结构体本身的内存 struct S_Ptr* ps (struct S_Ptr*)malloc(sizeof(struct S_Ptr)); if (ps NULL) return 1; ps-n 100; // 2. 单独为 arr 分配内存 (模拟原来的 20 字节) ps-arr (int*)malloc(20); if (ps-arr NULL) return 1; int i 0; for (i 0; i 5; i) { ps-arr[i] i 1; } // 3. 扩容 arr // 必须单独对 ps-arr 进行 realloc而不是对 ps 进行 realloc int* tmp (int*)realloc(ps-arr, 40); // 注意这里逻辑变成了总大小40还是增量40取决于需求这里假设扩容到40 if (tmp NULL) { perror(realloc); return 1; } ps-arr tmp; for (i 5; i 10; i) { ps-arr[i] i 1; } // 4. 输出 for (i 0; i 10; i) { printf(%d , ps-arr[i]); } // 5. 释放内存 (必须释放两次) free(ps-arr); // 先释放内部数组 free(ps); // 再释放结构体 return 0; }3柔性数组的优点通过上面的代码实现我们可以清晰地看到柔性数组int arr[]相对于指针int *arr的有三方面的核心优势①内存分配次数与效率主要优势指针方法需要2 次malloc。一次分配结构体。一次分配数组内存。频繁的内存分配会导致内存碎片。柔性数组只需要1 次malloc。结构体和数组数据在内存中是连续存储的。减少了系统调用次数效率更高。②内存释放的便捷性指针方法需要2 次free。必须先free(ps-arr)再free(ps)。(顺序颠倒会出错导致找不到arr)如果忘记释放其中任何一个都会造成内存泄漏。柔性数组只需要1 次free。free(ps)会一次性释放整块内存管理更简单不易出错。③访问速度与局部性指针方法ps指向的内存和ps-arr指向的内存在物理地址上可能相隔很远不连续。这会导致 CPU 缓存命中率降低。柔性数组数据紧跟在结构体后面具有极好的局部性原理优势访问速度通常更快。总结虽然使用int *arr也能实现类似的功能但柔性数组提供了一种更优雅、更高效的方式来管理“头结构 变长数据”的场景例如网络数据包、动态字符串等。它通过一次性分配连续内存解决了内存碎片问题并简化了内存管理逻辑。 [ 作者 ] shylyly [ 首次发布 ] 2026.5.17❌ [ 最新修改 ] 2026.10.19 [ 声明 ] 由于笔者水平有限文中难免有疏漏或不妥之处还望读者不吝赐教。
阅读完成 · 觉得有帮助?