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 的值 0malloc 回傳 0x00372b70 存入 p,str 完全不知情p 銷毀,str 依然 NULLvoid 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); } | 編譯錯誤 | 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 回傳位址
}
**ptr 或回傳新指標malloc 後檢查 NULLfree 後立即將指標設為 NULL,防止二次釋放/野指標free 使用指標是 C 語言的靈魂也是地雷區。記住核心原則:誰配置,誰釋放;傳址才能修改原變數;記憶體區塊生命週期決定指標有效性。