第一道题
直接上代码吧
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
Test();
return 0;
}
过程就是这样的,那么如果让这段程序运行,会产生什么样的效果呢?这段代码有两个问题,我们分析一下。
1.p是个局部变量,这GetmeMory这个函数执行完之后,p就被销毁了,返回空指针。这块在堆上动态开辟的空间也就找不到了,从而造成内存泄漏。
2.p是str的临时拷贝,str和p并不是同一块空间,str中还是空指针,不能解引用进行strcpy操作,导致程序崩溃。
存在问题:程序崩溃和内存泄漏
修改代码
void GetMemory(char **p)
{
*p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
我把str地址当做参数传了过去,这样就可以在函数外部修改函数内部的值了。str就可以接收到所开辟的100个字节的空间了。当然还可以在GetMemory函数中将p返回,返回类型为char*,在main函数中用str接受一下即可。方法不唯一,但是一定一定不要忘记了释放空间哦!
第二道题
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
如让它运行,不难发现会有这个警告: warning C4172: 返回局部变量或临时变量的地址。
其实是这样的,这属于返回栈空间地址问题。p数组是一个局部变量,在函数调用完之后,值就被销毁了(还给操作系统了),我们可以看到返回了p的地址,那么此时的地址就不一定还存着原来的值。然后还进行了打印,这就造成了非法访问。因此,返回栈空间地址是不靠谱儿的。。
存在问题:非法访问
修改代码
char *GetMemory(void)
{
char *p = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
将p[]改为*p就正确啦,改了之后,hello world 就是一个常量字符串,不放在栈上了,返回h的地址,str接收打印就没有问题了。
第三道题
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
int main()
{
Test();
return 0;
}
其实,这道题的问题只有一个,那就是内存泄漏,我们改正的方法就是在printf之后加上free(str); str = NULL;就可以了。
第四道题
void Test(void)
{
char *str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
显然,这个代码逻辑就不对,已经执行了strcpy(str, "hello"),就已经默认了这不是空指针了,然后在下面还进行判断,显然错误。我们如何改正呢?其实,在free(str)后面加上这样一个语句(str = NULL)。这样操作之后,free之后,将str指向的空间还给操作系统,再将空指针赋给str,然后判断str不为空指针(才有意义)进行字符串复制。