- return語句不可返回指向“棧記憶體”的“指標”或者“引用”,因為該記憶體在函數體結束時被自動銷毀。
char * Func(void)
{
char str[] = "hellow world";
// str的記憶體位於棧上
return str; // 將導致錯誤
}
void Test4(void)
{
char *str = NULL;
str = GetString();
// str 的內容是垃圾
cout<< str << endl;
}
儘管str指向的地址任然是在Func函數中指向“hellow world”的地址,但是當函數結束後指標指向的內容已經被銷毀。
char *GetMemory(int num)
{
char *p = (char *)malloc(sizeof(char)*num);
return p;
}
void main(void)
{
char *str = NULL;
str = GetMemory(100);
strcpy(str, "hello world!");
cout < < str < < endl;
free(str);str = NULL;
}
這個例子中p是指向堆的記憶體指標。在C中通過malloc分配的記憶體都是指向堆的。malloc或new動態申請的記憶體是堆上的記憶體
如果函數的參數是一個指標,不要指望用該指標去申請動態記憶體。樣本1 中,Test 函數的語句GetMemory(str, 200)並沒有使str 獲得期望的記憶體,str 依舊是NULL,為什嗎?
/*================樣本1==========================*/
void GetMemory(char *p,
int num)
{
p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
char *str = NULL;
GetMemory(str, 100);
// str 仍然為 NULLstrcpy(str, "hello");
// 運行錯誤
}
毛病出在函數GetMemory 中。編譯器總是要為函數的每個參數製作臨時副本,指標參數p 的副本是 _p,編譯器使 _p = p。如果函數體內的程式修改了_p 的內容,就導致參數p 的內容作相應的修改。這就是指標可以用作輸出參數的原因。在本例中,_p 申請了新的記憶體,只是把_p 所指的記憶體位址改變了,但是p 絲毫未變。所以函數GetMemory並不能輸出任何東西。事實上,每執行一次GetMemory
就會泄露一塊記憶體,因為沒有用free 釋放記憶體。如果非得要用指標參數去申請記憶體,那麼應該改用“指向指標的指標”,
見樣本2。
void GetMemory2(char **p,
int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
char *str = NULL;
GetMemory2(&str, 100);
// 注意參數是 &str,而不是strstrcpy(str, "hello");
cout<< str << endl;
free(str);
}
由於“指向指標的指標”這個概念不容易理解,我們可以用函數傳回值來傳遞動態記憶體。這種方法更加簡單,見樣本3。
/*======================樣本3=================================*/
char *GetMemory3(int num)
{
char *p = (char *)malloc(sizeof(char) * num);
return p;
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3(100);
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
樣本3 用函數傳回值來傳遞動態記憶體用函數傳回值來傳遞動態記憶體這種方法雖然好用,但是常常有人把return 語句用錯
了。這裡強調不要用return 語句返回指向“棧記憶體”的指標,因為該記憶體在函數結束時自動消亡,見樣本4。
/*=======================樣本4=============================*/
char *GetString(void)
{
char p[] = "hello world";
return p;
// 編譯器將提出警告
}
void Test4(void)
{
char *str = NULL;
str = GetString();
// str 的內容是垃圾
cout<< str << endl;
}
樣本4 return 語句返回指向“棧記憶體”的指標用調試器逐步跟蹤Test4,發現執行str = GetString 語句後str 不再是NULL 指標,但是str 的內容不是“hello world”而是垃圾。
如果把樣本4 改寫成樣本5,會怎麼樣?
/*==================樣本5=====================*/
char *GetString2(void)
{
char *p = "hello world";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<< str << endl;
}
樣本5 return 語句返回常量字串函數Test5 運行雖然不會出錯,但是函數GetString2 的設計概念卻是錯誤的。因為GetString2 內的“hello world”是常量字串,位於靜態儲存區,它在程式生命期內恒定不變。無論什麼時候調用GetString2,它返回的始終是同一個“唯讀”的記憶體塊