【C语言进阶】之动态内存管理笔试题及柔性数组

news2024/11/28 18:53:10

【C语言进阶】之动态内存管理笔试题

  • 1.动态内存管理笔试题汇总
    • 1.1第一道题
    • 1.2第二道题
    • 1.3第三道题
    • 1.4第四道题
  • 2.C/C++内存管理
  • 3.柔性数组
    • 3.1什么是柔性数组
    • 3.2柔性数组的使用
    • 3.2柔性数组的优点

📃博客主页: 小镇敲码人
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞
前言:接上一篇博客【C语言进阶】之动态内存管理,今天来跟着博主把理论应用在实践之中,彻底掌握动态内存管理的相关知识!!!!

1.动态内存管理笔试题汇总

1.1第一道题

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

请问运行Test函数会有怎样的结果呢?
运行结果:

在这里插入图片描述

解析:数组p是函数里开的一个临时变量,它的空间开在栈区上,出了GetMemory函数作用域它的生命周期结束,系统就把它的空间回收了,所以你返回的地址是系统已经回收的地址,里面的内容是未知的,是一串字符。

另外printf打印字符串,可以直接传字符串首元素的地址打印。

1.2第二道题

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

运行结果:

在这里插入图片描述
解析:程序直接崩溃,这是为什么呢?明明这次已经在堆区开辟空间了呀,实际上,我们并没有改变str,如果你不相信,我们可以来验证一下:

在这里插入图片描述
在调用函数GetMemory后为什么str的值没有改变呢?因为str和p都是一级指针,它们两个唯一的相似之处就是它们的值是一样的,本质还是值传递,想改变一级指针的值,需要传它的地址,我们把代码这样改就对了:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
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;
}

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

在这里插入图片描述

1.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 函数会有什么样的结果?

运行结果:
在这里插入图片描述
这道题和上一道题我们修改后的类似不做过多阐述,但是有个问题,虽然编译器没有报错,但是它动态开辟的空间没有释放,会造成内存泄露。

1.4第四道题

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

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

在这里插入图片描述
解析:
虽然运行结果没有问题,但其实这段代码是不对的,原因就是我们在free动态开辟的空间后没有及时的去将str置为空指针,使他成为了一个野指针,那片地址已经不属于我们了,你还进行写入和访问,显然是非法的,所以我们应该养成好习惯,free后就要将指针变量置空。

2.C/C++内存管理

在这里插入图片描述

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

1.栈区(stack):栈区主要放一些函数中创建的局部变量,生命周期在函数结束时就结束了,内存也被系统(OS)回收,这个区域通常存放临时变量、函数的参数、函数的返回数据、返回地址等。读写效率高,但是容量有限。
2.堆区(heap):这个区域主要是动态开辟的内存存放的地方,通常只有程序结束时系统才会回收其内存,除非你手动使用去回收,像C语言中使用的free函数。
3.数据段(静态区 static):这个内存区域主要存放静态变量、全局变量,生命周期也是全局,只有程序运行结束系统才会回收其空间。
4.代码段:这个区域内存主要存放函数体(类成员函数和全局函数)的二级制代码。

有了上面那幅图,相信你对动态内存管理又有了更深的理解,也可以更好的理解static这个关键字了:
1.一般的临时变量开在栈区,栈区的特点是,出了作用域,里面的临时变量就会被销毁。
2.static修饰的静态变量在数据段,生命周期变长了,在程序运行结束的时候它的空间才会被系统回收。

3.柔性数组

3.1什么是柔性数组

C99标准中,如果结构体的最后一个数组它的大小是未知的,我们就把那个数组叫做柔性数组。

typedef struct ss
{
	int a;
	int b[0];
}flexarr;

如果上面那种你的编译器不能通过,可以尝试写成下面这样:

typedef  struct sss
{
	int a;
	int b[];
}flexarr;

关于柔性数组有几点需要说明的:
1.sizeof计算结构体的大小时,是不将柔性数组的大小计算在内的。
2.当你要给柔性数组用malloc()函数开空间时,大小应该要比结构体的大小要大,以便于系统给柔性数组分配空间。
3.柔性数组前面必须要有至少要有一个成员。
如果你不相信我们可以用下面代码来验证一下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct ss
{
	int a;
	int b[0];
}flexarr;

int main()
{
	printf("%d", sizeof(flexarr));
	return 0;
}

运行结果:
在这里插入图片描述

3.2柔性数组的使用

通过下面代码我们来演示柔性数组的使用:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct ss
{
	int a;
	int b[0];
}flexarr;

int main()
{
	flexarr* p = (flexarr*)malloc(sizeof(flexarr) + 100 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	p->a = 100;
	memset(p->b, 0, sizeof(int) * 100);
	for (int i = 0; i < 100; i++)
	{
		p->b[i] += 1;
	}
	printf("%d\n", p->a);
	for (int i = 0; i < 100; i++)
	{
		printf("%d ", p->b[i]);
	}
	free(p);
	return 0;
}

运行结果:

在这里插入图片描述

flexarr* p = (flexarr*)malloc(sizeof(flexarr) + 100 * sizeof(int));

这个代码相当于给柔性数组开了100个int的空间。

3.2柔性数组的优点

上述flexarr也可以这样设计:


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct ss
{
	int a;
	int* b;
}flexarr;

int main()
{
	flexarr* p = (flexarr*)malloc(sizeof(flexarr) + 100);
	if (p == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	p->a = 100;
	p->b = (int*)malloc(sizeof(int) * 100);
	memset(p->b, 0, sizeof(int) * 100);
	for (int i = 0; i < 100; i++)
	{
		p->b[i] += 1;
	}
	printf("%d\n", p->a);
	for (int i = 0; i < 100; i++)
	{
		printf("%d ", p->b[i]);
	}
	free(p->b);
	p->b = NULL;
	free(p);
	p = NULL;
	return 0;
}

运行结果:

在这里插入图片描述

第一种方法和第二种相似,但是柔性数组有一定的优势:
1.方便内存释放

  • 如果我们的代码是在一个函数里面,给用户使用,用户是看不到我们具体的实现,给用户返回一个结构体,你在里面进行二次内存分配,用户只知道释放结构体的大小,怎么能知道还需要释放里面的动态数组呢?这样就会造成内存泄漏,不安全。
  • 2.提高了访问速度
    代码1使用柔性数组,只进行了一次内存分配,是连续的,可以提高访问速度,减少了内存碎片。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1172407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes Dashboard 用户名密码方式登录

Author&#xff1a;rab 前言 为了 K8s 集群安全&#xff0c;默认情况下 Dashboard 以 Token 的形式登录的&#xff0c;那如果我们想以用户名/密码的方式登录该怎么操作呢&#xff1f;其实只需要我们创建用户并进行 ClusterRoleBinding 绑定即可&#xff0c;接下来是具体的操作…

Cygwin一个在 Windows 操作系统上提供类似于Unix、Linux 环境的兼容层项目

一、简介 Cygwin 是一个在 Windows 操作系统上提供类似于 Unix/Linux 环境的兼容层的开源项目。它为 Windows 用户提供了一种在 Windows 平台上运行类 Unix 程序的方式。 Cygwin 提供了一组工具和库&#xff0c;包括一个动态链接库&#xff08;cygwin1.dll&#xff09;和一个用…

图解系列--防火墙

05.01 防火墙是怎样的网络硬件 构建安全网络体系而需要遵循的 CIA 基本理念。CIA 是机密性 (Confidentiality) 、 完整性(Integrity) 、 可用性(Availability)。 防火墙硬件作为防范装置能够同时实现CIA 中3个条目的相应对策。在20世纪90年代中期&#xff0c;普通企业一般都…

Kibana使用Timelion根据时间序列展示数据

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

【服务器】Java连接redis及使用Java操作redis、使用场景

一、Java连接redis-No-SQL 1、导入依赖 在你的项目里面导入redis的pom依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version> </dependency> 2、连接redis 连接redis //…

【MongoDB】MongoExport如何过滤数据导出

问题 使用MongoDB处理导出数据时&#xff0c;想增加数据过滤操作。 例如&#xff1a;导出所有isGirl为true的所有数据。 分析 在mongoexport说明文档中找到了query字段和queryFile字段&#xff0c;用来进行数据查询匹配导出。 query字段 后面直接跟 json格式数据。 queryF…

【C++语法讲解】 | 运算符重构 | 三种运算符的重构方式 |代码演示

文章目录 1&#xff0c;简述2&#xff0c;结构体的定义1&#xff0c;结构体的声明2&#xff0c;结构体的申请 3.1 &#xff0c;在结构体中重构3.2 在结构体外进行重构 1&#xff0c;简述 通常情况下&#xff0c;我们会创建一些简单的数据结构以应对日常的算法使用&#xff0c;…

layui form 中input输入框长度的统一设置

Layui.form中使用class"layui-input-inline"就可轻松将元素都放到一行&#xff0c;但如果元素过多&#xff0c;就会自动换行。那就需要手动设置input框的长度。 像这种情况&#xff1a; 其实只需要添加css样式就可修改了 .layui-form-item .layui-input-inline {wid…

海康Visionmaster通讯管理:通讯管理的心跳管理功能 的使用方法

当外部设备与视觉保持连接过程中&#xff0c;由于各种不可控的原因&#xff08;例如网线被意外拔 出&#xff0c;网口松动&#xff0c;视觉程序意外退出&#xff09;&#xff0c;如何让外部设备的程序可以知道&#xff1a;与视觉的通讯已 经中断。 可以通过通讯管理模块中的心跳…

802.11AX基础---走进HE WLAN

1、WiFi 6 是什么&#xff1f; WiFi 6是IEEE802.11ax的简称&#xff0c;也就是第六代WiFi的标准&#xff1b;它在继承前几代WiFi技术的前提下&#xff0c;不仅对速率进行优化&#xff0c;更着重于对 效率 的提升。 2、WiFi 6 为什么快&#xff1f; WiFi 6 理论速率计算公式&a…

webgoat靶场攻关

A&#xff08;5&#xff09; Broken Access Control Insecure Direct Object References 直接对象引用 直接对象引用是指应用程序使用客户端提供的输入来访问数据和对象。 例子 使用 GET 方法的直接对象引用示例可能如下所示 https://some.company.tld/dor?id12345 https…

css进阶知识点速览

0前言 零基础部分的博客 1选择器进阶 1.1后代选择器 作用&#xff1a;根据html标签的嵌套关系&#xff0c;选择父元素后代中满足条件的元素 选择器语法&#xff1a;选择器1 选择器2 {css} 结果&#xff1a; 在选择器1所找到标签的后代中 注意&#xff1a; 后代包括&#xf…

论文浅尝 | ChatKBQA:基于微调大语言模型的知识图谱问答框架

第一作者&#xff1a;罗浩然&#xff0c;北京邮电大学博士研究生&#xff0c;研究方向为知识图谱与大语言模型协同推理 OpenKG地址&#xff1a;http://openkg.cn/tool/bupt-chatkbqa GitHub地址&#xff1a;https://github.com/LHRLAB/ChatKBQA 论文链接&#xff1a;https://ar…

【std | C++】使用C++返回当前时间的年月日时分秒格式

#include <chrono> #include <ctime> #include <iomanip> #include <iostream> #include <thread>std::string getCurrentDataTimeString() {auto now = std::chrono::system_clock

go语言 | grpc原理介绍(三)

了解 gRPC 通信模式中的消息流 gRPC 支持四种通信模式&#xff0c;分别是简单 RPC、服务端流式 RPC、客户端流式 RPC 和双向流式 RPC。 简单 RPC 在gRPC中&#xff0c;一个简单的RPC调用遵循请求-响应模型&#xff0c;通常涉及以下几个关键步骤和组件&#xff1a; 请求头&a…

【QT】QFileInfo文件信息读取

基于上节&#xff1a;【QT】文件读写-CSDN博客 //文件信息类QFileInfo info(filePath);qDebug() << "后缀名:" << info.suffix() << "大小:"<< info.size()<< "文件名:" << info.fileName() << "…

消息中间件-RabbitMQ介绍

一、基础知识 1. 什么是RabbitMQ RabbitMQ是2007年发布&#xff0c;是一个在AMQP(高级消息队列协议)基础上完成的&#xff0c;简称MQ全称为Message Queue, 消息队列&#xff08;MQ&#xff09;是一种应用程序对应用程序的通信方法&#xff0c;由Erlang&#xff08;专门针对于大…

Git 内容学习

一、Git 的理解 Git是一个分布式版本控制系统&#xff08;Distributed Version Control System&#xff0c;简称 DVCS&#xff09;&#xff0c;用于对项目源代码进行管理和跟踪变更。分为两种类型的仓库&#xff1a;本地仓库和远程仓库。 二、Git 的工作流程 详解如下&#x…

【大学英语视听说上】压头韵收集 + 自然环境口语问答 + 口语考试练习

压头韵&#xff1a; 自然环境口语问答 Q1: Do you like wildlife? Why? Yes, I like wildlife because it represents the rich biodiversity of our planet. Wildlife plays crucial roles in ecosystem health and resilience, providing essential services like pollina…

【LeetCode刷题-栈与队列】--232.用栈实现队列

232.用栈实现队列 class MyQueue {Deque<Integer> inStack;Deque<Integer> outStack;public MyQueue() {inStack new ArrayDeque<Integer>();outStack new ArrayDeque<Integer>();}public void push(int x) {inStack.push(x);}public int pop() {if(…