1、如果函数的参数是一个指针,不要用该指针去申请动态内存。示例如下
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"); //运行时错误
}
问题:对于函数GetMemory(),编译器总要为函数的每个参数制作临时副本,指针参数p的副本是_p,编译器使_p = p。如果函数体内的程序修改了_p指向的内容,就导致参数p指向的内容也被做了相应的修改,这就是指针可以用做输出参数的原因。但本例中,_p申请了新的内存,只是把_p本身的值改变了,即指向了新的内存空间,但是p本身丝毫没变(即修改了_p本身的值,而不是_p指向的对象)。所以函数GetMemory()并不能输出任何东西,每执行一次GetMemory()就会泄漏一块内存。
2、应使用“指向指针的指针”或者“指向指针的引用”去申请内存
void GetMemory(char **p, int num) //或者是char *&rp
{
*p = (char *)malloc(sizeof(char)*num); //rp = ...
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100); //注意参数时&str,而不是str
strcpy(str,"hello"); //OK
cout<<str<<endl;
free(str); //ok
}
3、“指向指针的指针”与“指针的引用”不容易理解,可以用函数返回值来传递动态内存,示例如下:
char * GetMemory(int num)
{
char *p = (char *) malloc(sizeof(char)*num);
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory(100);
strcpy(str,"hello");
cout<<str<<endl;
free(str);
}
注意:不要用return语句返回指向“栈内存”的指针或引用,因为该内存在函数结束时将自动释放,示例如下:
char *GetString(void)
{
char p[] = "hello world"; //用字符串常量初始化数组的内存空间
return p; //编译器将提出警告
}
void test(void)
{
char *str = NULL;
str = GetString(); //str 的内容是垃圾
cout<<str<<endl
}
但上例修改成指针指向常量字符串的形式,则字符串位于静态存储区,在程序生命周期内始终有效,返回的始终是同一个“只读”内存块的地址,不可试图对它进行写操作,可以把返回值改为const char* 以避免无意中的修改。示例:
char * GetString2(void)
{
char *p = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetString2();
cout<<str<<endl;
}