动态内存管理的经典面试题解析

在学习这几个经典的面试题之前,先给大家解释几个名词:
1.空指针:简单的代码表现就是p=NULL(p为一个指针),空指针没有指向任何内存块,它里面存的值为0;

2.内存释放:在我们动态的申请了内存之后,当我们使用完了这块内存,我们需要把申请的这块内存还给我们的操作系统,而不是一直占用。而释放的本质就是这块内存被标注为可以被其它应用程序使用,而内存申请后这块内存对于其它应用程序来说就被标注为已占用。

3.野指针:野指针就是我们的指针指向了一块内存,然后这块内存被释放了,然后也没有给这个指针赋值为NULL,即这个指针指向了内存中的一块未知内存,因此这是非常危险的;

4.内存泄漏:内存泄漏就是说我们申请的内存没有被释放,由于我们申请内存后,这块内存被标注了占用,即别的进程是不能使用的,当我们使用完内存而没有释放,就会导致别的进程也使用不了这块内存,即所谓的内存泄漏。

几个关于内存分配的经典面试题:
题目1:

void GetMemory(char*p)
{
p = (char*)malloc(100);
}
void Test(void)
{
char*str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}

运行以上代码会出现什么问题?
我们注意观察,str一开始被赋值为NULL,然后我们给GetMemory函数传入了这个空指针。而在GetMemory函数内部,我们企图修改这个传入的空指针,我们传递参数的方式是值传递,即我们传给p的还是NULL。函数结束后,str事实上还是空指针。并没有达到修改其值的目的。

在这里需要注意的是,当我们需要修改变量的值的时候,我们需要传入被修改变量的地址,也就是这里的str的地址,即&str。

所以,这里我们需要修改为:

void GetMemory(char**p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char*str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
}

题目2:

char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}

运行以上代码,又会出现什么结果呢?
我们注意下GetMemory函数内部,对于数组P,在函数结束后p就被释放了,那么Test函数里的str实际上就成为了野指针了。

题目3:

扫描二维码关注公众号,回复: 1058300 查看本文章
void GetMemory2(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char*str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}

运行这一段代码,我们又会有什么发现呢?
这段代码避免了题目一中的问题,但是没有对内存分配是否成功进行判断。另外,这段代码没有对分配的内存进行释放,最后就会造成内存泄漏。

题目4:

void Test(void)
{
char*str = (char*) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}

分析这段代码,又有什么问题?
由于在代码段中,我们将str释放了,而没有给str赋值为NULL,这就容易造成野指针。

通过上面这几个例子,下面我们总结一下,在内存动态分配的时候,我们要注意以下几点:
1、内存申请的时候,我们需要对返回的地址进行判断,判断内存是否申请成功;
2、注意NULL指针的使用;
3、注意内存泄漏问题,即申请的内存要释放;
4、注意野指针问题,即对于释放了的指针,我们要给指针赋空值。

猜你喜欢

转载自blog.csdn.net/lws123253/article/details/80292826