动态内存管理经典笔试题讲解
4.经典笔试题讲解
下面,我们一起来看几个动态内存管理相关的经典笔试题。
4.1 题目1
我们来看这段代码:
#include <stdio.h>
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;
}
请问运行 Test 函数会有什么样的结果?
经过上面的学习,我们相信大家应该很容易能够看出来,上面这段代码存在一些比较严重的问题。
我们一起来分析一下:
首先,test函数进去,定义了一个字符指针char* str,给它赋了一个空指针NULL,然后,调用GetMemory函数,实参传的是str,GetMemory函数用了一个字符指针p接收,在GetMemory内部,用malloc动态开辟了100个字节的空间,返回值强制类型转换为char*赋给了p。
走到这一步我们其实就能发现一个小问题:
这里没有对malloc进行一个判断或者断言,因为malloc有可能开辟空间失败返回空指针。
当然这还不算这段代码中最严重的问题。
那我们接着往下看:
GetMemory(str);调用结束,下一句代码是:
strcpy(str, "hello world");
看到这里我们应该能猜出来这段代码的目的:
应该是想把字符串"hello world"拷贝到函数GetMemory(str)中动态开辟的那100个字节空间里,然后打印出来。
那到这里第二个问题就出来了。
strcpy(str, "hello world")
既然是想把"hello world"拷贝到函数GetMemory(str)中动态开辟的那100个字节空间里,那第一个参数str是不是应该指向malloc开辟的那100个字节才对啊。
但是,上面代码里面传参传的是指针变量str,形参p实际只是str的一个临时拷贝。我们把malloc的返回值赋给了p,让p指向了这100个字节空间的首地址,但是str是不是并没有改变啊,Test 函数中的 str 一直都是 NULL。
而strcpy在拷贝是应该是会对str解引用的,这样会导致程序崩溃的!!!
还有一个问题:
malloc开辟的空间使用完是需要使用free释放的,但是上述代码并没有释放,这样就可能导致内存泄漏,因此,这也是一个比较严重的错误。
那接下来我们就来修改一下这段代码,将它变成正确的:
#include <stdlib.h>
#include <string.h>
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);//不传地址,将p作为返回值赋给str也可以
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
这样代码就正确了:
4.2 题目2(返回栈空间地址的问题)
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
大家再来看看这段代码有没有什么问题?
我们一起来分析一下:
首先str还是一个char*的指针,给它赋值为NULL,然后调用GetMemory(),
GetMemory()内部创建了一个字符数组p,放了一个字符串"hello world",p是数组名,是首字符’h’的地址,将p作为返回值赋给str,那我们是不是就可以通过str访问数组p了,printf(str)就把"hello world"打印出来了。
是这样吗?
如果这样想,那就错了。
为什么呢?
数组p是我们在函数内部创建的一个局部的数组,当函数调用结束就被销毁了,数组所在的这块空间就还给操作系统了,那这时候我们再去打印这块空间里的内容,是不是就非法访问内存了。
这样也是不行的。
4.3 题目3
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 mani()
{
Test();
return 0;
}
再来看这段代码,有什么问题:
这段代码前面都没有什么大问题,当然这里还是没有对malloc进行是否为空指针的判断。
传的是str的地址,GetMemory调用结束后,str指向的就是malloc开辟的那100字节的空间,那strcpy(str, "hello");就能够成功把字符串"hello"拷贝到str指向的空间,然后打印出来,这都没什么问题。
但是:
是不是没有对malloc开辟的空间进行释放,还是存在一个内存泄漏问题。
我们可以来修改一下:
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
assert(*p);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
free(str);
str = NULL;
}
int mani()
{
Test();
return 0;
}
这样就没什么问题了。
4.4 题目4
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
来看这段代码,有没有问题:
首先,第一个问题还是没有对malloc的返回值进行一个判断,有可能是空指针。
其次,我们发现,在strcpy(str, "hello");之后,就直接free(str)了,这时str指向的空间已经被释放了,但是str还保留这块空间的地址,因为释放后我们并没有将它置空,那此时的str是不是已经成为野指针了,因为它指向了一块已经被释放的空间。
那下面的if (str != NULL)判断结果为真,就会进入if语句,而在if语句里面又有strcpy(str, "world"),把"world"拷贝到已经不属于我们的动态内存区,篡改动态内存区的内容,后果难以预料,非常危险。
所以这段代码也是有问题的。
以上就是对C语言动态内存管理的讲解及一些笔试题练习,欢迎大家指正!!!
- 点赞
- 收藏
- 关注作者
评论(0)