C语言的必看经典笔试题之(动态内存分配)!!!

经典笔试题

1.1题目一:

找出错误,并纠正。

void GetMemory(char *p)
{
    
    
	p = (char *)malloc(100);
}
void Test(void)
{
    
    
	char *str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf("%s\n",str);
}

int main()
{
    
    
	void Test();
	system("pause");
}

可以肯定的是以下两个错误:
1、没有判断空间申请是否成功。
2、没有释放,会导致内存泄漏。
还有呢?
题目一解析:
在这里插入图片描述
这里传入的是一级指针str,str里存放的是NULL的地址。
在这里插入图片描述
GetMemory函数调用后,发生形参实例化,产生临时变量p,拷贝到了str里的内容(NULL的地址)。
在这里插入图片描述
p指向开辟的空间的地址0x011089C8,但是函数调用结束后,临时变量p立 马释放了,虽然p仍旧指向开辟的空间的地址,但!却是不合法的,无效的。(参考free) 所以无法把开辟的内存的地址赋值给str,而且,开辟的内存没有及时释放,会产生内存泄漏。(没有释放前,开辟的内存一直存在,子函数GetMemory结束也存在,程序结束了才消失)。
证明如上图:
在这里插入图片描述
最后,拷贝“hello world”到
str里,str指向的是NULL,运行结果变成了将“hello world”写入NULL的位置,报错。
如何把申请成功的空间地址P,传给str,然后输出“hello world”呢?答案很简单,想改变实参的内容,就在传参的时候,传实参的地址,而不是实参本身。这里想改变的是实参str里的内容,所以传参时,传&str(二级指针)就好了。(之前写过几个交换函数,创建临时变量和不创建临时变量作为参考。)

直接看输出成功的代码和运行结果:
在这里插入图片描述

1.2题目二:

1.2.1

这个题目的错误在哪里?并改正。(据我的老师讲,是字节跳动的笔试题)

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

1.2.1、p[ ]是在栈上开辟空间的,存放的是“hello world”的字符拷贝,GetMemory1运行结束后,p[ ]被栈自动释放,即使return p;是将p在栈上的地址赋给了str,虽然指向了“hello world”,但是对应的空间p[ ]已经被释放,再调用printf函数时,栈结构发生变化,所以打印出来的是乱码。
不相信来看验证!
在这里插入图片描述

str在没运行printf时候,还是指向返回的p所指向的空间的。只不过p所指向的空间已经被栈自动释放了,所以再运行printf时,会显示字符无效。
在这里插入图片描述

再看下面这道题

1.2.2

char *GetMemory2(void)
{
    
    
	char *p = "hello world";
	return p;

}
int main()
{
    
    
	char *str = NULL;
	str = GetMemory();
	printf(str);
	system("pause");
}

1.2.2、这个p虽然也是在栈上开辟的,但是存放的内容却是字符常量区的地址。return p;GetMemory2运行结束后,p被释放。返回的是p里面存放的字符常量区“h”的地址,将p变量存放的地址“h”赋给了str,这个空间是没有被释放的,所以可以正常输出“hello world”。

1.3题目三

1.3.1

char *GetMemory4(void)
{
    
    

	char *p = NULL;
	p = (char*)malloc(20);
	if (NULL != *p)
	{
    
    
		p = "hello world";
	}
	free(p);
	return p;
}

1.3.1、这个会报错,形成断点,因为 当p = “hello world”; 时,是把字符常量区“h”的地址赋给了p,p本来指向的是开辟的空间的地址,但赋值过后p指向了字符常量区“h”。free的时候,释放的是字符常量区的空间,释放了一块不属于malloc开辟的空间!形成内存泄漏。错!还是一块只读不可更改的空间!大错特错!而且本身开辟的空间还没有被释放,错的离谱!
下一题:

1.3.2

char *GetMemory3(void)
{
    
    
	char *q = "hello world!";
	char *p = NULL;
	p=(char*)malloc(20);
	if ( NULL != *p )
	{
    
    
		for (int i = 0; i < 20; i++)
		{
    
    
			*(p + i) = *(q + i);
		}
	}
	free(p);
	return p;
}

1.3.2、这个输出的是乱码,free前后的p指向的空间虽然不变,返回p,也是把p存放的地址返回给了str,str指向的是free过后的“hello world“对应的空间。是不确定的,非法的,所以是乱码。
如果删掉free,,输出的就是”hello world“。这里判定空间开辟成功后进行的使用操作是:解引用式的给p指向的动态内存空间赋值,没有改变p的指向,和GetMemory3要区别开。

函数调用临时变量的相关问题。

这里有关函数调用产生临时变量,无法更改外部变量(指与形参对应的实参)的内容。(根据生命周期和作用域来谈)我会写一篇文章表达自己的理解,这是链接。

猜你喜欢

转载自blog.csdn.net/Zhou000815/article/details/110493077
今日推荐