【C语言】《柔性数组详解:概念、特性、代码演示以及和指针方案对比》

发布时间:2026/7/28 5:21:52

【C语言】《柔性数组详解:概念、特性、代码演示以及和指针方案对比》 柔性数组一.柔性数组的概念柔性数组Flexible Array也叫可变长数组。普通数组的长度在编译时就固定了而柔性数组的长度在运行时才确定。在C99标准中定义结构体时允许最后一个成员是未指定大小的数组例如int arr[]这个数组本身不占用结构体的空间它的实际大小可以在程序运行时根据需求动态分配。struct st_type { int i; int a[0];//柔性数组成员 }; //有些编译器会报错⽆法编译可以改成 struct st_type { int i; int a[];//柔性数组成员 };C99 中结构中的最后⼀个元素允许是未知⼤⼩的数组这就叫做柔性数组成员。二.柔性数组的特点柔性数组的特点结构中的柔性数组成员前⾯必须⾄少⼀个其他成员。sizeof 返回的这种结构⼤⼩不包括柔性数组的内存。包含柔性数组成员的结构⽤malloc ()函数进⾏内存的动态分配并且分配的内存应该⼤于结构的⼤⼩以适应柔性数组的预期⼤⼩。特点一代码示例如下struct S { int n; // 前面的成员 int arr[0]; // 柔性数组 };柔性数组必须在最后且前面得有至少一个成员。光一个柔性数组没法用。特点二代码示例如下#include stdio.h struct S { int n; int arr[0]; }; int main() { printf(%zu\n, sizeof(struct S)); // 输出 4只算 int n return 0; }只算int n的 4 个字节arr[0]不占空间。特点三代码示例如下#include stdio.h #include stdlib.h struct S { int n; int arr[0]; }; int main() { int num 10; // 结构体 柔性数组的空间一起申请 struct S* ps (struct S*)malloc(sizeof(struct S) num * sizeof(int)); if (ps NULL) { return 1; } ps-n num; for (int i 0; i num; i) { ps-arr[i] i 1; } free(ps); ps NULL; return 0; }因为柔性数组arr[0]本身不占空间它只是一个占位符就是为了告诉编译器这里将来会有一块连续的内存空间。所以分配的时候结构体本身的空间只算n的 4 字节再额外加一块空间给数组用两块拼在一起那柔性体现在哪里呢这行代码里的 10 * sizeof(int)就是柔性的体现。柔性说的不是malloc本身而是malloc后面加的那个数。那个数想写多大就写多大写 10 就装 10 个写 100 就装 100 个写 0 就一个都不装——完全由你控制写多少就给分配多少。柔性还可以理解为想变就变很灵活所以叫柔性数组。三.柔性数组的使用代码示例如下代码一柔性数组一次分配一次释放//代码一 #include stdio.h #include stdlib.h struct S { int n; // 前面的成员 int arr[0]; // 柔性数组不占空间 }; int main() { // 申请空间结构体 柔性数组空间得一起申请 struct S* ps (struct S*)malloc(sizeof(struct S) 10 * sizeof(int)); if (ps NULL) { return 1; } // 使用空间 ps-n 10; // 给 n 赋值 for (int i 0; i 10; i) // 给数组赋值 { ps-arr[i] i; } // 空间不够扩容到 20 个 struct S* ptr (struct S*)realloc(ps, sizeof(struct S) 20 * sizeof(int)); if (ptr ! NULL) { ps ptr; } // 释放一次性释放不需要单独释放 arr free(ps); ps NULL; return 0; }运行通过根据我们创建的代码以及运行可知柔性数组就是结构体里不占空间的可变长数组用 malloc 一次申请用 realloc 随时扩容用 free 一次释放。四.柔性数组的优势代码示例如下代码二指针方案两次分配两次释放//代码二 #include stdio.h #include stdlib.h struct S { int n; int* arr; // 指针指向单独申请的数组 }; int main() { // 1.先申请结构体 struct S* ps (struct S*)malloc(sizeof(struct S)); if (ps NULL) { return 1; } ps-n 10; // 2.再申请数组 ps-arr (int*)malloc(10 * sizeof(int)); if (ps-arr NULL) { free(ps); // 数组申请失败释放结构体 ps NULL; return 1; } // 3.使用 for (int i 0; i 10; i) { ps-arr[i] i; } // 4.扩容 int* ptr (int*)realloc(ps-arr, 20 * sizeof(int)); if (ptr ! NULL) { ps-arr ptr; } // 5.释放这里先释放数组再释放结构体 free(ps-arr); ps-arr NULL; free(ps); ps NULL; return 0; }运行如下上述 代码1 和 代码2 可以完成同样的功能但是 ⽅法1 的实现有两个好处第⼀个好处是⽅便内存释放如果我们的代码是在⼀个给别⼈⽤的函数中你在⾥⾯做了⼆次内存分配并把整个结构体返回给⽤⼾。⽤⼾调⽤free可以释放结构体但是⽤⼾并不知道这个结构体内的成员也需要free所以你不能指望⽤⼾来发现这个事。所以如果我们把结构体的内存以及其成员要的内存⼀次性分配好了并返回给⽤⼾⼀个结构体指针⽤⼾做⼀次free就可以把所有的内存也给释放掉。第⼆个好处是访问速度更快内存碎片更少代码一的结构体和数组在内存里是紧挨着的访问数组时 CPU 的缓存命中率更高速度自然会快一些。另外代码二用了两次malloc会在堆上产生两块大小不同的内存碎片。代码一只用一次malloc只产生一块连续的大内存后续回收后也能整块复用内存利用率更高。这里我们用柔性数组把结构体和数组合成一块连续内存一次申请一次释放用户更省心内存利用率也更高。

相关新闻