一、先来看看概念~
柔性数组:结构体最后一个元素是未知大小的数组,叫柔性数组。
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;
有些编译器会报错⽆法编译可以改成:
typedef struct st_type
{
int i;
int a[];//柔性数组成员
}type_a;
二、柔性数组的特点
- 结构体中的柔性数组成员前面必须至少有⼀个其他成员。
- sizeof 返回的这种结构体大小不包括柔性数组的内存。
- 包含柔性数组成员的结构体用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;
int main()
{
printf("%d\n", sizeof(type_a));//输出的是4
return 0;
}
由这段代码大家可以看出来,结构体的大小不包括柔性数组的内存
三、柔性数组的使用(两种方法)
方法一
可以使用一个结构体指针,把这片用malloc开辟的空间管理起来,还可以在此基础之上试试用realloc把这片空间调整到你想要的大小
库库提醒大家:在使用指针接收malloc,realloc等函数时,一定要判断接收到的是否是NULL,不要接收了NULL还傻傻的去对空指针进行解引用操作,还有一件事,在我们用完这块空间释放了之后一定要记得把指针置空!!防止出现野指针哦
#include <stdio.h>
#include <stdlib.h>
struct St
{
char c;
int n;
int arr[0];
};
int main()
{
struct St s = {0};
//用一个结构体指针把这片空间管理起来
struct St* ps = (struct St*)malloc(sizeof(struct St) + 10*sizeof(int));
if(ps == NULL)
{
perror("malloc");
return 1;
}
ps -> c = 'w';
ps -> n = 520;
int i = 0;
for(i = 0; i<10; i++)
{
ps -> arr[i] = i;
}
//还可以使用realloc来扩大arr的大小
struct St* ptr = realloc(ps, sizeof(struct St) + 15*sizeof(int));
if(ptr !=NULL)
{
ps = ptr;
}
else
{
perror("realloc");
return 1;
}
//打印
printf("%c\n", ps -> c);
printf("%d\n", ps -> n);
for(i = 0; i<10; i++)
{
printf("%d", ps ->arr[i]);
}
printf("\n");
//手动释放内存!!
free(ps);
ps = NULL;//一定要手动置空,free没有置空指针的功能
return 0;
}
方法二
也可以设计成下面的结构
使用一个指针来实现数组的功能
我们先用malloc给struct St划分一块空间,然后用malloc返回的指针指向这个arr指针,让arr指针接收我们第二次创建的空间,这个空间就相当于数组的空间,利用arr[i] 等价于*(arr+i)的思想来模拟实现数组
#include <stdio.h>
#include <stdlib.h>
struct St
{
char c;
int n;
int *arr;
};
int main()
{
struct St* ps = (struct St*)malloc(sizeof(struct St));
if(ps == NULL)
{
perror("malloc");
return 1;
}
ps -> c = 'w';
ps -> n = 520;
ps -> arr = (int*)malloc(10*sizeof(int));//指针arr指向这开辟的空间的首地址
if(ps -> arr == NULL)
{
printf("malloc -2");//表示第二个malloc出问题了所以写个-2来标记
return 1;
}
//使用
int i = 0;
//也可以用realloc来调整大小
int* ptr = (int*)realloc((ps -> arr), 15*sizeof(int));
if(ptr == NULL)
{
perror("realloc");
return 1;
}
else
{
ps -> arr = ptr;
}
for(i = 0; i<15; i++)
{
ps -> arr[i] = i;//arr[i] == *(arr + i)
}
//打印一下看看吧
for(i = 0; i<10; i++)
{
printf("%d", ps -> arr[i]);
}
printf("\n%d\n", ps -> n);
printf("%c\n", ps -> c);
//释放空间加置空连招~~~
free(ps -> arr);
ps -> arr = NULL;
free(ps);
ps = NULL;
return 0;
}
大家仔细看了代码后应该发现了,我们最后释放空间的时候,是一部分一部分释放的
三、优点
对比两种方法,不难看出方法一更加优秀
使用方案一有两个好处:
第⼀个好处是:方便内存释放(很显而易见,方案一只用释放一次内存,不需要考虑太多)
如果我们的代码是在⼀个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能 指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存⼀次性分配好了,并返回给用户⼀个结构体指针,用户做⼀次free就可以把所有的内存也给释放掉。
第二个好处是:这样有利于访问速度.
连续的内存有益于提搞访问速度,也有益于减少内存碎片。
什么是内存碎片?我们在向内存用malloc申请的时候申请的地方不一定是连续的,其中的间隙会造成内存的浪费,申请的越多,间隙越多,也就是内存碎片越多。
感谢阅读,求各位大佬多多点赞