33. 简易内存池
1、题目描述
● 请实现一个简易内存池,根据请求命令完成内存分配和释放。
● 内存池支持两种操作命令,REQUEST和RELEASE,其格式为:
● REQUEST=请求的内存大小 表示请求分配指定大小内存,如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为0,则输出error。
● RELEASE=释放的内存首地址 表示释放掉之前分配的内存,释放成功无需输出,如果释放不存在的首地址则输出error。
注意:内存池总大小为100字节。
内存池地址分配必须是连续内存,并优先从低地址分配。
内存释放后可被再次分配,已释放的内存在空闲时不能被二次释放。
不会释放已申请的内存块的中间地址。
释放操作只是针对首地址所对应的单个内存块进行操作,不会影响其它内存块。
2、输入描述
首行为整数 N , 表示操作命令的个数,取值范围:0 < N <= 100。
接下来的N行, 每行将给出一个操作命令,操作命令和参数之间用 “=”分割。3、输出描述
请求分配指定大小内存时,如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为0,则输出error
释放掉之前分配的内存时,释放成功无需输出,如果释放不存在的首地址则输出error。
用例:输入
5
REQUEST=10
REQUEST=20
RELEASE=0
REQUEST=20
REQUEST=10输出
0
10
30
0ps:
第一条,申请地址0~9的10个字节内存,返回首地址0
第二条,申请地址10~29的20字节内存,返回首地址10
第三条,释放首地址为0的内存申请,0~9地址内存被释放,变为空闲,释放成功,无需输出
第四条,申请20字节内存,09地址内存连续空间不足20字节,往后查找到3049地址,返回首地址30
第五条,申请10字节,0~9地址内存空间足够,返回首地址0
————————————————版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_52914380/article/details/138459806
一、问题分析
首先读题,仔细看描述中的内容,发现需求是
1.请实现一个简易内存池,根据请求命令完成内存分配和释放
2.内存池支持两种操作命令,REQUEST和RELEASE,其格式为:
REQUEST=请求的内存大小,表示请求分配指定大小内存,如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为0,则输出error。
RELEASE=释放的内存首地址,表示释放掉之前分配的内存,释放成功无需输出,如果释放不存在的首地址则输出error。
3.注意:(1)内存池总大小为100字节。
(2)内存池地址分配必须是连续内存,并优先从低地址分配
(3)内存释放后可被再次分配,已释放的内存在空闲时不能被二次释放
(4)不会释放已申请的内存块的中间地址
(5)释放操作只是针对首地址所对应的单个内存块进行操作,不会影响其他内存块。
4.输入描述:首行为整数N,表示操作命令的个数,取值范围:N大于0小于等于100.
接下来的N行,每行将给出一个操作命令,操作命令和参数之间用“=”分割。
5.输出描述:请求分配指定大小内存时,如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为0,则输出error
释放掉之前分配的内存时,释放成功无需输出,如果释放不存在的首地址则输出error。
二、解题思路
1.内存池一共有两种命令,一种是REQUEST,后面跟请求分配的内存大小
一种是RELEASE后面跟要释放内存的首地址
2.首先我们引入标准输入输出库、标准库、字符串处理库定义内存池总大小为100字节
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MEMORY_POOL_SIZE 100
3.然后定义MemoryBlock结构体用来表示内存池中的内存块信息。其中startAddress记录内存块的起始地址,size表示内存块的大小(字节数),isAllocated用于标记该内存块是否已经被分配出去(1表示已分配,0表示空闲),next指针用于链接下一个内存块,形成一个链表结构,方便管理内存池中多个内存块的情况。
typede struct MemoryBlock {
int startAddress; // 内存块起始地址
int size; // 内存块大小
int isAllocated; // 内存块是否已分配
struct MemoryBlock *next; // 指向下一个内存块的指针
} MemoryBlock;
4.然后声明一个函数用于创建并初始化内存池,通过动态分配内存创建一个MemoryBlock结构体来表示整个内存池,将其起始地址设为0,大小设为定义好的MEMORY_POOL_SIZE(也就是100字节),标记为未分配状态(isAllocated设为0),并将next指针设为NULL,表示初始时只有这一个代表整个内存池的空闲内存块,最后返回这个表示内存池的结构体指针。
MemoryBlock* initMemoryPool() {
MemoryBlock *pool = (MemoryBlock *)malloc(sizeof(MemoryBlock));
if(pool == NULL) {
perror("内存分配失败");
return NULL;
}
pool->startAddress = 0;
pool->size = MEMORY_POOL_SIZE;
pool->isAllocated = 0;
pool->next = NULL;
return pool;
}
5.声明一个函数用来查找空闲内存块,该函数接收内存池的头指针pool和请求分配的内存大小requestSize作为参数,通过遍历内存池链表(从内存池的头指针开始,沿着next指针逐个访问内存块),查找是否存在未分配(isAllocated为0)且大小足够(size大于等于requestSize)的空闲内存块,找到则返回该内存块的指针,若遍历完整个链表都没有找到符合条件的空闲内存块,就返回NULL。
MemoryBlock* findFreeBlock(MemoryBlock *pool, int requestSize) {
MemoryBlock *current = pool;
while(current != NULL) {
if(current->isAllocated == 0 && current->size >= requestSize) {
return current;
}
current = current->next;
}
return NULL;
}
6.声明一个内存分配函数用于实际分配内存,首先判断请求分配的内存大小是否为0,若是则输出error并返回-1表示分配失败。然后调用findFreeBlock函数在内存池中查找合适的空闲内存块,如果没找到(返回NULL),同样输出error并返回-1.若找到了空闲内存块,分两种情况处理:
如果找到的空闲内存块大小正好等于请求的大小,直接将该内存块的isAllocated标记为1,表示已分配,然后返回该内存块的起始地址。
如果空闲内存块大小大于请求的大小,需要将其拆分成两个内存块,一个用于分配(大小设为requestSize,标记为已分配),另一个保持空闲(大小为原空闲内存块大小减去请求的大小,标记为未分配),并通过调整链表指针将新的空闲内存块插入到链表中合适的位置,最后返回分配的内存块的起始地址。
int allocateMemory(MemoryBlock **pool, int requestSize) {
if(requestSize == 0) {
printf("error\n");
return -1;
}
MemoryBlock *freeBlock = findFreeBlock(*pool, requestSize);
if(freeBlock == NULL) {
printf("error\n");
return -1;
}
if(freeBlock->size == requestSize) {
freeBlock->isAllocated = 1;
} else {
MemoryBlock *newBlock = (MemoryBlock *)malloc(sizeof(MemoryBlock));
if(newBlock == NULL) {
perror("内存分配失败");
return -1;
}
newBlock->startAddress = freeBlock->startAddress + requestSize;
newBlock->size = freeBlock->size - requestSize;
newBlock->isAllocated = 0;
newBlock->next = freeBlock->next;
freeBlock->size = requestSize;
freeBlock->isAllocated = 1;
freeBlock->next = newBlock;
}
return freeBlock->startAddress;
}
7.然后是释放内存函数,用于释放指定首地址对应的内存块,通过遍历内存池链表来查找要释放的内存块(根据起始地址匹配),如果找到了对应的内存块且该内存块是已分配状态,则将其标记为未分配,并且和前后有可能存在的空闲内存块合并,
void releaseMemory(MemoryBlock **pool, int relaseAddress) {
MemoryBlock *prev = NULL;
MemoryBlock *current = *pool;
while(current != NULL) {
if(current->startAddress == releaseAddress) {
if(current->isAllocated == 0) {
printf("error\n");
return;
}
current->isAllocated = 0;
// 如果前面有空闲内存块我们尝试合并
if(prev != NULL && prev->isAllocated == 0) {
prev->size += current->size;
prev->next = current->next;
free(current);
current = prev;
}
// 如果后面有空闲内存块,我们尝试合并
if(current->next != NULL && current->next->isAllocated == 0) {
current->size += current->next->size;
current->next = current->next->next;
}
return;
}
prev = current;
current = current->next;
}
printf("error\n");
}
8.主函数首先定义一个整数int N;用于读取命令的个数
int main() {
int N;
scanf("%d", &N);
MemoryBlock *memoryPool = initMemoryPool();
for(int i = 0;i < N; i++) {
char command[20];
scanf("%s",command);
if(strncmp(command,"REQUEST", 7) == 0) {
int requestSize;
sscanf(command + 7, "=%d", &requestSize);
int address = allocateMemory(&memoryPool, requestSize);
if(address != -1) {
printf("%d\n", address);
}
}
else if(strncmp(command,"RELEASE", 7) == 0) {
int relaseAddress;
sscanf(command + 7, "=%d", &releaseAddress);
releaseMemory(&memoryPool, releaseAddress);
}
}
return 0;
}
三、具体步骤
使用的语言是C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MEMORY_POOL_SIZE 100// 内存块结构体
typedef struct MemoryBlock {int startAddress;int size;bool isAllocated;struct MemoryBlock *next;
} MemoryBlock;// 初始化内存池
MemoryBlock* initMemoryBlock() {MemoryBlock *pool = (MemoryBlock *)malloc(sizeof(MemoryBlock));if(pool == NULL) {perror("内存分配失败");return NULL;}pool->startAddress = 0;pool->size = MEMORY_POOL_SIZE;pool->isAllocated = false;pool->next = NULL;return pool;
}// 寻找空闲内存池
MemoryBlock* findFreeBlock(MemoryBlock* pool, int requestSize) {MemoryBlock *current = pool;while(current != NULL) {if(current->isAllocated == false && current->size >= requestSize) {return current;}current = current->next;}return NULL;
}// 为空闲地址池分配内存
int allocateMemory(MemoryBlock** pool, int requestSize) {if(requestSize == 0) {printf("error\n");return -1;}MemoryBlock *freeBlock = findFreeBlock(*pool, requestSize);if(freeBlock == NULL) {printf("error\n");return -1;}if(freeBlock->size == requestSize) {freeBlock->isAllocated = true;} else {MemoryBlock *newBlock = (MemoryBlock*)malloc(sizeof(MemoryBlock));if(newBlock == NULL) {perror("内存分配失败");return -1;}newBlock->size = freeBlock->size - requestSize;newBlock->isAllocated = false;newBlock->startAddress = freeBlock->startAddress + requestSize;newBlock->next = freeBlock->next;freeBlock->isAllocated = true;freeBlock->size = requestSize;freeBlock->next = newBlock;}return freeBlock->startAddress;
}void releaseMemory(MemoryBlock** pool, int relaseAddress) {MemoryBlock* prev = NULL, *current = *pool;while(current != NULL) {if(current->startAddress == relaseAddress) {if(current->isAllocated == false) {printf("error\n");return;}current->isAllocated = false;if(prev!= NULL && prev->isAllocated == false) {prev->size += current->size;prev->next = current->next;free(current);current = prev;}if(current->next != NULL && current->next->isAllocated == 0) {current->size += current->next->size;current->next = current->next->next;}return;}prev = current;current = current->next;}printf("error\n");
}int main() {int N;scanf("%d", &N);MemoryBlock *memoryPool = initMemoryBlock();for(int i = 0; i < N; i++) {char command[20];int num;scanf("%s", command);char *temp;temp = strtok(command, "=");num = atoi(strtok(NULL, "="));//printf("%s=%d\n", temp, num);if(strcmp(temp,"REQUEST") == 0) {int address = allocateMemory(&memoryPool, num);if(address != -1) {printf("%d\n", address);}} else if(strcmp(temp, "RELEASE") == 0) {releaseMemory(&memoryPool, num);}}return 0;
}
相关文章:
33. 简易内存池
1、题目描述 ● 请实现一个简易内存池,根据请求命令完成内存分配和释放。 ● 内存池支持两种操作命令,REQUEST和RELEASE,其格式为: ● REQUEST请求的内存大小 表示请求分配指定大小内存,如果分配成功,返回分配到的内存…...
win32汇编环境,对话框程序模版,含文本框与菜单简单功能
;运行效果 ;win32汇编环境,对话框程序模版,含文本框与菜单简单功能 ;直接抄进RadAsm可编译运行。 ;下面为asm文件 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g…...
人工智能与传统编程的主要区别是什么?
传统编程:开发者预先编写软件行为规则,代码基于程序员定义逻辑处理输入并产生确定输出,具有确定性、手动编写规则和结构化逻辑特点,如垃圾邮件分类程序基于预设关键词等规则。AI 编程:从数据中学习而非手动编写规则&am…...
实战交易策略 篇十一:一揽子交易策略
文章目录 系列文章适用条件核心策略小额大量投资行业或主题聚焦同步操作优势系列文章 实战交易策略 篇一:奥利弗瓦莱士短线交易策略 实战交易策略 篇二:杰西利弗莫尔股票大作手操盘术策略 实战交易策略 篇三:333交易策略 实战交易策略 篇四:价值投资交易策略 实战交易策略…...
doris 2.1 -Data Manipulation-Transaction
注意:doris 只能控制读一致性,并不能rollback 1 Explicit and Implicit Transactions 1.1 Explicit Transactions 1.1.1 Explicit transactions require users to actively start, commit transactions. Only insert into values statement is supported in 2.1. BEGIN; …...
多模态融合:阿尔茨海默病检测
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、实验介绍 本实验包含 645 名阿尔茨海默病受试者,分为 AD、CN 和 MCI 组,数据集包含 3D MRI 图像与一份CSV数据,MRI数据…...
Ceph 手动部署(CentOS9)
#Ceph手动部署、CentOS9、squid版本、数字版本19.2.0 #部署服务:块、对象、文件 一、部署前规划 1、兼容性确认 2、资源规划 节点类型节点名称操作系统CPU/内存硬盘网络组件安装集群节点CephAdm01CentOS94U/8GOS:40G,OSD:2*100GIP1:192.169.0.9(管理&集群),IP2:…...
家政预约小程序05活动管理
目录 1 搭建活动管理页面2 搭建活动规则页面3 搭建规则新增页面3 配置规则跳转4 搭建活动参与记录总结 上一篇我们介绍了活动管理的表结构设计,本篇我们介绍一下后台功能。 1 搭建活动管理页面 我们一共搭建了三个表,先搭建主表的后台功能。打开我们的后…...
解决安装pynini和WeTextProcessing报错问题
点击这里,访问博客 0. 背景 最近在给别人有偿部署ASR-LLM-TTS项目时遇到安装pynini和WeTextProcessing依赖报错的问题,报错信息如下: IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files…...
【PCIe 总线及设备入门学习专栏 4.1 -- PCI 总线的地址空间分配】
文章目录 Overview 本文转自:https://blog.chinaaet.com/justlxy/p/5100053219 Overview PCI 总线具有32位数据/地址复用总线,所以其存储地址空间为 2324GB。也就是PCI上的所有设备共同映射到这4GB上,每个PCI设备占用唯一的一段PCI地址&…...
华为配置 之 RIP
简介: RIP(路由信息协议)是一种广泛使用的内部网关协议,基于距离向量算法来决定路径。它通过向全网广播路由控制信息来动态交换网络拓扑信息,从而计算出最佳路由路径。RIP易于配置和理解,非常适用于小型网络…...
探寻AI Agent:开启知识图谱自动生成新篇章(17/30)
一、AI Agent 与知识图谱:智能时代的双雄 在当今科技飞速发展的时代,人工智能如同一股汹涌澎湃的浪潮,正以前所未有的力量重塑着我们的世界。而在这股浪潮中,AI Agent 与知识图谱无疑是两颗最为璀璨的明珠,它们各自发挥…...
卸载wps后word图标没有变成白纸恢复
这几天下载了个wps教育版,后头用完了删了 用习惯的2019图标 给兄弟我干没了??? 其他老哥说什么卸载关联重新下 ,而且还要什么撤销保存原来的备份什么,兄弟也是不得不怂了 后头就发现了这个半宝藏博主&…...
LeetCode 热题 100_二叉树的直径(40_543_简单_C++)(二叉树;递归)
LeetCode 热题 100_二叉树的直径(40_543) 题目描述:输入输出样例:题解:解题思路:思路一(递归): 代码实现代码实现(思路一(递归)&#…...
【数据结构】线性数据结构——链表
1. 定义 链表是一种线性数据结构,由多个节点(Node)组成。每个节点存储数据和指向下一个节点的指针。与数组不同,链表的节点不需要在内存中连续存储。 2. 特点 动态存储: 链表的大小不固定,可以动态增加或…...
开源存储详解-分布式存储与ceph
ceph体系结构 rados:reliable, autonomous, distributed object storage, rados rados采用c开发 对象存储 ceph严格意义讲只提供对象存储能力,ceph的块存储能力实际是基于对象存储库librados的rbd 对象存储特点 对象存储采用put/get/delete…...
[算法] [leetcode-509] 斐波那契数
509 斐波那契数 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0,F(1) 1 F(n) F(n - 1) F(n - 2),其中 n…...
运维人员的Go语言学习路线
以下是一份更为详细的适合运维人员的Go语言学习路线图: 一、基础环境搭建与入门(第 1 - 2 周) 第 1 周 环境搭建 在本地开发机和常用的运维服务器环境(如 Linux 系统)中安装 Go 语言。从官方网站(https://…...
[创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较
目录 一、波士顿矩阵 1、基本原理 2、各象限产品的定义及战略对策 3、应用 4、优点与局限性 二、技术成熟度模型与产品生命周期模型的配对 1、技术成熟度模型 2、产品生命周期模型 3、技术成熟度模型与产品生命周期模型的配对 三、产品生命周期与产品类型的对应关系 …...
安卓入门十一 常用网络协议四
MQTT(Message Queuing Telemetry Transport) MQTT是一种轻量级的、发布/订阅模式的消息传输协议。它被设计用于在低带宽或不稳定网络环境下,实现物联网设备之间的可靠通信。 4.1 MQTT详细介绍 发布/订阅模式:MQTT 使用发布/订…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
