1. 柔性数组的来源

有时候需要在结构体中存放一个长度动态的字符串,一般的做法,是在结构体中定义一个指针成员,这个指针成员指向该字符串所在的动态内存空间

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

p指向字符串。这种方法造成字符串与结构体是分离的,不利于操作。如果把字符串跟结构体直接连在一起,不是更好吗?

即申请一块动态内存空间,这段连续的空间包括结构体以及p所指向的数据。

char* str="hello";
struct s_test *ptest = (struct s_test*)malloc(sizeof(s_test)+streln(str)+1);
strcpy(ptest+1,str);

(char*)(ptest + 1)就是字符串“hello”的地址

2.柔性数组原型

上例中p成了多余的东西,可以去掉。

但是,又产生了另外一个问题:老是使用(char*)(ptestt + 1)不方便。如果能够找出一种方法,既能直接引用该字符串,又不占用结构体的空间,就完美了,符合这种条件的代码结构应该是一个非对象的符号地址,在结构体的尾部放置一个0长度的数组是一个绝妙的解决方案。不过,C/C++标准规定不能定义长度为0的数组,因此,有些编译器就把0长度的数组成员作为自己的非标准扩展,例如:

typedef struct s_test  
{
int a;
double b;
char c[0];
};

c就叫柔性数组成员,如果把ptest指向的动态分配内存看作一个整体,c就是一个长度可以动态变化的结构体成员,柔性一词来源于此。c的长度为0,因此它不占用test的空间,同时ptest->c就是“hello world”的首地址,不需要再使用(char*)(ptestt + 1)这么丑陋的语法了。

C99使用不完整类型实现柔性数组成员,标准形式是这样的:

struct s_test 
{
int a;
double b;
char c[];
};

c同样不占用test的空间,只作为一个符号地址存在,而且必须是结构体的最后一个成员

完整实验一:

#include <stdlib.h>
#include <string.h>
struct line
{ int length; char contents[0]; };// C99的玩法是:char contents[]; 没有指定数组长度
int main(int argc, char *argv[])
{
int this_length=10;
struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
memset(thisline->contents, 'a', this_length);
printf("%s",thisline->contents);


return 0;
}

实验结果为:aaaaaaaaaa

上面这段代码的意思是:我想分配一个不定长的数组,于是我有一个结构体,其中有两个成员,一个是length,代表数组的长度,一个是contents,代码数组的内容。后面代码里的 this_length(长度是10)代表是想分配的数据的长度。