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

C 指標進階:GetMemory 經典面試題深度剖析與記憶體管理陷阱

     編輯:關於C語言

為什麼 GetMemory(str) 無法修改指標?

這是 C 語言指標教學中最經典的「坑」:指標本身也是變數,傳遞給函數時是「傳值呼叫」,函數內部修改的是副本,不影響原指標。

錯誤示範:一級指標傳遞

void GetMemory(char *p) {
    p = (char*)malloc(100); // 修改區域副本 p
}
int main() {
    char *str = NULL;
    GetMemory(str); // str 仍為 NULL
    strcpy(str, "Hello"); // 崩潰:解參考空指標
}

記憶體圖解:

  • str 位於 0x0012ff7c,值 0 (NULL)
  • 呼叫 GetMemory 時,參數 p 另闢棧框 0x0012ff2c,複製 str 的值 0
  • malloc 回傳 0x00372b70 存入 p,str 完全不知情
  • 函數返回,p 銷毀,str 依然 NULL

正解:二級指標(指標的指標)

void GetMemory(char **p) {
    *p = (char*)malloc(100); // 透過解參考修改原指標
}
int main() {
    char *str = NULL;
    GetMemory(&str); // 傳遞 str 的位址
    strcpy(str, "Hello"); // 正常運作
    free(str); // 記得釋放!
}

關鍵差異:p 指向 str 的位址(0x0012ff7c),*p 即 str 本身,修改 *p 等同修改 str。

更多變體與陷阱

程式碼片段結果原因
void GetMemory(char **p) { p = malloc(100); }編譯錯誤無法將 char* 指派給 char**
p = (char**)malloc(100);編譯通過,執行崩潰強制轉型掩蓋型別錯誤,實際寫入錯誤位址
void GetMemory(char *p) { p = malloc(100); }
GetMemory(&str);
編譯錯誤char** 不能隱式轉為 char*

其他常見記憶體錯誤模式

// 1. 回傳區域陣列指標(棧記憶體函數返回即失效)
char *GetMemory2(void) {
    char p[] = "hello world";
    return p; // 錯誤:p 位於棧上
}

// 2. 回傳字串常數(安全:存放於唯讀資料段)
char *GetMemory3(void) {
    return "hello world"; // 正確:靜態儲存期
}

// 3. 釋放後仍使用(野指標)
void Test5(void) {
    char *str = malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL) { // 錯誤:free 不會將指標設為 NULL
        strcpy(str, "world"); // 未定義行為
    }
}

// 4. 指標位移後釋放(必須釋放原始位址)
void Test6(void) {
    char *str = malloc(100);
    strcpy(str, "hello");
    str += 6; // 指標移動
    free(str); // 錯誤:傳遞非 malloc 回傳位址
}

最佳實務檢核表

  1. 需修改呼叫端指標 → 使用二級指標 **ptr 或回傳新指標
  2. malloc 後檢查 NULL
  3. free 後立即將指標設為 NULL,防止二次釋放/野指標
  4. 指標運算後保留原始位址供 free 使用
  5. 區域陣列/變數位址絕不回傳或長期保存
  6. 字串常數屬唯讀區,不可修改

指標是 C 語言的靈魂也是地雷區。記住核心原則:誰配置,誰釋放;傳址才能修改原變數;記憶體區塊生命週期決定指標有效性。

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