柔性数组
也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
例如:
柔性数组的特点
-
结构中的柔性数组成员前面必须至少有一个其他成员。
-
sizeof 返回的这种结构大小不包括柔性数组的内存。
-
包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
柔性数组前需要有至少应该成员:
为带有柔性数组成员的结构体开辟的空间必须比结构体的最小的占用内存大小更大:
当空间不够使用,需要增容的时候,我们可以用realloc进行增容
现在数组可通过malloc开辟,也可通过realloc增容,具备了可扩展性,体现了柔性,因此称为柔性数组。
结构体最后应该数组元素大小需要是可变化的可扩展的时候,就需要用到柔性数组了。(应用少,并不流行)
代码1
柔性数组
struct S
{int n;int arr[0];//柔性数组成员
};int main()
{//printf("%d\n", sizeof(struct S));//输出4struct S* ps = malloc(sizeof(struct S) + 40);if (ps == NULL){perror("malloc");return 0;}ps->n = 100;int i = 0;for (i = 0; i < 10; i++)//逐个元素赋值{ps->arr[i] = i + 1;}//空间不够,需要增容struct S* ptr = realloc(ps, sizeof(struct S) + 60);if (ptr == NULL)//增容失败{perror("realloc");return 1;}ps = ptr;//增容成功ps->n = 15;for (i = 0; i < 15; i++){printf("%d\n", ps->arr[i]);//打印柔性数组前15个}//释放空间free(ps);ps = NULL;return 0;
}
其他方法实现柔性数组
有没有一种方案可以替代柔性数组呢,用其他方法来实现一模一样的效果。
先开辟出结构体大小的空间,然后用arr作为起始地址开辟一段新的空间存放数组,这段数组可以用realloc增容。
代码2
//柔性数组的替换
struct S
{int n;int* arr;
};
int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){perror("malloc->ps");return 1;}ps->n = 100;ps->arr = (int*)malloc(40);if (ps->arr == NULL){perror("malloc->arr");return 1;}int i = 0;for (i = 0; i < 10; i++){ps->arr[i] = i + 1;}//调整增容int* ptr = (int*)realloc(ps->arr, 60);if (ptr != NULL){ps->arr = ptr;}else{perror("realloc");return 1;}//打印for (i = 0; i < 15; i++){printf("%d\n", ps->arr[i]);}//释放free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}
柔性数组的优势
上述 代码1 和 代码2 可以完成同样的功能,但是 方法1 的实现有两个好处:
第一个好处是:方便内存释放。
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
第二个好处是:这样有利于访问速度。
连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)