定义:结构体中最后一个元素允许是未知大小的数组,这个数组就是柔性数组(soft array),也叫伸缩性数组。但结构中的柔性数组前面必须至少一个其他成员。
例:
typedef struct
{
uint8_t afn; //功能码
uint8_t seq; //seq
uint8_t payload[ ]; //payload
}package_info_t;
当然有的编译器会对这种定义报错,需改成如下定义:
typedef struct
{
uint8_t afn; //功能码
uint8_t seq; //seq
uint8_t payload[0]; //payload
}package_info_t;
这边使用柔性数组,是用来解析不定长通信包的。一般在解析不定长数据包时,最懒的方法是把载荷(payload)的最大长度设置为数组缓存的大小,比如最大的通信包载荷是1000,那么可以定义如下
#define MAX_LEN 1000
typedef struct
{
uint8_t afn; //功能码
uint8_t seq; //seq
uint8_t payload[MAX_LEN]; //payload
}package_info_t;
这种固定长度的定义,显然处理起来简单,但是在载荷变化时,比如数据包的载荷有时候为5、12、50等等远小于MAX_LEN长度时,是及其浪费内存资源的。这时候可以考虑采用动态内存开辟的方式来实现资源的集约化,柔性数组的使用就满足了该场景。
例:
struct flexible_array
{
int state;
int value[0]; //柔性数组成员,也可以写value[];
};
int main()
{
//柔性数组申请10个int的空间
struct flexible_array *p=(struct flexible_array*)malloc(sizeof(struct flexible_array) + 10 * sizeof(int));
if (p == NULL)
{
return -1;
}
int j = 0;
for (j = 0;j < 10;j++)
{
p->value[j] = j;
}
for (j = 0;j < 10;j++)
{
printf("%d ", p->value[j]);
}
printf("\n");
//释放空间
free(p);
p = NULL;
return 0;
}
这个例子是柔性数组动态申请10个int的内存空间来使用,结果如下
这里需要注意:
对于编译器而言,此时长度为0的数组并不占用空间,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!!!
struct flexible_array *p=(struct flexible_array*)malloc(sizeof(struct flexible_array) + 10 * sizeof(int));
当然柔性数组还可以扩展伸缩,只需用realloc:
struct flexible_array* ptr=realloc(p, sizeof(struct flexible_array) + 15 * sizeof(int));
这就是柔性数组的用法。
当然在解析不定长数据包时,除了使用柔性数组,也可以采用指针的方式来实现动态内存分配:
struct memory
{
int state;
char * p_value; //指针;
};
实现如下:
//首先是结构体分配内存,获取指针
struct memory *p = (struct memory*)malloc(sizeof(struct memory));
if(p == NULL)
{
return -1;
}
p->state = 0;
//其次,获取一个10个char型的内存空间
p->p_value = (char *)malloc(10 * sizeof(char));
if(p->p_value == NULL)
{
return -1;
}
在内存释放时的操作如下
//释放,必须先释放p_value;否则p一释放,p_value就丢失了指向
free(p->p_value);
p->p_value = NULL;
free(p);
p = NULL;
乍一看,和上面的柔性数组使用区别不大?
这种方式,动态申请了两块内存,那么这两块内存是不连续的,这样就导致了内存碎片化。柔性数组内存是连续的,是一块内存,连续的内存有益于提高访问速度。
其次,在释放内存时,需要分两次释放,而且是依次释放,这在独立编程时是问题不大,但是如果把这部分封装成API,那么如果封装接口不完善,没有做到把申请的内存都释放的话(比如没有结构体内部指针内存的释放),就容易有内存泄漏的风险。