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 <stdio.h>
#include <stdlib.h>

struct line {
         int length;
         char test;
         char contents[0];//or <span style="font-family: Arial, Helvetica, sans-serif;">char contents[];</span>
    };

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;
}

运行效果:

update:2015-4-8
FlexibleArray2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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;
}


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

FlexibleArray3.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

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

    return 0;
}


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


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值