【C语言】动态内存面试题(一)

提示:这系列文章会列出关于动态内存常出现的面试题,我会解析每道题中的错误,并改成正确的代码。面试题(一)主要是关于函数调用完毕局部变量会被销毁的问题。

文章目录


面试题一

请思考以下代码,找出错误,并改正

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void GetMemory(char* p)//空指针也是有类型的,它与其他同类型指针的值都不相同
{
	p = (char*)malloc(100);//p用来接收str-NULL
}
void Test(void)
{
	//一定要将指针变量进行初始化,不然可能会沦为野指针
	char* str = NULL;
	//调用获取内存函数
	GetMemory(str);
	//拷贝字符串
	strcpy(str, "hello world");
	printf(str);//printf("abc");和printf(str)一个道理
}
int main()
{
	Test();
	return 0;
}

图解错误原因
在这里插入图片描述

1.这个代码在vs编译器下运行,会出现出现崩溃的现象;
2.str以值传递的形式给p,我们知道函数内部创建的非静态局部变量只有在函数被调用的时候,才向堆栈中申请临时空间,这里原来p是NULL,然后mallo将开辟的动态内存空间的起始地址传给p,假设起始地址是0x0012ff40,那么指针变量p中现在存的就是这个地址,注意的是函数一旦调用完毕,函数内部申请的栈空间就会被释放,也就是说指针变量p在函数调用完毕后会被销毁,那块内存空间会被操作系统回收,那么起始地址就带不回来了给str了,也就无法完成字符串的拷贝,这个时候在main函数中str为NULL指针,对NULL解引用程序会奔溃。
3.上面可以理解为,malloc动态开辟的内存起始地址是卧底的身份,卧底的身份只有上司p知道,而这时候上司p被杀害了,那么也就没有人会知道这个卧底的身份,即起始地址就无法知道了,这个代码就是错误的,str没有办法获得起始地址,无法进行拷贝。
4.我们在函数GetMemory用malloc开辟了100个字节的动态内存空间,而动态内存是需要我们手动释放的,而在这个代码中,并没有出现free函数对内存进行释放,所以会造成内存泄漏。

正确代码如下
方法1:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* GetMemory(char** p)//二级指针保存的是另一个指针的地址
{
    //p存的是指针str的地址
    //对p进行解引用,可以拿到str的地址
    //然后把malloc开辟的内存的起始地址赋给str的地址
    //通过址传递就可以实现字符串拷贝
	*p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);//传址
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str=NULL;
}
int main()
{
	Test();
	return 0;
}

那么如何理解这个代码呢?

我们利用址传递,将str的地址传递过去,二级指针用来接收指针的地址,所以在函数中p中存的是str的地址,解引用p就拿到了str的地址,mallo开辟的动态内存空间的起始地址就可以直接赋给str,这样即使栈区指针变量p被销毁了,也不影响动态内存空间的获取。

方法2:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* GetMemory(char* p)
{
	p = (char*)malloc(100);
	return p;
}
void Test(void)
{
	char* str = NULL;
	str=GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str=NULL;
}
int main()
{
	Test();
	return 0;
}

我们考虑到如果上司p被杀害就无法知道卧底的身份(动态开辟内存空间的起始地址),那么还有一种方法,就是可以在p被销毁之前,把地址传出去,用str接收(上司被杀害之前,就把卧底的身份告诉另一个人),注意这是返回的是p,而p的类型是char*,所以GetMemory函数的返回类型要改成char*类型。

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_麦子熟了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值