来看一道“简单”却又“多坑”的面试题,关于动态内存的。?
1:找出下列代码的错误
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
int main()
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
return 0;
}
这是一段十分简洁的代码,一提到动态内存,我们首先应该发现这两个明显的错误:
1.开辟动态内存后没有free掉;
2.在使用动态内存时没有判断返回值是否为空;
一般人稍稍一看也就这两个错误了,可是并不是这样的,最大的错误是:
GetMemory()函数的形参p是一个拷贝值,所以开辟的内存起始地址并没有返回到str上,导致str一直为NULL,当GetMemory函数一结束,里面的局部变量p就会被释放掉,导致无法再找到开辟动态内存的地址,从而导致内存泄漏;
这里修改后的代码为:
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
int main()
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
return 0;
}
这里我们将函数参数改为一个二级指针,实参则为一个指针的地址,这样拷贝的二级指针p也指向str,解引用后则就是str;
画一张图来更好地理解一下:
这里还有一种方式更改错误,这种方式就是设置一个返回值,这样更加易懂:
char* GetMemory(char* p)
{
p = (char*)malloc(100);
return p;
}
int main()
{
char* str = NULL;
str = GetMemory(str);
strcpy(str, "hello world");
printf(str);
free(str);
return 0;
}
2.找出下列代码错误:
#include<stdio.h>
#include<stdlib.h>
char* getmemory(void)
{
char arr[] = "i love you";
return arr;
}
int main()
{
char* p = getmemory();
printf("%s\n", p);
return 0;
}
这个题估计很多人看了之后觉得没有啥问题,但我们运行结果将会是一堆乱码;
因为在函数结束后,它的栈帧就会被释放,但这个数组arr的数据都还残留在内存中,只是不能被引用,而此时我们又调用了printf函数,就会产生新的函数栈帧,这个函数栈帧就会覆盖掉getmemory函数的栈帧,所以再用指针寻找原来的arr时,原有数据已经被覆盖了,所以是一团乱码。
我们可以调试(F10)来查看证明我们的观点,将箭头运行到printf函数处,我们查看*p,将会看到它的值还是i,而将指针指向return时,*p的值已经不是原来的值了。