現代 C (C11/C17/C23)

彈性陣列成員(flexible array member)

/ FLEK-suh-bul /

假設你想用一次配置容納一個小型標頭,緊接其後是數量可變的位元組——把長度與資料打包在一起。在 C99 之前,人們用「結構技巧(struct hack)」造假:宣告一個大小為 1 的末尾陣列再超額配置。C99 把它正式化:彈性陣列成員是一個「沒有大小」、宣告為結構「最後」成員的陣列,例如 char data[]。

你只能把它宣告為最後一個成員,例如 struct buf { size_t len; char data[]; };。彈性成員對 sizeof(struct buf) 沒有貢獻(sizeof 計算時把 data 當作長度為零)。你用單一 malloc 配置標頭加上所需任意數量元素的空間:malloc(sizeof(struct buf) + n) 給你一個結構,其 data 陣列可從索引 0 用到 n-1。這把標頭與酬載打包進一次配置,只需一次 free() 就能釋放兩者。

它對網路封包、可變長度記錄、以及快取友善的單次配置容器很有用。誠實的提醒:彈性陣列成員必須是「最後」一個成員,且結構必須至少還有一個其他成員;你不能做這種結構的「陣列」,也不能把它嵌入另一個結構內;而且你必須自己配置額外空間——一個純區域變數 'struct buf b;' 給 data 的可用元素恰為零,所以寫入 b.data 是越界的未定義行為。

struct buf { size_t len; char data[]; }; // data[] 是彈性成員 size_t n = 100; struct buf *b = malloc(sizeof *b + n); // 標頭 + 100 位元組,一次配置 b->len = n; b->data[0] = 'H'; // 索引 0..n-1 有效 free(b); // 一次 free 釋放兩者

sizeof 忽略 data[];你 malloc 標頭加上自選長度,一次 free 釋放整個區塊。

它必須是「最後」一個成員,而且你必須超額配置;沒有額外 malloc 空間的彈性陣列成員可用元素為零,所以對它索引就是越界的未定義行為。

又稱
FAMthe struct hack done right結構末尾可變長陣列