C 語言原生不支援真正的二維陣列,所謂「二維陣列」實為「陣列的陣列」。靜態宣告 int a[10][20] 編譯期即固定大小,若需依執行期輸入決定維度,必須動態配置記憶體。本文介紹高效、通用的單一記憶體區塊配置法,避免傳統指標陣列逐列 malloc 造成的記憶體碎片與釋放麻煩。
對 p[i][j],編譯器轉換為 *(*(p+i)+j):
p+i:計算第 i 列指標*(p+i):取得該列首元素位址(指標)*(p+i)+j:計算第 j 個元素位址*(*(p+i)+j):取值因此,我們只需配置一個指標陣列(列指標),再配置一塊連續記憶體存放所有元素,將列指標指向對應位移即可。
typedef unsigned char MK_Byte;
#define SUCCESS 0
#define MFAILED 1
#define MNOMEMORY 2
// 宣告巨集:確保初始化為 NULL
#define DeclareTwoDArray(ATYPE, iname) ATYPE ** iname = NULL
// 記憶體操作巨集:便於移植與除錯
#define MKMALLOC(nsize) malloc(nsize)
#define MKFREE(name) \
if (NULL != name) { \
free(name); \
name = NULL; \
}
int MKCreatArray(int nsize, int X, int Y, void ***parray) {
void **tdarray = NULL; // 列指標陣列
MK_Byte *tmparray = NULL; // 實際資料區塊
int i = 0;
*parray = NULL;
// 1. 配置列指標陣列 (Y 個指標)
if (!(tdarray = (void **)MKMALLOC(sizeof(MK_Byte *) * Y)))
return MNOMEMORY;
// 2. 配置連續資料區塊 (X*Y 個元素)
if (!(tmparray = (MK_Byte *)MKMALLOC(nsize * X * Y))) {
MKFREE(tdarray);
return MNOMEMORY;
}
// 3. 歸零初始化
memset(tmparray, 0x00, nsize * X * Y);
// 4. 設定列指標指向正確位移
for (i = 0; i < Y; i++)
tdarray[i] = tmparray + (i * X) * nsize;
*parray = tdarray;
return SUCCESS;
}
void MKFreeArray(void ***parray) {
if (*parray) {
MKFREE((*parray)[0]); // 釋放資料區塊
MKFREE(*parray); // 釋放指標陣列
}
}
void testTwoDArray() {
DeclareTwoDArray(int, a);
DeclareTwoDArray(float, b);
// 建立 3行 x 2列 int 陣列
MKCreatArray(sizeof(int), 3, 2, &a);
a[1][2] = 10; // 注意:索引 0-based,此處為第 2 行第 3 列
a[0][1] = 23;
printf("%d,%d\n", a[1][2], a[0][1]);
MKFreeArray(&a);
// 重新配置 6x6
MKCreatArray(sizeof(int), 6, 6, &a);
a[5][5] = 234;
a[4][0] = 567;
printf("%d,%d\n", a[5][5], a[4][0]);
MKFreeArray(&a);
// 建立 float 陣列
MKCreatArray(sizeof(float), 2, 2, &b);
b[0][0] = 0.5f;
b[1][1] = 0.006f;
printf("%g,%g\n", b[0][0], b[1][1]);
MKFreeArray(&b);
}
| 特性 | 傳統逐列 malloc | 本文單一區塊法 |
|---|---|---|
| 記憶體碎片 | 多,易造成外部碎片 | 無,單一連續區塊 |
| 快取效能 | 差,資料分散 | 優,空間局部性佳 |
| 釋放複雜度 | 需迴圈逐列 free | 兩次 free 完成 |
| 型別通用性 | 需為每型別寫函數 | void** 通用,支援任意型別 |
| 錯誤處理 | 部分配置失敗難回滾 | 失敗自動釋放已配置區塊 |
MKCreatArray(sizeof(type), 欄數X, 列數Y, &ptr),X 對應第二維度(行),Y 對應第一維度(列)a[0..Y-1][0..X-1],切勿越界double),建議配置時對齊至 8 位元組邊界malloc,可改用靜態記憶體池實作相同介面單一記憶體區塊配合指標陣列,是 C 語言實作動態二維陣列的最佳實踐:效能高、釋放簡單、型別通用。提供的 MKCreatArray/MKFreeArray 組合可直接納入專案,解決動態矩陣配置痛點。