若是函數的參數是一個指針,不要期望用該指針去申請動態內存。函數
Test 函數的語句GetMemory(str, 200)並無使str得到指望的內存,str 依舊是NULL,爲何?spa
void GetMemory(char *p, int num)設計
{指針
p = (char *)malloc(sizeof(char) *num);調試
}內存
void Test(void)字符串
{編譯器
char *str = NULL;編譯
GetMemory(str, 100); // str仍然爲 NULL程序
strcpy(str, "hello");//運行錯誤
}
試圖用指針參數申請動態內存
參數p的副本是 _p,編譯器使 _p = p 。若是函數體內的程序修改了_p的內容,就致使
參數p的內容做相應的修改。這就是指針能夠用做輸出參數的緣由。在本例中,_p 申請
了新的內存,只是把_p所指的內存地址改變了,可是p 絲毫未變。因此函數GetMemory
並不能輸出任何東西。事實上,每執行一次GetMemory就會泄露一塊內存,由於沒有用
free釋放內存。
若是非得要用指針參數去申請內存,那麼應該改用「指向指針的指針」,見示例:
void GetMemory2(char **p, intnum)
{
*p = (char *)malloc(sizeof(char)* num);
}
void Test2(void)
{
char *str = NULL;
GetMemory2(&str, 100); //注意參數是 &str,而不是str
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
示例7-4-2用指向指針的指針申請動態內存
因爲「指向指針的指針」這個概念不容易理解,咱們能夠用函數返回值來傳遞動態
內存。這種方法更加簡單。
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);
}
用函數返回值來傳遞動態內存
用函數返回值來傳遞動態內存這種方法雖然好用,可是經常有人把return語句用錯
了。這裏強調不要用return語句返回指向「棧內存」的指針,由於該內存在函數結束時
自動消亡,見示例。
char *GetString(void)
{
char p[] = "helloworld";
return p; //編譯器將提出警告
}
void Test4(void)
{
char *str = NULL;
str = GetString(); // str的內容是垃圾
cout<< str << endl;
}
return語句返回指向「棧內存」的指針用調試器逐步跟蹤Test4,發現執行str = GetString語句後str 再也不是NULL 指針,
可是str的內容不是「helloworld」而是垃圾。
若是將上示例改寫成以下會怎麼樣?
char *GetString2(void)
{
char *p = "helloworld";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<< str << endl;
}
return語句返回常量字符串
函數Test5運行雖然不會出錯,可是函數GetString2 的設計概念倒是錯誤的。由於
GetString2內的「hello world」是常量字符串,位於靜態存儲區,它在程序生命期內
恆定不變。不管何時調用GetString2,它返回的始終是同一個「只讀」的內存塊。