也许你从来没有听说过
柔性数组(
flexible array
)
这个概念,但是它确实是存在的。
C99
中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
struct S
{
int i;
char ch[0];//char ch[]
};
int main()
{
return 0;
}
上面一个结构体中最后一个未指定大小的数组就是柔性数组。上面的俩种方法都是可以的。
柔性数组的特点:
一 结构中的柔性数组成员前面必须至少一个其他成员。结构体成员中不能就会只有一名柔性数组成员,应该还包含其他的非柔性数组的成员。
struct s
{
int arr[];
};
二、sizeof返回的这种结构大小不包括柔性数组的内存
所以,当你用sizeof来计算一个含有柔性数组成员的结构体大小时,计算出的结果不包括柔性数组成员在内。
比如:
struct S
{
int i;
char ch[0];//char ch[]
};
int main()
{
printf("%zd\n", sizeof(struct S));//结果是4
return 0;
}
三、包含柔性数组成员的结构用malloc函数进行内存的的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
struct S
{
int i;
char ch[0];//char ch[]
};
int main()
{
struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(char));
if (ps == NULL)//判断
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
*(ps->ch) = 'Q';
}
for (i = 0; i < 10; i++)
{
printf("%c ", *(ps->ch));
}
free(ps);
ps = NULL;
return 0;
}
在图中开辟的前面的sizeof开辟的是int i的空间,后面一个是柔性数组的空间。然后我们可以开辟的10个空间打印10个字符Q。
模拟实现柔性数组的功能
其实,我们若不借用柔性数组也能实现以上功能:
typedef struct S
{
int i;
char* ch;
}S;
int main()
{
S* ps = (S*)malloc(sizeof(S));
if (ps == NULL)
{
perror("malloc");
return 1;
}
ps->ch = (char*)malloc(sizeof(char) * 10);
if (ps->ch == NULL)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
*(ps->ch) = 'Q';
}
char* plc = (char*)realloc(ps->ch, 20 * sizeof(char));
if (plc != NULL)
{
ps->ch = plc;
}
else
{
perror("realloc");
return 1;
}
for (i = 0; i < 10; i++)
{
printf("%c ", *(ps->ch));
}
free(ps->ch);
ps->ch = NULL;
free(ps);
ps = NULL;
return 0;
}
柔性数组其实也就是结构体中的一个数组,准确来说,是一个空间大小可以自由变换的数组,那么我们在结构体中定义一个指针,使指针指向的空间可以自由变换(即指针指向的是动态开辟的内存),也就达到了这个效果。
注意: 这里释放动态内存空间时,需要先释放ps->ch指向的动态内存空间,再释放ps指向的动态内存空间。 如果我们先释放的是ps指向的动态内存空间,那么ps->ch所指向的空间就再也找不到了。
柔性数组的优点:
上述
代码
1
和
代码
2
可以完成同样的功能,但是
方法
1
的实现有两个好处:
第一个好处是:
方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给
用户。用户调用
free
可以释放结构体,但是用户并不知道这个结构体内的成员也需要
free
,所以你
不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好
了,并返回给用户一个结构体指针,用户做一次
free
就可以把所有的内存也给释放掉。
第二个好处是:
这样有利于访问速度
.
连续的内存有益于提高访问速度,也有益于减少内存碎片