该文章将介绍柔性数组是什么,有什么作用以及如何使用柔性数组,帮助你更好的理解结构体中的细节。
1.柔性数组
可能你从来没有听过柔性数组这个概念,但是它确实是存在的。
在C99中,结构体中最后一个成员允许是大小未知的数组,这就叫做【柔性数组】成员。
比如:
struct Stu { int n; char c; int arr[];这个就是柔性数组成员 };
有些编译器会报错无法编译可以改成
struct Stu { int n; char c; int arr[0]; };
2.柔性数组的特点:
- 结构体中的柔性数组成员前面必须至少要有一个其他成员。
- sizeof返回的这个结构体大小不包含柔性数组的内存
- 包含柔性数组的结构体要用malloc()函数进行内存的动态分配,并且分配的大小应该大于结构体的大小,以适应柔性数组的预期大小
例如:
struct Stu { int n; int arr[];柔性数组 }; int main() { printf("%d", sizeof(struct Stu)); //这个结构体大小不包含柔性数组的内存,相当于这个给结构体中只有int n;成员,大小也就是4 return 0; }
3.柔性数组的使用
struct S { int a; char arr[];//不设置大小--柔性数组,结构体中最后一个,前面至少要求一个成员 //这个结构体大小是除柔性数组以外的成员计算得到大小 //柔性数组的空间使用需要malloc开辟 }; int main() {//使用malloc函数给结构体变量开辟内存,sizeof(struct S)是为结构体中除柔性数组外成员分配空间,而后面的则是为柔性数组开辟空间 //最后都把开辟的空间转换为结构体类型,用结构体指针来接收 struct S*p=(struct S*)malloc(sizeof(struct S) + 10 * sizeof(char)); if (p == NULL)//判断一下 { perror("malloc"); return 1; } p->a = 100;//访问变量 int i = 0; for (i = 0; i < 10; i++)//给数组分配了10个整形的空间 { p->arr[i] = '6';//使用这块空间 } for (i = 0; i < 10; i++) { printf("%c ", p->arr[i]);//打印出来 } //想要给柔性数组增容 -----p指向的是原先的空间大小的指针,要想开辟更大的空间,在原基础上加就可以了 struct S*ptr=(struct S*)realloc(p,sizeof(struct S) + 20 * sizeof(char)); if (ptr != NULL)//还是要判断一下 { p = ptr; } else { perror("realloc"); return 1; } //释放 free(p); p = NULL; return 0; }//
这样的柔性数组arr相当于先获得10个整形大小的连续空间,后来又增容到20个整形的连续空间。
4.柔性数组的优势
上面的代码就是将结构体中一个数组的大小可以随意变化。也可以这样写:
struct S { int a; int* arr;//成员是指针不是柔性数组 //用malloc使这个指针指向一块大小可以是自己改变的 }; int main() { struct S *p = (struct S*)malloc(sizeof(struct S));//给结构体变量申请一块空间,用结构体指针接收 p->a = 100;//访问结构体成员 p->arr = (int*)malloc(10 * sizeof(int));//给指针arr指向的地方申请10个整形空间 int i = 0; for (i = 0; i < 10; i++) { p->arr[i] = '6';//使用malloc为arr开辟的空间 } for (i = 0; i < 10; i++) { printf("%c ", p->arr[i]); } //增容 int *ptr=(int*)realloc(p->arr, 20 * sizeof(int)); if (ptr == NULL)//判断一下 { perror("realloc"); return 1; } free(p->arr);//必须先释放arr开辟的空间再释放p开辟的空间,从里到外释放 p->arr = NULL; free(p); p = NULL; return 0; }
上面代码1和代码2都可以完成相同的功能,但代码1的实现有两个好处:
第一个好处是:方便内存释放
可以明显的看出来代码2比代码1,多开辟空间也多释放空间。
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
第二个好处是:有利于提高访问速度
频繁的开辟空间会形成大量的内存碎片而连续的内存有益于提高访问速度,减少内存碎片。
如果想了解更多的知识这里有陈皓大佬的一篇文章里面也是讲的柔性数组,供参考