当我们需要调用一个申请内存的函数时,大概想的是将函数的参数定义为一个指针来传递内存吧,但是可以用指针去申请动态内存吗?
如下函数GetMemory(str,200):
void GetMemory(char *p, int num)
{
p = (char *)malloc(sizeof(char)*num);
if(p == NULL)
return;
}
void Test(void)
{
char *str = NULL;
GetMemory(str,100); //str 仍为NULL!
strcpy(str,"hello"); //运行错误
}
毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本称为_p,编译器使 _p = p。如果函数体内的程序修改了 _p的内容,就会导致p的内容作相应的修改。这就是可以用指针作为输出参数的原因。
在本例中,_p申请了新的内存,只是把 _p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有释放动态内存。
如果非要用指针参数来传递内存,那么应该用二级指针,也就是“指向指针的指针”,如下:
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(sizeof(char)*num);
if(p==NULL || *p==NULL)
return;
}
void Test2(void)
{
char *str = NULL;
GetMemory2(&str,100);
strcpy(str,"hello");
cout<<str<<endl;
free(str);
}
这样才可以正确的申请内存,并且不会内存泄漏。
除了二级指针作为参数来申请内存外,还可以用函数的返回值来完成。如下:
char *GetMemory3(int num)
{
char *p = (char *)malloc(sizeof(char)*num);
retun 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[] = "hello, world";
return p; //警告!
}
void Test4(void)
{
char *str = NULL;
str = GetString(); //str的内容是垃圾
cout<<str<<endl;
}
用调试器逐步跟踪Test4,发现执行str = Getstring语句后的str不再是NULL指针,但str中的内容不是“hello world”而是垃圾。
那如果将上例改写如下可以吗:
char *Getstring2(void)
{
char *p = "hello, world";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<<str<<endl;
}
虽然Test5不会运行出错,但是函数GetString2的设计概念却是错误的。因为GetSting2内的“hello world”是常量字符串,位于静态存储区,它的程序生命期恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。