0%

C语言之柔性数组flexible array

C99标准中,结构体中的最后一个元素可以是未知大小的数组,这个数组就叫做柔性数组成员(其前面至少要存在一个其他成员)。

一、概念

      在C99中,结构体中的最后一个元素可以是未知大小的数组,这个数组就叫做柔性数组成员,也称伸缩性数组成员,其前面至少要存在一个其他成员。官方说明:As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.。C99支持incomplete typeint a[]格式,不支持zero arrayint a[0]格式(有的编译器支持)。关于incomplete说明:incomplete types(types that describe objects but lack information needed to determine their sizes).。柔性数组成员特性如下:

  • 柔性数组不占内存,即sizeof返回的这种结构体大小时不包括柔性数组的内存
  • 柔性数组成员必须定义在结构体里面且为最后元素
  • 结构体中不能单独只有柔性数组成员

包含柔性数组成员的结构体用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小以适应柔性数组的预期大小。

二、使用

      C语言数据类型可分为四大类,即基本类型(数值类型(又分为整型和实数型)、字符串)、构造类型(数组、结构体、共用体、枚举)、指针类型、空类型。对于大部分数据类型,在其声明后所占的内存空间就已确定,如char a占1个字节,int b[10]则占40个字节,结构体所占内存为成员所占空间的总和(不考虑内存对齐的情况,实际不是取的和),共用体则为最大成员的所占的空间。

      结构体是比较常用的一种数据类型,有时需要在结构体中存放一个长度是动态的成员,此时一般又两种做法:

方式一:定义一个指针成员,指针指向动态的内存空间
方式二:使用柔性数组成员

  1. 指针成员方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

// #pragma pack(32);

typedef struct Test {
long double b;
int a;
char *p;
} Test;

int main()
{
Test *t = (Test *)malloc(sizeof(Test));

char *str = (char *)malloc(sizeof(char) * 10);
strcpy(str, "hello");

t->p = str;

printf("指针p的内容:%s\n", (t->p));
printf("t的地址为:%p\n", t);

printf("char *大小为:%d\n", sizeof(char *));

printf("t.b的地址为:\t%p\n", &(t->b));
printf("t.a的地址为:\t%p\n", &(t->a));
printf("t.p本身的地址为:%p\n", &(t->p));
printf("t.p内容的地址为:%p\n", (t->p));

printf("t.b的偏移量为:%d\n", offsetof(struct Test, b));
printf("t.a的偏移量为:%d\n", offsetof(struct Test, a));
printf("t.p的偏移量为:%d\n", offsetof(struct Test, p));//64位机器指针固定占8个字节

printf("t的内存大小为:%lu", sizeof(Test));

free(t);
free(t->p);

return 0;
}

通过以上代码可知,使用此方式分配和释放内存都需要进行两次。运行后可知,结构体内存和指针p指向的字符串内存是不连续的,

  1. 柔性数组方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <string.h>
#include <stdlib.h>

typedef struct Test {
int a;
char p[];
} Test;

int main() {
Test *t = (Test*)malloc(sizeof(Test) + sizeof(char) * (10+1));
strcpy(t->p, "hello");

printf("%s\n", (t->p));
printf("Address:\n");
printf("t\t %p\n", t);
printf("t.a\t %p\n", &(t->a));
printf("t.p\t %p\n", (t->p));
free(t);

return 0;
}

三、参考

  1. 参考一
  2. 参考二