C 語言函數不能直接返回數組類型 (數組退化為指針,且局部數組生命週期隨函數結束而終止)。必須通過以下三種標準方案之一實現:
#define ROWS 3
#define COLS 4
typedef struct {
int data[ROWS][COLS];
} Matrix;
Matrix create_matrix(void) {
Matrix m = {0}; // 零初始化
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
m.data[i][j] = i * COLS + j; // 示例填充
return m; // 結構體按值返回 (C99 保證支持,現代編譯器優化為 NRV/RVO)
}
int main(void) {
Matrix mat = create_matrix();
printf("%d\n", mat.data[1][2]); // 訪問元素
return 0;
}
優點:語義清晰、類型安全、無內存管理負擔、可直接賦值/傳參/返回。
限制:編譯期確定維度、大對象返回可能有拷貝開銷 (現代編譯器優化消除)。
void fill_matrix(int rows, int cols, int (*mat)[cols]) { // VLA 參數 (C99) 或 int **mat
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
mat[i][j] = i * cols + j;
}
// 靜態分配版
int main(void) {
int mat[3][4];
fill_matrix(3, 4, mat);
printf("%d\n", mat[1][2]);
return 0;
}
// 動態分配版 (堆上,維度運行期決定)
int **alloc_matrix(int rows, int cols) {
int **mat = malloc(rows * sizeof(int*));
mat[0] = malloc(rows * cols * sizeof(int)); // 連續內存
for (int i = 1; i < rows; ++i) mat[i] = mat[0] + i * cols;
return mat;
}
void free_matrix(int **mat) { free(mat[0]); free(mat); }
優點:無拷貝、支持動態維度、調用者控制生命週期。
注意:VLA (Variable Length Array) 參數需 C99 支持,MSVC 不支持;動態分配需成對 free。
// 返回連續內存二維數組指針 (int (*)[cols])
int (*create_matrix_dyn(int rows, int cols))[cols] { // C99 返回 VLA 指針
int (*mat)[cols] = malloc(rows * sizeof(*mat));
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
mat[i][j] = i * cols + j;
return mat;
}
// 或者返回 int** (非連續,靈活但訪問慢)
int **create_matrix_ptr(int rows, int cols) {
int **mat = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; ++i) mat[i] = malloc(cols * sizeof(int));
// 填充...
return mat;
}
風險:調用者**必須**記住 free,易洩漏。現代 C 推薦方案二 (調用者分配) 或方案一 (結構體)。
| 方案 | 適用場景 | 內存管理 | 類型安全 | 性能 | 可移植性 |
|---|---|---|---|---|---|
| 結構體封裝 | 中小固定維度、值語義 | 自動 (棧/寄存器) | 最高 | 極快 (NRV) | C89+ 完美 |
| 調用者分配+填充 | 大數組、動態維度、高性能 | 調用者控制 (棧/堆) | 高 (VLA 指針) | 零拷貝最快 | C99 VLA / 手動 int** |
| 函數內分配返回指針 | 工廠模式、插件接口 | 調用者負責 free | 中 (易誤用) | 分配開銷 | C89+ 但易出錯 |