前言
在c99标准中,引入了“柔性数组”的概念;
即在c99中,结构体的最后一个成员可以是一个未知大小的数组(没有长度的数组);
这个数组就叫做**【柔性数组】成员**;
柔性数组可以根据使用者的需求进行malloc,确保数组在使用中能保证足够且不过多浪费空间。
例:
struct SC { int a; char c; int arr[]; /*int arr[0]; 若是编译器报错也可写成该形式*/ }; int main() { struct SC s; printf("%d ", sizeof(s)); return 0; }
柔性数组的特点
柔性数组在计算大小时是不参与到结构体大小之中的,在结构体中,柔性数组属于一个未知大小的数组,即编译器也不能确定的大小。
柔性数组的使用
#include<stdio.h> //声明存在柔性数组的结构体 struct SC { int a; char c; int arr[]; /*int arr[0]; 若是编译器报错也可写成该形式*/ }; int main() { //使用malloc函数为带柔性数组的结构体变量进行动态内存分配 struct SC* s = (struct SC*)malloc(sizeof(struct SC) + 10 * sizeof(int)); if (s == NULL) {//判断返回指针是否有效 perror("malloc"); return 1; } else { //使用 s->a = 10; s->c = 'c'; for (int i = 0; i < 10; i++) { s->arr[i] = i+1; } for (int i = 0; i < 10; i++) { printf("%d ", s->arr[i]); } } //释放内存 - 指针置空 free(s); s = NULL; return 0; }
声明一个存在柔性数组成员的结构体,并使用该类型创建一个指针变量,利用该指针malloc所需要的内存即可。
同时,在使用柔性数组应注意:
- 结构中的柔性数组成员前面必须至少存在一个其他成员
在使用柔性数组时应确保该结构体除了柔性数组成员还应拥有其他成员,根据上文可知,柔性数组为一个未知大小的数组,故若是结构体中只存在柔性数组,则不能确定结构体大小 - error 。 - 柔性数组成员应存在于结构体内所有成员的最后一位。
- 若是使用sizeof( )计算结构体大小,返回值不包括柔性数组成员。
- 柔性数组的大小使用malloc函数进行初始化
包含柔性数组成员的结构体使用malloc函数进行动态内存分配,且内存分配的大小必须大于结构体的大小,以适应柔性数组的预期大小。
不使用柔性数组实现可变数组
若是不使用柔性数组,能使用其他方式来实现类似于柔性数组的可变效果吗?
#include<errno.h> #include<string.h> #include<stdlib.h> struct SC { int a; char c; int* p; }; int main() { //第一次malloc struct SC* py = (struct SC*)malloc(sizeof(struct SC)); if (py == NULL){//判断malloc返回的指针是否有效 printf("%s\n", strerror(errno)); return 1; } //第二次malloc py->p = (int*)malloc(10 * sizeof(int)); if (py->p == NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 py->a = 10; py->c = 'w'; for (int i = 0; i < 10; i++) { py->p[i] = i + 1; } printf("%d %c\n", py->a, py->c); for (int i = 0; i < 10; i++) { printf("%d ", py->p[i]); } //释放 //释放时应按照顺序进行释放 free(py->p); py->p = NULL; free(py); py = NULL; return 0; }
在结构体中不设置柔性数组,取而代之的是一个整形的指针,可根据需要来变换指针的类型;
- 第一次malloc:
malloc结构体变量的大小存放至结构体指针中,确保可通过结构体指针访问到相应的空间。 - 第二次malloc:
第二次malloc则是通过结构体内部的指针来开辟一个根据需求所定的大小用于存放数组数据模拟柔性数组。通过指针来链接各个内存空间。
两者的区别
若是将柔性数组定为方案一,不使用柔性数组实现可变数组定为方案二;
哪种方案的效率会更高?
- 方案一优先:
柔性数组 | 非柔性数组 | |
malloc | 一次 | 两次 |
free | 一次 | 两次 |
置空 | 一次 | 两次 |
- malloc函数为动态内存分配,但是malloc进行多次动态内存分配时所分配到的空间并不是连续的,所以在每块动态内存空间中,将会存在内存碎片;因为内存碎片的大小十分小,故他们的被利用率将大大降低。
- 且从上文可知每次进行动态开辟内存时再用完或者不用时应该及时释放,若不释放程序结束内存也会由操作系统进行回收,但若是程序未结束,也未释放内存,则会导致内存泄漏的问题;
多次malloc意味着需要更多次的free释放以及多次的置空指针,也意味着代码的维护难度要加大。
注意事项
在使用柔性数组时应注意:
- 使用柔性数组时,柔性数组成员前至少需要存在一位其他成员;
- 在使用sizeof计算结构体大小时,柔性数组不参与其中;
- 带有柔性数组成员的结构体应使用malloc函数进行动态内存分配,且分配的动态内存必须大于结构体的大小,以适应柔性数组的预期大小。