柔性数组

柔性数组既数组大小待定的数组, C语言中结构体的最后一个元素可以是大小未知的数组,也就是所谓的0长度,所以我们可以用结构体来创建柔性数组。

用途

主要用途是为了满足需要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。

用法

在一个结构体的最后 ,申明一个长度为空的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,我们可以进行动态分配,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!

对于柔性数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:

struct buff {
  int len;
  int array[0];
};

或者: C99标准

struct buff {
   int len;
   int array[]
}

数据结构大小:这样的变长数组常用于网络通信中构造不定长数据包, 不会浪费空间浪费网络流量, 因为char data[0]; 只是个数组名, 是不占用存储空间的,即
sizeof(struct person) = sizeof(int)

#include <stdio.h>
#include <stdlib.h>

struct buff {
   int len;
   char data[0];
};

int main(int argc, char *argv[]) {
        printf("malloc before, size=%u\n",sizeof(struct buff));
        struct buff *bdata = (struct buff *)malloc(sizeof(struct buff) + 10*sizeof(char));
        printf("malloc after, size=%u\n", sizeof(*bdata));
        return 0;
}

运行结果为:

malloc before, size=4
malloc after, size=4

为什么0长度数组不占用存储空间

本质涉及到c语言中数组与指针的区别问题。 char a[1] 中a 与 char *b 的b 相同吗?

char a[1] 中的a是一个常量,等于&a[0] , 而 char *b 是一个实实在在的指针变量b,所以a = b是不允许的,而b=a是允许的。

代码判断

#include <stdio.h>

int main() {
   char s[0];
   printf("address = %p,size = %d\n",s,sizeof(s));

   char *ptr = (char *)malloc(0);
   printf("ptr = %p\n",ptr);
}

执行结果为:

address = 0x7ffc440ddd70,size = 0
ptr = 0xf92010

无论通过栈分配还是malloc堆分配对应的0长度数组都有地址,但是大小为0,表明地址只是一个偏移量而已

文档更新时间: 2021-03-09 21:26   作者:周国强