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

C語言結構體參數傳遞陷阱與正確姿勢完整指南

     編輯:關於C

問題場景

函式 GetEmployeeInfo 需填充員工資訊結構體:

typedef struct {
    char szEmployeeName[100];
    unsigned short iEmployeeAge;
    unsigned int iEmployeeNo;
} TEmployeeInfo;

int GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo);

錯誤嘗試 1:傳遞未初始化指標

int main() {
    TEmployeeInfo *ptEmployeeInfo = NULL;
    GetEmployeeInfo(ptEmployeeInfo);  // 函式內檢查 NULL 直接返回失敗
    // 印出垃圾值或崩潰
}

指標為 NULL,函式無法寫入,調用者得到未初始化記憶體。

錯誤嘗試 2:主函式先填充再傳遞指標

int main() {
    TEmployeeInfo *ptEmployeeInfo = NULL;
    // 直接對 NULL 指標解引用賦值 → 段錯誤
    strcpy(ptEmployeeInfo->szEmployeeName, "Di Renjie");  // 崩潰!
    GetEmployeeInfo(ptEmployeeInfo);
}

對 NULL 指標解引用直接導致 SIGSEGV。即使分配了記憶體,若函式內再次分配或修改指標指向,會造成記憶體洩漏或雙重釋放風險。

正確姿勢:傳遞結構體位址(非指標變數)

int main() {
    TEmployeeInfo tEmployeeInfo = {0};  // 棟疊分配,自動初始化為 0
    int ret = GetEmployeeInfo(&tEmployeeInfo);  // 傳遞位址
    if (ret == 0)
        printf("姓名:%s 年齡:%d 工號:%d\n",
               tEmployeeInfo.szEmployeeName,
               tEmployeeInfo.iEmployeeAge,
               tEmployeeInfo.iEmployeeNo);
    return 0;
}

int GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo) {
    if (!ptEmployeeInfo) return -1;  // 防禦性檢查
    strcpy(ptEmployeeInfo->szEmployeeName, "Li Yuanfang");
    ptEmployeeInfo->iEmployeeAge = 100;
    ptEmployeeInfo->iEmployeeNo = 123456;
    return 0;
}

核心原則總結

  1. 調用者負責分配記憶體(棟疊/靜態/堆),傳遞位址給函式填充。
  2. 函式不應分配/釋放調用者傳入的記憶體,也不應修改指標本身(指標按值傳遞,修改不影響調用者)。
  3. 防禦性檢查: 函式入口驗證指標非 NULL。
  4. 棟疊分配優先: 簡單、自動管理生命週期、無洩漏風險。大型結構體或需跨函式生命週期時再用堆。
  5. 初始化習慣: 定義變數即初始化(= {0} 或指定欄位),避免未初始化讀取。

進階:輸出參數模式

若函式需返回多個無關資料,可用多個輸出參數:

void GetEmployeeInfo(char *name, int *age, int *no);  // 調用者提供緩衝區
// 或
typedef struct { char name[100]; int age; int no; } EmpOut;
int GetEmployeeInfo(EmpOut *out);  // 結構體作為輸出載體

避免返回指向區域變數/靜態變數/動態記憶體的指標(除非明確文檔所有權轉移)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved