铅笔

在你的害怕中坚持的越多,你就会越自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

柔性数组

Posted on 2018-04-09 19:47  黑色の铅笔  阅读(200)  评论(0编辑  收藏  举报

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)代表是想分配的数据的长度。

 

原文:http://www.jb51.net/article/54960.htm