在标准 C 和 C++ 中,不允许用 0 长度数组,但在 GNU C 中,却可以定义 0 长度数组;

struct line
{
     int length ;
     char contents[0];
};

0 长度数组不占有空间,从打印 sizeof (struct line) 可以看到这个结构体的长度为 4,这 4 字节空间属于整型量 length 。那么结构体里最后的 0 长度字符数组 contents[0] 用来做什么呢?答案是,它可以用来指向一段由你自己分配的 buffer 空间。如:

int this_length = 60 ;
struct line *thisline = (struct line *)malloc(sizeof(struct line )+this_length);
thisline->length = this_length;

这样,就开辟了 64 字节空间。前面 4 个字节为 this_length 用,后面 60 个字节被 contents 数组用。经过空间分配后,就相当于把结构体定义为:

struct line
{
     int length ;
     char contents[60];
}

顺便看一下这个空间的分布,做如下打印:

printf ("thisline 指向的地址为:%p\n",thisline);
printf ("thisline指向的第一个元素值为:%d\n" , thisline->length );
printf ("该元素的地址为%p\n", &thisline->length);
printf ("%p\n",&thisline->contents);
printf ("%p\n",&thisline->contents[0]);
printf ("%p\n",&thisline->contents[1]);

输出为:

thisline指向的地址为:0x8780008
thisline指向的第一个元素值为:60
该元素的地址为0x8780008
0x878000c
0x878000c
0x878000d

从输出可以看到,thisline-contents只是一个“不占有空间“(其特性由编译器决定)的常量指针。在这里,它表示接着整型值后的起始地址。

现在,我们可以使用这个数组了,比如给这个数组的前几个元素赋下值:

char c = 'x';
int i;

thisline->contents [0] = c;
c = 'y';
thisline->contents [1] = c;
c = 'z';
thisline->contents [2] = c;
for (i = 0 ; i < 3 ; i ++ )
      printf ("%c\n" , thisline->contents [i]);

关于释放问题:

由于分配的空间返回的指针被强制转换为 struct line 类型,且所得到的空间并不是平缓的(包含的不是同一种元素类型的空间)。在这里的空间组成是,一个整型值 + 后面一大块字符型缓冲区。所以,在释放时,free() 函数认为 *thisline 只是一个指向 4 字节整型值的空间。因而,我们要完全释放整个申请的空间,还需要:

free (thisline->contents);

正确的释放步骤为:

free (thisline->contents);   /*先释放掉后面的数组buffer*/
free(thisline);    /*再释放掉 4 字节整型空间*/