• 【C语言】动态内存管理 经典笔试题


    前言

    通过前面动态内存管理的学习,我了解到如何去开辟空间,知道malloc,realloc,calloc的使用,它们之间有什么不同,以及如何释放动态开辟的内存,下面我们通过几个经典面试题,来巩固和加深我们对动态开辟的理解和掌握。
    下面几个面试题,主要找出代码中的一些严重的错误,我也会解释其中的原因,同时也会将错误的代码修改,希望能够帮助大家。

    笔试题1

    错误代码

    如果下面的test函数运行,会编译通过吗,可以先仔细阅读代码并仔细分析这个代码错误在哪里

    #include
    #include
    #include
    void GetMemory(char* p) 
    {
    	p = (char*)malloc(100);//开辟空间
    }
    void Test(void)
    {
    	char* str = NULL;//将str置为NULL
    	GetMemory(str);//通过GetMemory函数将str传参给p
    	strcpy(str, "hello world");//字符串拷贝
    	printf(str);
    }
    int main()
    {
    	Test();//调用test函数
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    分析+图解

    从上述的代码中,我一步一步来分析,从Test函数调用,进入Test函数内部,将str置为空指针,然后再将str传参,指针p来接收str,p就表示NULL,然后malloc开辟100个字节的空间的地址放到p中,所以p就是指向100个字节空间的地址,开辟完空间然后跳出 GetMemory,回到Test函数中,但是我们发现str并没有改变,还是空指针,这时strcpy函数是无法拷贝字符串,所以我们要把str的地址传过去,p来接收str的地址,p就是指向str,然后对p的解引用找到str,把开辟空间的地址传给str,这是str就是指向开辟空间的地址,还有一个问题就是如果开辟空间如果不释放,内存空间就会泄漏,所以我们要对开辟空间进行free。

    在这里插入图片描述
    正确代码

    #include
    #include
    #include
    void GetMemory(char** p)
    {
    	*p = (char*)malloc(100);//对p进行解引用,找到str,把开辟空间的地址传给str,str指向malloc开辟的空间。
    }
    void Test(void)
    {
    	char* str = NULL;
    	GetMemory(&str);//取出str的地址,由于str的类型是char*,所以接收str的地址是二级指针来接收
    	strcpy(str, "hello world");
    	printf(str);
    	free(str);//释放开辟的空间
    	str = NULL;
    }
    int main()
    {
    	Test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    除了上述的改法,还可以将GetMemory的返回值类型改为char*,将p的地址返回,然后用str=GetMemory(str)接收,这样也可以把开辟空间的地址传给str。

    笔试题2

    错误代码

    #include
    #include
    
    char* GetMemory(void)
    {
        char p[] = "hello world";
        //static char p[] = "hello world";
    	return p;
    }
    
    void Test(void)
    {
    	char* str = NULL;
    	str = GetMemory();
    	printf(str);
    }
    
    int main()
    {
    	Test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    从上述的代码中,最大的问题在于GetMemory函数体中,在栈区中为"hello world"开辟空间,p是数组名,表示存放着第一个字符的地址,然后返回p,但是在栈区开辟的空间,数组p出了作用域,空间就会被操作系统销毁,这是p就成了一个野指针,虽然p中存放着地址,但是指向的空间已经被销毁了,就会导致非法访问。

    所以我们在 char p[] = "hello world"的前面加上static,这是就会改变它的生命周期,直到程序结束,内存空间才会销毁,这样就会避免出了所在的作用域就被销毁回收了。

    笔试题3

    #include
    #include
    #include
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    经过我们对第一道笔试题的分析,我们明显可以看出它的错误点,malloc开辟了空间一定要释放,不然会造成内存泄漏
    free(str);
    str=NULL;

    笔试题4

    #include
    #include
    #include
    void Test(void)
    {
    	char* str = (char*)malloc(100);
    	strcpy(str, "hello");
    	free(str);
    	//
    	if (str != NULL)
    	{
    		//str是野指针,非法访问
    		strcpy(str, "world");
    		printf(str);
    	}
    }
    int main()
    {
    	Test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这道题问题所在就是虽然我们释放str所在的空间,但是没有将str置为空指针
    如果不置为空指针,也是属于野指针的问题,会造成非法访问。
    请记得对str进行置空
    str=NULL;

    总结

    学习总是循序渐进的,我们一起加油,向自己心中的梦想努力。
    如果对上述一些问题还是不太了解,可以先看一看前面写的文章
    动态内存管理
    这些文章都涉及到上述的一些知识点。

    在这里插入图片描述

  • 相关阅读:
    突破供应链管理瓶颈,SCM供应链协同系统提升冷链物流行业整体供应链协同效率
    ABAP json解析使用引用代替预定义数据结构
    【调试笔记-20240618-Windows- Tauri 调试中关闭自动重构的功能】
    竞赛 基于生成对抗网络的照片上色动态算法设计与实现 - 深度学习 opencv python
    Vert.x web 接收请求时反序列化对象 Failed to decode 如何解决?
    MyBatis入门
    word转PDF的方法 简介快速
    数量关系(刘文超)
    爱上开源之golang入门至实战第四章函数(Func)(五)
    Python 大麦抢票脚本
  • 原文地址:https://blog.csdn.net/m0_71659028/article/details/127121754