【C语言进阶篇】动态内存常考笔试题

C/C++
191
0
0
2024-02-25

⛺️生活的理想,就是为了理想的生活!

文章目录
  • 📋 前言
  • 💬 C/C++程序的内存开辟
  • 💭 内存布局图:
  • 💬几个经典的笔试题:
  • 💭 题目1:
  • 请问运行Test 函数会有什么样的结果?
  • 💭 题目2:
  • 请问运行Test 函数会有什么样的结果?
  • 💭 题目3:
  • 请问运行Test 函数会有什么样的结果?
  • ✅ 代码改进
  • 💭 题目4:
  • 请问运行Test 函数会有什么样的结果?
  • ✅ 代码改进
  • 全篇总结

📋 前言

🌈hello!各位宝子们大家好啊,关于动态内存管理和 位段 等知识我们在前面一篇已经详细介绍了? ⛳️今天就来看看这些经典的笔试题你会做吗?而这需要一些基本的C/C++程序内存分配的几个区域这些知识,今天就给大家一起讲一讲!

🔥 注:本笔试题出自《高质量的C/C++编程》林锐博士这本书 《高质量的C/C++编程》《动态内存管理》《位段 联合 枚举》

💬 C/C++程序的内存开辟

⛳️大家在学习C语言的过程中不知道思没思考过这个问题!我们每次创建的变量或者开辟的动态内存空间究竟是在内存中的那个位置开辟的呢?今天就给大家讲讲!

📑 C/C++程序内存分配的几个区域:

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结 束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是 分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返 回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分 配方式类似于链表。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。
这些就是我们C/C++在运行中的大致内存区域不知道现在清楚了嘛?那么我们在来看这幅图相信大家就明白了

💭 内存布局图:

在这里插入图片描述

用通俗易懂的话来描述就是:

  1. 栈区(stack):存放的是我们平常创建的变量 形参 等 临时变量!
  2. 堆区(heap):目前我们学的动态内存分配 都是在堆区开辟的!
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段可执行代码 和 只读 常量

💬几个经典的笔试题:

⛳️好了这些C/C++的内存分布我们懂了下面的经典笔试题就可以做一做了看一下你是否真的理解了

💭 题目1:

void GetMemory(char *p)
{
 p = (char *)malloc(100);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str);
 strcpy(str, "hello world");
 printf(str);
}
⁉️这里我们看的这个程序的意思大概就是,把我们的字符类型的指针变量传给 GetMemory 函数想利用它来为我们开辟空间并返回!
  • 下面我们运行一下看看
请问运行Test 函数会有什么样的结果?

在这里插入图片描述

我们代码运行了,却是这样的结果!其实这个代码有3个问题
  1. 我们这里传过去的是指针变量 并不是地址 ,所以而p是str的一份临时拷贝改变形参并不会改变实参所以当GetMemory 函数结束时 p 还是NULL空指针
  2. malloc开辟的空间并未释放, GetMemory 函数返回时 p 会销毁。导致内存泄漏
  3. p 开辟的100个字节空间与 str 无关所以,str 还是空指针。
  4. 而我们 strcpy 对空指针解引用,程序肯定会崩溃!

在这里插入图片描述

💭 题目2:

char *GetMemory(void)
{
 char p[] = "hello world";
 return p;
}
void Test(void)
{
 char *str = NULL;
 str = GetMemory();
 printf(str);
}
请问运行Test 函数会有什么样的结果?

在这里插入图片描述

我们代码运行了,却是这样的结果!其实这个代码有3个问题
  1. 我们的数组a是在栈空间开辟的,所以当GetMemory函数结束时会 销毁
  2. 虽然我们返回的是 数组 的首地址,但是这个地址是野指针啊
  3. 所以我们在访问这个数组时就会非法访问,导致访问的是一段乱码!
  4. 这个属于返回栈空间地址的问题 在这里插入图片描述

在这里插入图片描述

💭 题目3:

void GetMemory(char **p, int num)
{
 *p = (char *)malloc(num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
}
请问运行Test 函数会有什么样的结果?

在这里插入图片描述

我们代码运行了,看上去结果没有问题!其实这个代码也有3个问题
  1. 那就是动态内存申请的空间没有free释放! 这样我们的代码就更加完美了
✅ 代码改进
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

💭 题目4:

void Test(void)
{
 char *str = (char *) malloc(100);
 strcpy(str, "hello");
 free(str);
 if(str != NULL)
 {
 strcpy(str, "world");
 printf(str);
 }
}
请问运行Test 函数会有什么样的结果?

在这里插入图片描述

我们代码运行了,看上去结果没有问题!其实这个代码也有3个问题
  1. 那就是动态内存申请的空间提前free释放! str 已经释放了但是我们还使用
  2. 这就会造成问题内存非法访问的问题!所以我们free释放完一定要置为空指针!
✅ 代码改进
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Test(void)
{
	char* str = (char*)malloc(100);
	if (str == NULL)
	{
		perror("malloc");
		return 1;
	}
	strcpy(str, "hello");
	free(str);
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

全篇总结

✅ 归纳: 好了以上就是关于C/C++的内存分布 和 动态内存管理的笔试题就全部讲解完毕啦! C/C++程序的内存开辟形参实参问题返回栈空间地址问题free为释放free提前释放 ☁️ 不知道大家今天的这套笔试题看懂多少呢?