弹性数组

创建

最近在学习 Linux 的 inotify 系统调用时,有个结构体给我看懵了:

struct inotify_event {
   int      wd;       /* Watch descriptor */
   uint32_t mask;     /* Mask describing event */
   uint32_t cookie;   /* Unique cookie associating related events (for rename(2)) */
   uint32_t len;      /* Size of name field */
   char     name[];   /* Optional null-terminated name */
};

前面的还好说,主要是这个 name 字段,这是一个数组却又没有指定长度,那么编译器在编译的时候到底会给他分配多少内存呢?
后来查了下资料,这叫弹性数组,编译期不分配栈上内存,通常由用户在运行时根据需求在堆上分配内存。

具体怎么用呢?

按需申请堆内存分配

struct my_data {
    int a;
    int b;
    char c[];
};

    struct my_data *m = (struct my_data *)malloc(sizeof(struct my_data) + 6 * sizeof(char));
    m->c[0] = 'h';
    m->c[1] = 'e';
    m->c[2] = 'l';
    m->c[3] = 'l';
    m->c[4] = 'o';
    m->c[5] = 0x0;

    printf("m->c = %s\n", m->c);
    // m->c = hello

为什么这么设计呢?

我们先来看看假如不使用弹性数组会发生什么。
有一个结构体,包含一个类型为 char[] 的可选字段,假如不使用弹性数组,那么我有两种方式来创建结构体:

// 第一种
struct my_data {
    int a;
    int b;
    char c[100];
};

// 第二种
struct my_data {
    int a;
    int b;
    char *c;
};

第一种是按最大长度分配内存,好处是使用方便,坏处是不管有没有用到该字段都要分配 100 个字节,浪费内存。
第二种方式是结构体保存一个指针,好处是清晰明了,坏处是:

  1. 虽比第一种节省内存,但仍然要给指针分配内存
  2. 内存可能不连续,导致读取效率下降
  3. 如果 c 字段是从 malloc 分配而来的,在 free 结构体的时候容易忘掉要 free 字段 c 从而导致内存泄漏

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

苏ICP备2023046324号-1