动态内存管理经典笔试题讲解

举报
YIN_尹 发表于 2023/08/07 20:11:01 2023/08/07
【摘要】 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, "h...

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;
}

这样代码就正确了:

cf300fe349624067b78613c7e50b85eb.png

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语言动态内存管理的讲解及一些笔试题练习,欢迎大家指正!!!

8075029d35ca4ea491bab6e67de6dec8.png

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。