目录
前言
前述知识铺垫:C语言动态内存详解
1.柔性数组是什么
也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。 例如:
typedef struct st_type { int i; int a[];//柔性数组成员 }type_a;
有些编译器会报错无法编译可以改成:
typedef struct st_type { int i; int a[0];//柔性数组成员 }type_a;
柔性数组成员前至少有一个其他成员。
柔性数组的柔性体现在其大小可以调整(配合动态内存调整内容)
2.柔性数组特点
- 结构中的柔性数组成员前面必须至少一个其他成员。
- sizeof 返回的这种结构大小不包括柔性数组的内存。
(这里根据特点二来输出,发现只打印了柔性数组成员前成员的大小,并没有打印我们的柔性数组的大小,这是因为我们的柔性数组大小是未知的,想计算都没有办法)
- 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大 小,以适应柔性数组的预期大小。
比如:我希望我们的柔性数组存储10个整型,我们就应该这样来开辟空间:
3.柔性数组的使用
typedef struct st_type { int i; int a[0];//柔性数组成员 }type_a; int main() { /*int sz = sizeof(type_a); printf("%d\n", sz);*/ type_a* pc = (type_a*)malloc(sizeof(type_a) + 40); if (pc == NULL) { perror("malloc"); return; } pc->i = 100; int a = 0; for (a = 0; a < 10; a++) { pc->a[a] = a + 1; } //用完释放内存 free(pc); pc = NULL; return 0; }
代码逻辑解析:
当我们进行扩容:
typedef struct st_type { int i; int a[0];//柔性数组成员 }type_a; int main() { /*int sz = sizeof(type_a); printf("%d\n", sz);*/ type_a* pc = (type_a*)malloc(sizeof(type_a) + 40); if (pc == NULL) { perror("malloc"); return; } pc->i = 100; int a = 0; for (a = 0; a < 10; a++) { pc->a[a] = a + 1; } //空间不够,进行扩容 type_a* str = (type_a*)realloc(pc, sizeof(type_a) + 60); if (str == NULL) { perror("realloc"); return; } pc = str; pc->i = 15; for (a = 0; a < 15; a++) { printf("%d\n", pc->a[a]); } //用完释放内存 free(pc); pc = NULL; return 0; }
未来在使用结构体的时候,当你希望结构体最后一个数组成员的大小是可变的时候就可以使用柔性数组了。柔性数组的数据都在堆区。没有特别强的应用场景,只是一种新的语法形式。
4.柔性数组代替
很多伙伴可能已经想到了我们没有必要这样去实现,可以使用指针的形式,然后将我们的结构体和指针指向的空间都用我们动态内存来开辟,这样数据不也是都在堆区嘛,这样也是可行的我们来看一下实现:
struct s { int n; int* arr; }; int main() { struct s* ps = (struct s*)malloc(sizeof(struct s)); if (ps == NULL); { perror("malloc-ps "); return; } ps->n = 100; ps->arr = (int*)malloc(40); if (ps->arr == NULL) { perror("malloc->arr"); return; } int i = 0; for (i = 0; i < 10; i++) { ps->arr[i] = i + 1; } //当空间不足我们可以进行调整 int* ptr = (int*)realloc(ps->arr, 60); if (ptr == NULL) { perror("realloc"); return; } ps->arr = ptr; for (i = 0; i < 15; i++) { printf("%d\n", ps->arr[i]); } //使用完,我们记得释放空间,记得一定先释放里面的再释放外面的 free(ps->arr); ps->arr = NULL; free(ps); ps = NULL; return 0; }
我们看到和上面的柔性数组得到的结果是一样的,那么柔性数组的优势是什么呢?
5.柔性数组优势
首先对比两种方式:
①开辟次数越多,malloc次数越多越危险,有时候会忘记释放空间。
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给 用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你 不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好 了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
②内存开辟的次数越多,那么每块内存之间的空隙也会增多,那么,内存碎片增多,对内存的访问效率就降低了。
连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正 你跑不了要用做偏移量的加法来寻址)
6.结语
以上就是本期的所有内容,大家可以配合解释和原码运行理解。创作不易,大家如果觉得还可以的话,欢迎大家三连,有问题的地方欢迎大家指正,一起交流学习,一起成长,我是Nicn,正在c++方向前行的奋斗者,感谢大家的关注与喜欢。