结构成员指针
typedef struct XXX
{
...
类型* 结构成员指针;
}XXX;
-
当结构中某类成员的数量不确定时,应该先设计一个结构成员指针,通过创建结构变量时,另外申请一块堆内存,并让该结构成员指针指向它,从而配合长度属性使用
-
当使用结构成员指针时,需要分配两次内存,先要给结构变量分配内存,然后还要给结构成员指针另外再分配内存,并且很可能不连续,所以内存碎片的几率增加
-
这样的结构变量不能直接写入文件中(因为对于结构成员指针是直接把存储的地址写入文件,是没有意义),并且这样的结构变量也不能直接赋值使用(因为会只拷贝地址,相当于两个变量共同指向同一块内存,称为浅拷贝,没意义)
#include <stdio.h>
#include <stdlib.h>
typedef struct Test
{
int n;
int* my_p;
}Test;
int main(int argc,const char* argv[])
{
Test* t = malloc(sizeof(Test));
Test* t1 = malloc(sizeof(Test));
t->my_p = malloc(sizeof(int)*5);
t->n = 100;
for(int i=0; i<5; i++)
{
t->my_p[i] = i;
}
*t1 = *t;
t1->my_p[0] = 88;
printf("%d\n",t->my_p[0]);
free(t->my_p);
free(t);
free(t1->my_p); // 会重复释放 同一块堆内存
free(t1);
t = NULL;
t1 = NULL;
}
柔性数组
定义:在C99语法标准中,一个结构体的最后一个成员,可以是一个长度未知的数组,称为柔型数组,即在结构体末尾零长度的数组
typedef struct XXX
{
...
size_t len;
类型 数组名[0]; // 不会报错 个别编译器 类型 数组名[] 会报错
}XXX;
特点:
-
通过sizeof计算带有柔型数组的结构体大小时,不会包含柔型数组的内存
-
结构中柔性数组成员前面必须至少有一个其他的成员,而且柔性数组成员必须在所有结构成员的末尾
-
柔型数组的原理是编译器巧妙地通过数组合法越界的手段来访问结构体后序多余的内存,因为柔型数组的内存与结构的内存一定是连续的
-
使用柔性数组时,需要通过malloc进行内存分配,并且分配的内存要大于结构的大小,才能让柔性数组成立(calloc、realloc也要多分配内存)
柔性数组的使用:
#include <stdlib.h>
typedef struct Test
{
char c;
int i;
int arr[0];
}Test;
int main(int argc,const char* argv[])
{
printf("%d\n",sizeof(Test));
Test* t = malloc(sizeof(Test)+40);
//Test* t = malloc(sizeof(Test)+sizeof(((Test*)0)->arr[0])*10);
printf("%d\n",sizeof(*t));//结构长度依然是8 不会计算柔性数组长度
t->c = 'a';
t->i = 100;
for(int i=0; i<10; i++)
{
t->arr[i] = i;
printf("%d ",t->arr[i]);
}
free(t);
t = NULL;
}
柔性数组优点:
-
节约存储成员指针的内存,因为柔型数组名不占用内存空间
-
分配、释放内存时可以一次性搞定,使用方便,并且降低了内存碎片、内存泄漏的可能,并且在后续的使用中用法与结构成员指针一样
-
使用柔型数组的结构体内存可以直接进行赋值、写入文件的
-
柔型数组的结构体内存与结构其他成员的内存是连续的,因此访问柔性数组成员时速度更快
柔型数组的限制:
-
一个结构体中只能有一个柔型数组,但是结构成员指针可以有任意多个
-
柔型数组必须放在结构体末尾,结构成员指针无限制
-
必须也像结构成员指针一样,有另一个成员变量存储它的长度
-
一些古老的编译器可能不支持这种语法