若函式參數是指標,在函式內對該指標重新分配記憶體 (malloc),無法影響呼叫端的原始指標。
void GetMemory(char *p, int num) {
p = (char*)malloc(sizeof(char) * num); // 修改區域副本 _p
}
void Test() {
char *str = NULL;
GetMemory(str, 100); // str 仍為 NULL
strcpy(str, "hello"); // 崩潰
}
原因:編譯器建立參數副本 _p,函式內修改 _p 指向,原 p (即 str) 不變。且每次調用洩漏一塊記憶體。
void GetMemory2(char **p, int num) {
*p = (char*)malloc(sizeof(char) * num); // 解引用修改原指標值
}
void Test2() {
char *str = NULL;
GetMemory2(&str, 100); // 傳入 str 位址
strcpy(str, "hello");
free(str);
}
char *GetMemory3(int num) {
char *p = (char*)malloc(sizeof(char) * num);
return p;
}
void Test3() {
char *str = GetMemory3(100);
strcpy(str, "hello");
free(str);
}
char *GetString() {
char p[] = "hello world"; // 區域陣列在堆疊
return p; // 警告:回傳區域變數位址
}
void Test4() {
char *str = GetString(); // str 指向已銷毀記憶體,內容為垃圾值
}
char *GetString2() {
char *p = "hello world"; // 指向常數區 (或用 static/malloc)
return p; // 安全
}
assert(p != NULL) 或 if(p==NULL)。malloc/free、new/delete 次數嚴格對等。free(p); p = NULL; 杜絕野指標。陣列作參數時退化為指標,sizeof 失效。若需在函式內得知陣列大小,必須額外傳遞長度參數,或使用結構體包裹。
指標參數傳遞記憶體的本質是「值傳遞指標值」。要修改呼叫端指標指向,必須傳遞指標的位址 (雙重指標) 或利用回傳值。堅決杜絕回傳堆疊位址,嚴守釋放即置 NULL,是 C 程式設計師的職業素養。