C语言0长度数组(柔性数组)


0长度数组,又称为柔性数组(flexible array),通常用来实现变长数组,常见于TLV(type-length-value)的数据结构中。 在标准 C 和 C++ 中,不允许用 0 长度数组,但在 GNU C 中,却可以定义 0 长度数组(在C99之前写成长度为0,C99中可以直接不写索引)。通常会拿手册中给的例子来说明
struct line {
         int length;
         char contents[0]; // char contents[]; //C99
}


从打印出来的结构体尺寸 sizeof (struct line) = 4 (和编译器有关,看内存对齐规则),可以看到contents[0]不占有空间(不同于字符指针类型),它存在的好处是在结构体的后面允许我们自己申请一定大小的存储空间,而不是每次都使用 MAX_SIZE 大小的结构体。通常的使用方法如下:

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

通过测试代码可以发现:为0长度数组分配的空间紧跟着该该结构体最后一个字段之后,而且释放结构体指针后,我们自己分配的空间也会释放(不同于有些网上的说法)。所以需要注意的是我们释放的是由某个指针指向的内存空间,而非指针,指针变量是在程序结束后回收的,所以在我们释放一段内存之后要将其置为NULL,否则还是可以访问的,不过访问到的都是垃圾数据。


测试代码:FlexibleArray.c
#include 
#include 

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

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

    printf ("thisline addr is %p\n", thisline);
    printf ("thisline->length field value is %d\n",thisline->length);
    printf ("thisline->length field addr is %p\n", &thisline->length);
    printf ("thisline->test field addr is %p\n", &thisline->test);
    printf ("thisline->contents field addr is %p\n", &thisline->contents);
    printf ("thisline->contents[0] addr is %p\n", &thisline->contents[0]);
    printf ("thisline->contents[0] addr is %p\n", &thisline->contents[1]);

    for(i=0; i<3; i++){
        thisline->contents[i] = 'a' + i;
    }
    
    char *p = thisline->contents;
    printf("%c\n", p[2]);
    
    free(thisline);
    //After free , when we access the space ,we got garbage data;
    printf("%d\n", thisline->length);
    printf("%c\n", p[2]);

    return 0;
}

运行效果:
C语言0长度数组(柔性数组)_第1张图片
update:2015-4-8
FlexibleArray2.c
#include 
#include 
#include 

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

int main(){
    int i;
    char s[20] = "Hello World.";
    int that_length = 60;
    struct line thisline = {5, 'A', {'a', 'b', 'c'}};

    struct line *thatline = malloc(sizeof(struct line) + that_length);
    thatline->length = that_length;
    for(i=0; i<3; i++){
        thatline->contents[i] = 'A' + i;
    }


    char *p = thatline->contents;
    printf("%c\n", p[2]);

    free(thatline->contents);
   thatline->contents = thisline.contents;
// error: incompatible types when assigning to type ‘char[]’ from type ‘char *’
    p = thatline->contents;
   printf("%c\n", p[2]);

    return 0;
}
C语言0长度数组(柔性数组)_第2张图片

可以看到根本无法修改一个实例中contents的指向,所以占用的是完整的内存区间,不能指向单独的地址空间。

FlexibleArray3.c
#include 
#include 
#include 

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

int main(){
    struct line thisline = {5, 'A', {'a', 'b', 'c'}};

    return 0;
}


可以看到严格的弹性数组和长度0的数组还是有区别的,这里就不能使用静态初始化,只能像FlexibleArray1.c中那样操作。


你可能感兴趣的:(Linux环境编程)