柔性数组
在c99中,结构体的最后一个元素允许是未知大小的数组,这个就是柔性数组
柔性数组的特点
1.结构体中的柔性数组成员前面必须至少有一个其他成员
2.sizeof返回的这种结构大小不包括柔性数组的内存
3.包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
柔性数组的声明
struct S
{
int n;
int arr[];//这里不指定数组的大小
};
有些编译器支持上面的写法,有些编译器支持下面的写法
struct S
{
int n;
int arr[0];
};
柔性数组的大小
struct S
{
int n;
int arr[0];
};
int main()
{
printf("%d ", sizeof(struct S));
return 0;
}
这里我们在计算结构中包含柔性数组的大小的时候,不计算柔性数组的内存
柔性数组的使用
struct S
{
int n;
int arr[];
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(struct S));
// 为n开辟空间 为arr数组开辟空间
if (p == NULL)
{
//这里判断
perror("malloc");
return 1;
}
//申请成功,使用
p->n = 100;
int i = 0;
for (i = 0; i < 5; i++)
{
p->arr[i] = i + 1;
}
//空间不够,增容
struct S* ptr = (struct S*)realloc(p, sizeof(struct S) + 10 * sizeof(struct S));
//这里先创建一个结构体指针变量接收realloc的返回值
if (ptr == NULL)
{
perror("realloc");
return 1;
}
//增容成功,使用
p = ptr;
for (i = 5; i < 10; i++)
{
p->arr[i] = i + 1;
}
//使用完毕,释放
free(p);
p == NULL;
return 0;
}
这里,我们通过malloc函数申请空间,然后通过realloc函数来调节这个数组的大小,达到这个数组可以变长变短的效果,这个就是柔性数组。
结构体包含指针的形式模拟实现柔性数组的效果
我们可以不通过使用结构体中包含柔性数组的形式,我们通过结构体中包含指针也可以完成
struct S
{
int n;
int* arr;//这里我们创建一个数组指针
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S));
//这里我们先为结构体开辟空间
if (p == NULL)
{
perror("malloc");
return 1;
}
p->n = 100;
//这里我们为数组指针指向的数组开辟空间
p->arr = (int*)malloc(5*sizeof(int));
if (p->arr == NULL)//判断是否开辟成功
{
perror("malloc");
return 1;
}
//开辟成功,使用
int i = 0;
for (i = 0; i < 5; i++)
{
p->arr[i] = i + 1;
}
//假设大小不够,进行增容
int* ptr = (int*)realloc(p->arr, 10* sizeof(int));
if (ptr == NULL)
{
perror("realloc");
return 1;
}
//增容成功,使用
p->arr = ptr;
for (i = 5; i < 10; i++)
{
p->arr[i] = i + 1;
}
//这里我们需要先释放arr开辟的空间,在释放结构体开辟的空间
//如果我们先释放了结构体开辟的空间,那么我们就找不到arr开辟的空间了,会造成内存泄漏的问日
free(p->arr);
p->arr = NULL;
free(p);
p = NULL;
return 0;
}
柔性数组的优势
使用结构体包含指针的方式也可以完成结构体包含柔性数组的方式的效果,那么结构体包含柔性数组的优势是什么呢?
这里有两点优势
1.方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,那么就会导致内存泄漏的问题。如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户只需要一次free就可以把所有的内存也给释放掉
2.有利于访问速度
连续的内存有利于提高访问速度,也有益于减少内存碎片。
如果malloc函数使用的次数越多,内存碎片就越多,那么内存的利用率就会越低