Hello大家好,很高兴我们又见面啦!
给生活添点passion,开始今天的编程之路。
今天我们来看几个经典的动态内存笔试题。
1、题目1
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
int main()
{
char* str = NULL;
GetMemory(str);
strcpy(str, "Hello world");
printf(str);
return 0;
}
程序没有输出结果。
首先,printf(str)应该是打印出存放在str这个位置的字符串,我们想让他输出一个字符串,但是为什么没输出呢?
其实是这里的内存开辟有问题。
我们在进入函数时,创建了一个形参指针变量,开辟的时候也是在我们的形参那里开辟的,而我们的形参不会影响实参。也就是说,我们真正存放字符串的地址仍然是NULL。那么在strcpy的时候就不可避免地解引用空指针。这个错误归根结底还是解引用了空指针(上一篇介绍过)。
图片理解:
解决办法
我们想一下,既然要开辟实参那里的地址,那么是不是需要让开辟的时候从str那开辟呢?
现在问题就成了怎么从str那开始开辟。回想指针初识篇的传址调用,是不是在进入函数之后对形参进行了解引用操作呢?那我们现在也对形参进行解引用,让形参解引用之后指向str不就好了吗?
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
int main()
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "Hello world");
printf(str);
return 0;
}
这里我们就运用了二级指针,我们把str这个指针的地址传过去,那么解引用二级指针不就指向了str这个指针吗?
图片理解:
2、题目2
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
char * GetMemory(void)
{
char p[] ="Hello world";
return p;
}
int main()
{
char* str = NULL;
str = GetMemory();
printf(str);
return 0;
}
运行结果:
这个题目的错误就在于忽略了变量的生命周期(这部分知识在补充篇详细讲解过)。我们的确把字符串存放在了p这个数组里,但是当出函数后,这个p地址里存放的内容就消失了,所以打印出来是一堆乱码。
3、题目3
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
return 0;
}
运行结果:
注:这里拿手机编译器运行了一下
虽然这个程序正常打印里,但实际上他是有问题的。我们提前释放了内存,导致这一百个字节的空间不是我们的了,那么这时候我们再去放入world就属于是非法访问了。那这个地能访问吗?还真能,他还真往里面放了个world并且打印出来了。但实际上这种写法是有问题的,所以千万别这样写。
好了,今天的内容就分享到这,觉得有帮助的还请点点关注支持一下,我们下次再见!
标签:笔试,动态内存,编程,char,str,world,include,GetMemory,指针 From: https://blog.csdn.net/2401_87995839/article/details/143970491