首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言函數返回數組的兩種正確姿勢:指針返回與結構體封裝

     編輯:關於C

C語言中數組不是一級類型,不能直接作為函數返回值(會退化為指針且指向棧上失效內存)。本文詳解兩種標準解決方案:返回指向動態分配數組的指針與封裝在結構體中返回,附帶內存管理陷阱與現代C++替代方案。

為什麼不能直接返回數組


int* bad_func() {
    int arr[10] = {1,2,3}; // 棧上數組
    return arr;            // 錯誤:返回棧地址,函數結束後內存失效
}
  • 函數參數/返回值中的int arr[]、int arr[10]均調整為int*
  • 棧上數組生命周期隨函數結束終止,返回指針成懸垂指針
  • 靜態數組static int arr[10]可返回但不可重入、非線程安全

方案一:返回指向動態數組的指針

正確聲明語法


// 返回指向「含10個int的數組」的指針
int (*func())[10];  // 函數聲明
int (*p)[10] = func(); // 接收變量

int (*)[10]是「指向int[10]的指針」類型,不可寫作int*[10](那是指針數組)。

完整實現


#include 
#include 

// 返回指向10個int數組的指針
int (*create_array())[10] {
    // 1. 動態分配:一個int[10]數組
    int (*arr)[10] = calloc(1, sizeof(int[10])); // 或 malloc(sizeof(int[10]))
    if (!arr) return NULL;
    
    // 2. 初始化
    for (int i = 0; i < 10; i++) {
        (*arr)[i] = i * i; // 注意解引用優先級:(*arr)[i]
    }
    return arr;
}

int main() {
    int (*result)[10] = create_array();
    if (!result) return 1;
    
    printf("第3個元素: %d\n", (*result)[3]); // 輸出 9
    
    free(result); // 必須釋放!指針指向單塊內存
    return 0;
}

關鍵點總結

多維數組擴展


// 返回指向 3x4 int 數組的指針
int (*create_2d())[3][4] {
    int (*arr)[3][4] = malloc(sizeof(int[3][4]));
    // 初始化 (*arr)[i][j] = ...
    return arr;
}

// 使用
int (*mat)[3][4] = create_2d();
printf("%d\n", (*mat)[1][2]);
free(mat);

方案二:結構體封裝返回(值語義,無需手動釋放)

實現


#include 

typedef struct {
    int data[10];
} IntArray10;

IntArray10 create_array() {
    IntArray10 arr;
    for (int i = 0; i < 10; i++) {
        arr.data[i] = i * i;
    }
    return arr; // 結構體按值返回(複製)
}

int main() {
    IntArray10 arr = create_array();
    printf("第3個元素: %d\n", arr.data[3]); // 直接訪問,無指針
    return 0; // 自動銷毀,無內存洩漏風險
}

優缺點對比

環節要點
分配calloc(1, sizeof(int[10]))或malloc(sizeof(int[10])),分配整個數組塊
訪問(*arr)[i]先解引用指針得數組,再下標
返回直接返回指針arr(類型int(*)[10])
接收同類型變量int (*p)[10]
釋放free(p),單次分配對應單次釋放
錯誤處理檢查分配返回NULL

現代 C++ 最佳替代方案

1. std::array (C++11,固定大小,棧上,值語義)


#include 
#include 

std::array create_array() {
    std::array arr;
    for (int i = 0; i < 10; i++) arr[i] = i * i;
    return arr; // 移動語義/複製消除,零開銷
}

int main() {
    auto arr = create_array();
    std::cout << arr[3] << '\n'; // 9
}

2. std::vector (動態大小,堆上,RAII)


#include 

std::vector create_array(int n) {
    std::vector vec(n);
    for (int i = 0; i < n; i++) vec[i] = i * i;
    return vec; // 移動語義,無拷貝開銷
}

3. 智能指針管理動態數組 (C++11)


#include 

std::unique_ptr create_array(int n) {
    auto arr = std::make_unique(n);
    for (int i = 0; i < n; i++) arr[i] = i * i;
    return arr; // 所有權轉移,自動釋放
}

常見誤區避坑指南

維度指針返回結構體返回
內存管理手動malloc/free,易洩漏/雙重釋放自動棧管理,RAII友好
性能單次分配,返回指針極快涉及結構體複製(大數組開銷大)
大小靈活性運行時決定大小編譯期固定大小
線程安全各調用獨立分配,天然安全各調用獨立棧幀,天然安全
適用場景大數組、動態大小、C語言小固定數組、C++、性能非瓶頸

總結選型建議

  • C語言、固定小數組:結構體封裝,簡單安全
  • C語言、大數組/動態大小:返回int(*)[N]指針,malloc/free配對
  • C++11+、固定大小:std::array,零開銷抽象
  • C++11+、動態大小:std::vector或std::unique_ptr<T[]>
  • 跨語言接口/ABI穩定:輸出參數void func(T* out, size_t* len)或C風格指針+長度

理解「數組非一級類型」的本質限制,選擇合適的封裝策略,是C/C++資源管理正確性的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
誤區代碼問題正確寫法
int* f() { int a[10]; return a; }返回棧地址動態分配或結構體/標準容器
int (*f())[10] { int a[10]; return &a; }同樣返回棧地址malloc/calloc分配
int* f() { return malloc(10*sizeof(int)); }類型不匹配,丟失大小信息返回int(*)[10]或用結構體
int (*p)[10] = malloc(...); p[0][3] = 5;解引用錯誤(*p)[3] = 5;
忘記free內存洩漏配對free,或用RAII容器