C语言模拟操作系统内存分配——首次适应算法(First Fit)

算法思想:

将内存块中的所有的块按照地址递增的顺序连接成一个链表,每次要将新的作业放入内存的时候就按顺序查找内存块链表,每次都是用找到的可以用的第一个内存块。

链表数据结构:

链表结点共有4个区域和一个下指针构成,四个区域分别记录该内存块的起始地址,该内存块长度,内存块的状态和内存块存放的作业编号(没有作业时存放的是0)。

模拟实现的策略:

1.插入操作时依照地址递增的顺序检查可以装入的第一个内存块
若找到,则装入内存中,并且把内部碎片分出来变成新的结点插入链表中
若没找到则分配失败
2.撤销操作时按照作业编号找到要撤销作业所在内存块
若找到,则将状态置位未分配,此时假如前后有可以合并的空内存块则合并

若没有找到,则返回没有找到该作业信息

实现代码:

#include <stdio.h>
#include <stdlib.h>
/*
算法思想:
1.插入操作时依照地址递增的顺序检查可以装入的第一个内存块
若找到,则装入内存中,并且把内部碎片分出来变成新的结点插入链表中
若没找到则分配失败
2.撤销操作时按照作业编号找到要撤销作业所在内存块
若找到,则将状态置位未分配,此时假如前后有可以合并的空内存块则合并
若没有找到,则返回没有找到该作业信息
*/

//使用链表的数据结构
typedef struct LNode{
	int address;//表示该分区的起始地址
	int length; //表示该分区的长度
	int state;  //0表示该分区空闲,1表示该分区已分配
	int number; //作业的编号
	struct LNode *next;
}*pLNode;

//链表的插入操作
//L是链表的头指针,addr是该内存块的首地址,len是该内存块的长度
//sta是内存块的状态,num是将占有内存块作业的编号
void InsertLNode(pLNode L,int addr,int len,int sta,int num) {
	pLNode p = (pLNode)malloc(sizeof(LNode));
	p->address = addr;
	p->length = len;
	p->state = sta;
	p->number = num;
	p->next = NULL;
	L->next = p;
}

//初始化链表
//初始化链表的头指针,假设操作系统有8M的内存空间,且始址为0
//leng为内存空间的总大小,单位为M
void InitLNode(pLNode L,int leng){

	//L = (pLNode)malloc(sizeof(LNode));
	L->address = 0;//从首地址开始
	L->length = 8;
	L->state = 1;
	L->number = 65535;
	//插入剩余的空闲分区
	InsertLNode(L, 8, leng - 8,0,0);
	printf("初始化成功!\n");
}

//撤销作业
//L为链表头指针,num为待撤销的作业编号
//若找到该作业则把其占有的内存块state置0
void Revocation(pLNode L, int num) {
	pLNode p = L->next;
	if (p->number == num) {
		//找到了这个作业
		p->state = 0;
		printf("成功撤销编号为%d的作业!\n",num);
		return;
	}
	while (p->next != NULL) {
		p = p->next;
		p->state = 0;
		printf("成功撤销编号为%d的作业!\n", num);
		return;
	}
	printf("撤销作业失败,没有找到编号为%d的作业\n", num);
}

//检查链表中是否有连续的未分配内存区,如果有就合并
void Merge_free(pLNode L) {
	pLNode p = L,pre;
	int num = 0;//用于检测连续空闲内存空间数量,等于2表示有连续的内存空间
	while (p != NULL) {
		if (p->state == 0) {
			//表示为空闲区
			num++;
			if (num == 1)
				pre = p;//为合并做准备
			else if (num == 2) {
				//表示有连续的空闲区,执行合并操作
				//将p结点的长度加给前驱结点的长度
				//前驱结点指向p结点的下结点
				//释放p结点
				//将p指向前驱结点,方便下次判断
				//num置1
				pre->length += p->length;
				pre->next = p->next;
				free(p);
				p = pre;
				num = 1;
			}
		}
		else if (p->state == 1)
			num = 0;
		p = p->next;
	}
}

//为作业分配内存空间
//L为链表头指针,len为作业需要的内存大小,num为作业编号
void Allocation(pLNode L, int len, int num) {
	pLNode p = L->next;
	while (p != NULL) {
		if (p->state == 0) {
			//表示内存块未分配
			if (p->length > len) {
				//表示可以分配内存空间
				//但是需要把内部碎片分出来,构成新的空闲内存块
				//新的内存块的起始地址为p->address + len,长度为p->length-len
				pLNode l = (pLNode)malloc(sizeof(LNode));
				l->length = p->length - len;
				l->address = p->address + len;
				l->state = 0;
				l->number = 0;
				l->next = p->next;
				p->next = l;
				p->length = len;
				p->number = num;
				p->state = 1;
				printf("内存分配成功!\n");
				return;
			}
			else if (p->length == len) {
				//刚刚好够分配,只要修改作业编号和内存块状态即可
				p->number = num;
				p->state = 1;
				printf("内存分配成功!\n");
				return;
			}
		}
		p = p->next;
	}
	printf("内存分配失败,没有找到合适的空闲内存块\n");
}

//打印
void print(pLNode L) {
	printf("************************************************************\n");
	printf("内存分配情况如下:\n");
	printf("起始地址\t内存块长度\t存放作业编号\t内存块状态\n");
	pLNode p = L;
	while (p != NULL) {
		printf("%8d\t%10d\t", p->address, p->length);
		if (p->number == 65535) {
			printf("    操作系统\t");
		}
		else if (p->number == 0) {
			printf("      无作业\t");
		}
		else {
			printf("%12d\t", p->number);
		}
		if (p->state == 0) {
			printf("      空闲\n");
		}
		else {
			printf("    已分配\n");
		}
		p = p->next;
	}
	printf("************************************************************\n");
}

//服务选择菜单
int select() {
	int a;
	printf("************************************************************\n");
	printf("请选择服务:\n");
	printf("1.为新作业分配内存\t2.撤销作业\n3.查看内存分配情况\t4.退出\n");
	printf("请输入编号以选择:");
	scanf("%d", &a);
	return a;
	printf("************************************************************\n");
}

int main()
{
	pLNode L = (pLNode)malloc(sizeof(LNode));
	InitLNode(L, 512);
	int a;
	int len, num;
	a = select();
	getchar();
	while (a != 4) {
		switch (a) {
		case 1:
			printf("请输入要分配内存的作业的长度和编号:");
			scanf("%d%d", &len, &num);
			Allocation(L, len, num);
			break;
		case 2:
			printf("请输入要撤销作业的编号:");
			scanf("%d", &num);
			Revocation(L, num);
			break;
		case 3:
			//system("cls");
			print(L);
			break;
		default:
			break;
		}
		a = select();
	}
    return 0;
}
调试结果:


猜你喜欢

转载自blog.csdn.net/haohulala/article/details/80631914