C语言动态内存管理(二)经典笔试题

第二篇内容为大家详细剖析关于动态内存管理的几个经典笔试题

目录

  • 四、笔试题
    • 1.请问运行Test函数会有什么样的结果?
      • 结果:
      • 结果运行出错的原因:
      • 本题目注意点:
      • 改正该题目的错误:
        • 正确修改1:(利用传值)
        • 正确修改2:(利用传址)
      • 本题涉及知识点
    • 2.请问运行Test函数会有什么样的结果?
      • 结果
      • 出错原因:
      • 通俗理解本题:
      • 教训:局部变量的地址不要随便返回
      • 重点内容:注意区分在函数里什么时候可以返回
    • 3.请问运行Test函数会有什么样的结果?
      • 错误点:
      • 改正:
      • 重点
    • 4.请问运行Test函数会有什么样的结果?
      • 错误点:
      • 改正:
    • 5.Nice校招笔试题
      • (1)
      • (2)

四、笔试题

1.请问运行Test函数会有什么样的结果?

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

结果:

C语言动态内存管理(二)经典笔试题_第1张图片

结果运行出错的原因:

(1)
调用GetMemory函数的时候,str的传参为值传递,p是str的临时拷贝,所以在GetMemory函数内部将动态开辟空间的地址存放在p中的时候,不会影响str,所以GetMemory函数返回之后,str中依然是NULL指针。strcpy函数就会调用失败,原因是对NULL指针的解引用操作,程序会崩溃
(2)
GetMemory函数内部malloc申请的空间没有机会释放,造成了内存泄漏

本题目注意点:

(1)注意这个程序想释放也释放不了,无论是在主函数中释放还是在test函数内部。因为一旦返回,就没有人记得动态开辟的空间在哪里,动态开辟空间的地址带不出来。
(2)而这道题的本意是想把100个字节的地址放到str里面,然后把hello world拷贝到str指向的空间里。

改正该题目的错误:

正确修改1:(利用传值)

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;
	return 0;
}
int main() {
	Test();
	return 0;
}

C语言动态内存管理(二)经典笔试题_第2张图片
解释:
(1)这里也是利用传值,但是GetMemory函数返回的是指针,p所指向的是malloc出来的空间,是在堆上,除了函数不销毁这块空间,通过p返回的地址仍然可以找到这块空间。
与原题传值对比:
原题目中的p是函数的形参变量,形参变量是个临时变量,出了函数就销毁了。p销毁了,p这块空间还给操作系统,没人记得malloc申请的空间在哪里。
(2)使用完动态开辟的这块空间用free回收掉
C语言动态内存管理(二)经典笔试题_第3张图片

正确修改2:(利用传址)

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

C语言动态内存管理(二)经典笔试题_第4张图片
解释:
将指针str的地址传给GetMemory函数的形参,str是char类型的是一级指针,它的地址用二级指针**p接收,在GetMemory函数中的p存的就是str,这样的话不通过返回值也能把地址带回来
C语言动态内存管理(二)经典笔试题_第5张图片

本题涉及知识点

关于printf打印字符的两种方式:
在这里插入图片描述
比如这句代码 char* p=“hehe\n”;
意思不是把字符串hehe\n放到p里面,而是把这个表达式字符串首地址h的地址放到p中

2.请问运行Test函数会有什么样的结果?

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

结果

C语言动态内存管理(二)经典笔试题_第6张图片

出错原因:

返回栈空间地址的问题:
GetMemory函数内部创建的数组是临时的,虽然返回了数组的起始地址给str,但是数组的内存出了GetMemory函数就被回收了,而str依然保存了数组的起始地址,这时使用str,str就是野指针
C语言动态内存管理(二)经典笔试题_第7张图片

通俗理解本题:

张三开了一间房,告诉李四明天来如家酒店302房间可入住,但是在李四来之前,张三已经把房间退了。等到李四根据张三提供的地址来到302时却无法入住,这间房也不属于李四。

这里的把房间退了相当于将空间还给操作系统,即使你有这个空间的地址信息,而这个空间确不属于你,且不能访问这个空间

教训:局部变量的地址不要随便返回

举例说明:
C语言动态内存管理(二)经典笔试题_第8张图片
根据上面的讲解,这里打印的应该是随机值,而这里刚好打印出正确的结果,是怎么回事?难道这样写也正确吗?
答:这样写是错误的。之所以刚好打印出结果10,是因为恰好空间没有被改掉的情况。


当多打印个别的语句时,就可以发现此时*p的值改变成5了。
C语言动态内存管理(二)经典笔试题_第9张图片
这里为什么多打印个hehe下面就变了?
答:因为栈帧空间会被覆盖
C语言动态内存管理(二)经典笔试题_第10张图片

重点内容:注意区分在函数里什么时候可以返回

char* GetMemory(char* p) {
	p = (char*)malloc(100);
	return p;
}

在这里插入图片描述

3.请问运行Test函数会有什么样的结果?

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

错误点:

malloc动态开辟的空间在使用完没有释放掉,造成内存泄漏

改正:

释放指针并将指针置为空
C语言动态内存管理(二)经典笔试题_第11张图片

重点

free完之后的指针如果不是空指针,一定要置为空指针,避免野指针问题

4.请问运行Test函数会有什么样的结果?

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

错误点:

(1)free完动态开辟的空间应该及时将指针置空,这里没有置空
(2)str指向的空间已经回收了,因为str没有置为空指针,还能找到刚开辟的那块空间,但是这块空间已经回收给操作系统了,不属于str,不能用,拷贝时形成非法访问,此时的str是野指针

改正:

C语言动态内存管理(二)经典笔试题_第12张图片

5.Nice校招笔试题

指出下面哪段程序有问题,并说明问题是什么。

(1)

C语言动态内存管理(二)经典笔试题_第13张图片
该题是返回栈空间地址的问题。
如果有人接收了这个函数返回的指针,就会造成野指针的问题。

(2)

C语言动态内存管理(二)经典笔试题_第14张图片
指针ptr没有初始化,没有任何指向,里面是随机值。
不知道ptr指向谁,直接对它解引用
对野指针解引用,还把10放进去,非法访问内存。

结语:
本篇内容就到这里啦,关于动态内存管理的内容未完待续,请见下篇博客。如果对大家有帮助的话,希望友友们可以点赞收藏博客,关注后续的学习内容哦!❤️

你可能感兴趣的:(C语言,c语言,开发语言,c++,数据结构)