C言語における柔軟配列(Flexible Array Member)の活用と利点

C言語では、malloccallocrealloc といった関数を用いてヒープ領域に動的メモリを確保できます。これらに関連する特殊なデータ構造として、「柔軟配列(Flexible Array Member)」があります。

柔軟配列は、構造体の末尾に要素数を明示せずに宣言される配列です。以下のように定義します:

struct Data {
    int header;
    char flag;
    int payload[];  // 柔軟配列(C99以降で標準化)
};

この payload[] は通常の配列とは異なり、構造体定義内ではサイズが指定されません。実際のメモリは、構造体本体と柔軟配列の領域をまとめて動的に確保します。

メモリ確保と使用例

10個の整数を格納できる柔軟配列を持つ構造体を確保するには、次のようにします:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

struct Data {
    int header;
    char flag;
    int payload[];
};

int main(void) {
    size_t count = 10;
    struct Data *obj = malloc(sizeof(struct Data) + count * sizeof(int));
    if (!obj) {
        fprintf(stderr, "Allocation failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    obj->header = 42;
    obj->flag = 'X';
    for (size_t i = 0; i < count; ++i) {
        obj->payload[i] = (int)(i + 1);
    }

    printf("Header: %d, Flag: %c\n", obj->header, obj->flag);
    for (size_t i = 0; i < count; ++i) {
        printf("%d ", obj->payload[i]);
    }
    putchar('\n');

    free(obj);
    return EXIT_SUCCESS;
}

サイズ変更の例

必要に応じて、realloc を使って柔軟配列のサイズを拡張できます:

    // 初期確保
    struct Data *obj = malloc(sizeof(struct Data) + 10 * sizeof(int));
    // ... 初期化 ...

    // サイズを20要素に拡張
    struct Data *tmp = realloc(obj, sizeof(struct Data) + 20 * sizeof(int));
    if (!tmp) {
        free(obj);
        fprintf(stderr, "Reallocation failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }
    obj = tmp;

    // 新しい要素を初期化
    for (size_t i = 10; i < 20; ++i) {
        obj->payload[i] = (int)(i + 1);
    }
    // ... 使用後 free(obj);

柔軟配列の利点

柔軟配列を使わずに同様の機能を実現する場合、構造体内にポインタを置き、別途配列用のメモリを確保する方法が考えられます:

struct Alternative {
    int header;
    char flag;
    int *payload;  // ポインタ
};

この場合、メモリ解放時に payload と構造体本体の両方を個別に free する必要があります。順序を誤ると未定義動作やメモリリークを引き起こす可能性があります。

一方、柔軟配列は単一の malloc 呼び出しで構造体と配列を連続したメモリ上に配置するため、以下の利点があります:

  1. メモリ管理が簡潔:解放は一度の free で済む。
  2. メモリの局所性が高い:構造体とデータが物理的に近接しており、キャッシュ効率が向上する。
  3. フラグメンテーションの低減:複数回の malloc を避けることで、ヒープの断片化を抑制できる。

これらの特性により、柔軟配列はパフォーマンスやコードの信頼性が求められる場面で有用です。

タグ: C言語 柔軟配列 動的メモリ メモリ管理 構造体

7月7日 18:26 投稿