C的0长数组

来源:互联网 发布:python 开发网站 编辑:程序博客网 时间:2024/05/07 17:05

[原文]http://hi.baidu.com/bmrs/blog/item/83561e00605c13db267fb555.html

一、零长数组

    在标准 C 或者 C++ 中由于不支持 0 长度的数组,所以 int array[0]; 这样的定义是非法的。不过有些编译器(如GCC)的扩展功能支持 0 长度的数组。

    在 C 中,0 长度的数组的主要用途是用来作为结构体的最后一个成员,然后用它来访问此结构体对象之后的一段内存(通常是动态分配的内存)。由于其非标准性,在程序中尽量避免使用 0 长度的数组。作为替换,可以使用 C99 标准中的不完整数组来替换 0 长度的数组定义。如:

        typedef struct _X {
            int a;
            char array[]; //注意,因为是不完整数组,因此不可以计算sizeof(X),无法编译通过
        } X;

    在GNU的gcc-4.4.0的官方指南中的5.14节Arrays of Length Zero一节中,它是如此写道:

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

        //...ommit code here

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

    这个用法主要用于变长Buffer,struct line的大小为4,结构体中的contents[0]不占用任何空间,甚至是一个指针的空间都不占(待会儿下面的示例代码会验证),contents在这儿只是表示一个常量指针,这个特性是用编译器来实现的,即在使用thisline->contents的时候,这个指针就是表示分配内存地址中的某块buffer,比如malloc (sizeof (struct line) + this_length)返回的是0x8f00a40,thisline->contents指向的位置就是(0x8f00a40 + sizeof(struct line)),而这儿sizeof(struct line)仅仅是一个int的四字节。

    对于这个用法,我们定义的结构体指针可以指向任意长度的内存buffer,这个技巧在变长buffer中使用起来相当方便。可能有朋友说,为什么不把最后的contents直接定义为一个指针呢?这儿的差别是这样的,如果定义为一个指针,它需要占用4Bytes,并且在申请好内存后必须人为赋地址才可以。如果使用这个用法,这个常量指针不占用空间,并且无需赋值。

     [以下内容原创]
     如果是这样定义结构体
     struct line{
               int length;
               char *pContents;
     }
     企图用pContents来保存新分配内存空间的地址,在程序中这样使用:
     struct line *p = (struct line*)malloc(sizeof(struct line));
     p->pContents = (char *)malloc(100);
     那么释放内存的时候要释放两次,先是free(p->pContents)再是free(p)。
     而如果是
     struct line{
               int length;
               char contents[0];//或者使用char contents[];这个或许会更好一些
     }
     一开始我可以分配一块大大的内存空间,struct line *p = (struct line*)malloc(sizeof(struct line) + 100);contents指向了那块未使用的100个字节的内存。释放的时候直接free(p)就好了。