參數策略
如果函數的參數是一個指針,不要指望用該指針去動態申請內存。如下:
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所指的內容也跟着改變(畢竟指向同樣的地方)。但是在GetMemory中動態分配內存空間,改變了_p的內容。在調用函數中的p還是指向NULL。再者,因為函數GetMemory中動態分配了空間,但是沒釋放,這樣調用一次函數,就泄露了一次內存。圖示:
如果非得用指針參數申請內存,可以用指針的指針作為參數申請內存
void GetMemory(char **p, int num) { *p = (char *)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); //記得加地址符 strcpy(str, "hello"); free(str) }
原理是一樣的,比較難理解,圖示表示:
比較好的方法是傳指針的引用
#include <iostream> #include <string> #include <cstring> #include <cstdlib> using namespace std; void GetMemory(char *&p, int num) { p = (char *)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; GetMemory(str, 100); strcpy(str, "hello"); cout << str << endl; free(str); } int main() { Test(); }
這里注意指針的引用 為char* &a,要是不好理解可以這樣:
typedef char* pchar; pchar &a
返回值策略
可以用函數返回值來傳遞動態內存。這中方法比“指針的指針”簡單多了
char *GetMemory(int num) { char *p = (char *)malloc(sizeof(char) * num); return p; } void Test(void) { char *str = NULL; str = GetMemory(100); //str指向了動態分配的空間 strcpy(str, "hello"); free(str) }
在使用返回值時,千萬別返回指向“棧內存”的指針、引用,因為該內存在函數結束時自動消亡了,返回的指針是個野指針了。例如
char *GetString() { char p[] = "hello world"; //數組內容存儲在棧區,函數結束時,會釋放掉 return p; } void Test(void) { char *str = NULL; str = GetString(); //因為非配的內存早已釋放掉,此時的str是個野指針,內容是垃圾 cout << str << endl; }
在函數中不定義數組,定義指針,示例:
char *GetString() { char *p = "hello world"; //數組內容存儲在靜態區,函數結束時,不會釋放掉 return p; } void Test(void) { char *str = NULL; str = GetString(); cout << str << endl; }
此時的程序是正確的,但是有一點,此時分配的內存處於靜態區,是只可以讀取但是不可以修改的。