#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 128 //系统分配给用户的最大内存
int a;
typedef struct MCB{//内存控制块
int add; //分区起始地址
int sta; //分区状态,0为可用,1为不可用,2不可用且移入回收站
int size; //分区大小
int jno; //分区装入作业号,作业号从1开始
struct MCB* next; //链连指针
}MCB;
MCB *free_table,*ft; //可用分区的头指针,尾指针
MCB *used_table,*ut; //已分配分区的头指针,尾指针
MCB *recover_table,*rt; //回收作业的头指针,尾指针
void initFree_table()//初始化可用区链表,初始大小为整个用户分区
{
if(!(free_table=(MCB*)malloc(sizeof(struct MCB))))
exit(1);
free_table->add = 0;
free_table->size = MAX_SIZE;
free_table->sta = 0;
free_table->jno = 0;
free_table->next = NULL;
ft=free_table;
}
void initUsed_table()//初始化已分配分区链表
{
if(!(used_table=(MCB*)malloc(sizeof(struct MCB))))
exit(1);
used_table->add = 0;
used_table->size = 0;
used_table->sta = 1;
used_table->jno = 0;
used_table->next = NULL;
ut=used_table;
}
void initRecover_table()//初始化回收站分区链表
{
if(!(recover_table=(MCB*)malloc(sizeof(struct MCB))))
exit(1);
recover_table->add = 0;
recover_table->size = 0;
recover_table->sta = 2;
recover_table->jno = 0;
recover_table->next = NULL;
rt=recover_table;
}
void add_ut(MCB *pf,int size,int jno)
{
//修改已分配链表
if(used_table->next == NULL && used_table->size == 0)//若其为首,则已分配链表的头指针即为该块的首部
{//已用分区表的第一块
used_table->add = pf->add;
used_table->size = size;
used_table->jno = jno;
}else{// 若不为首,将新增分区加到已分配链表末尾
//pt为临时MCB
MCB *pt;
if(!(pt=(MCB*)malloc(sizeof(struct MCB))))
exit(1);
pt->size = size;
pt->add = pf->add; //分区起始地址
pt->jno = jno; //分区装入作业号,作业号从1开始
pt->sta = 1; //状态改为1
pt->next = NULL;
ut->next = pt;
ut = ut->next; //已分配分区的尾指针后移1位
}
}
void add_rt(MCB *pu,int size,int jno) //移入回收站
{
//修改已回收链表
if(recover_table->next == NULL && recover_table->size == 0)//若其为首,则回收链表的头指针即为该块的首部
{//回收分区表的第一块
recover_table->add = pu->add;
recover_table->size = size;
recover_table->jno = jno;
}else{// 若不为首,将新增分区加到已分配链表末尾
//pt为临时MCB
MCB *pt;
if(!(pt=(MCB*)malloc(sizeof(struct MCB))))
exit(1);
else{
pt->size = size;
pt->add = pu->add; //分区起始地址
pt->jno = jno; //分区装入作业号,作业号从1开始
pt->sta = 2; //状态改为2
pt->next = NULL;
rt->next = pt;
rt = rt->next; //回收分区的尾指针后移1位
}
}
}
void se(int jno){
//从used_table中找到jno
MCB *pu = used_table;
MCB *p = pu;//指向要回收块,即回收作业的前一个项
while(pu && pu->jno != jno)
{
p = pu;
pu = pu->next;
}
if(pu == NULL)
{
printf("没有找到作业编号为%d的作业!可以执行添加操作\n\n",jno);
a=1;
}
else{
a=0;
}
}
void allot(int jno,int size)//首次适应法为作业分配存储空间
{
if(jno <= 0 ) /*|| jno有重复*///分区装入作业号,作业号从1开始
{
printf("输入作业号有误,请重新输入!\n");
return;
}
se(jno);
if (a==0)
{
printf("输入作业号有重复,请重新输入!\n");
return;
}
if(size > MAX_SIZE)
{
printf("作业太大,无法分配!\n");
return;
}
if(size <= 0)
{
printf("作业大小不合法!\n");
}
//查空白分区链表
MCB *pf = free_table;
MCB *p=pf;
while(pf != NULL && pf->size < size) //空闲区不为空,且大小不支持装入
{
p = pf; //指针指向当前空闲区
pf = pf->next; //空闲区指针后移,直至找到大小支持的空闲区,或退出
}
if(pf == NULL) //若未找到大小支持的空闲区则
{
printf("未找到可用分区!\n");
return;
}
if(pf->size == size){ //找到支持的空闲区 若空闲区大小正好等于所需要的大小
//把该分区从可用区链表中删除
if(pf == free_table) //若支持的空闲区为首位
{/*删除的是头结点*/
free_table->sta = 1;
if(free_table->next != NULL)
{//存在后续结点,则头指针后移
free_table = free_table->next;
}else{//只有一个结点,则置空可用区
free_table->size = 0;
}
}else{ //若支持的空闲区不为首位 则将其状态置1,并将其在空闲区列表删除
pf->sta = 1;
p->next = pf->next;
pf->next = NULL;
}
//将新增分区pf加到已分配链表
add_ut(pf,size,jno);
}else if(pf->size > size){
//把空白分区一分为二
//将新增分区pf加到已分配链表
add_ut(pf,size,jno);
//修改空闲分区链表
pf->add = pf->add + size;
pf->size -= size;
pf->jno = 0;
}
printf("作业空间已成功分配...\n\n");
return;//正常分配
}
void Select(int jno)//查找内存空间
{
//从used_table中找到jno
MCB *pu = used_table;
MCB *p = pu;//指向要回收块,即回收作业的前一个项
while(pu && pu->jno != jno)
{
p = pu;
pu = pu->next;
}
if(pu == NULL)
{
printf("没有找到作业编号为%d的作业!可以执行添加操作\n\n",jno);
return;
}
printf("该作业编号已存在!可以执行删除操作\n");
printf("\t作业编号\t起始地址\t结束地址\t分区大小\n");
printf("\t%d\t\t%d\t\t%d\t\t%d\n",pu->jno,pu->add,pu->add+pu->size,pu->size);
}
void reclaim(int jno)//回收内存空间
{
//从used_table中找到jno
MCB *pu = used_table;
MCB *p = pu;//指向要回收块,即回收作业的前一个项
while(pu && pu->jno != jno)
{
p = pu;
pu = pu->next;
}
if(pu == NULL)
{
printf("没有找到作业编号为%d的作业!\n\n",jno);
return;
}
int size = pu->size;
//把jno块pu插入recover_table
printf("是否将其放入回收站,若是则输入1,否则输入0!\n");
int n;
scanf("%d",&n);
if(n==1){
add_rt(pu,size,jno);
printf("作业空间已存入回收站...\n\n");
}
else{
}
//删除used_table中的jno块,即pu
if(pu == used_table) /*删除的是头结点*/
{
if(used_table->next != NULL)
{
used_table = used_table->next;
}else{
used_table->size = 0;
}
}else{
p->next = pu->next;
}
//把jno块pu插入free_table
if(free_table->next == NULL && free_table->size == 0)
{//可用区为空,则创建新的可用区
free_table->size = size;
free_table->add = pu->add;
free_table->sta = 0;
free_table->next = NULL;
}
else
{/*查到应插入的位置,分两大种情况:在头结点之前,之后*/
MCB *pf=free_table; //下一个位置,或下邻区
MCB *q=pf; //q为要插入的位置,或上邻区
/*插入位置在可用区头结点之前*/
if(pu->add+size < free_table->add)
{
MCB *tmp;
if(!(tmp=(MCB*)malloc(sizeof(struct MCB))))
exit(1);
tmp->next = free_table;
tmp->jno = 0;
tmp->add = pu->add;
tmp->size = pu->size;
tmp->sta = 0;
free_table = tmp;
}else if(pu->add+size == free_table->add){
/*插入位置和可用区头结点下邻*/
free_table->add -= size;
free_table->size += size;
}
else
{/*插入位置在可用区头结点之后*/
//查找位置
while(pf->next != NULL && pf->add+pf->size <= pu->add) //找到与其最接近的插入位置在其之前的结点地址赋值给q,pf为其指正的next值地址
{
q = pf;
pf = pf->next;
}
if(q->add+q->size == pu->add)/*有与归还区上邻的空闲区*/
{
//归还长度+下邻区长度
q->size = q->size+size;
if(pf->add == pu->add+size)/*有与归还区下邻的空闲区*/
{
//删除下邻链接点
q->next = pf->next;
//把上邻空闲节点的长度增加归还块长度
q->size = q->size + pf->size;
free(pf);
}
}
else
{
q->next = pu;
if(pf->add == pu->add+size)/*有与归还区下邻的空闲区*/
{
//把上邻空闲节点的长度增加归还块长度
pu->size = size + pf->size;
pu->next = pf->next;
free(pf);
}else{//把归还块直接插入未分配链表中
pu->next = pf;
pu->jno = 0;
}
}
}
}
printf("成功回收作业分区!\n");
}
void displayUt(MCB *pMCB)//显示已使用作业分区表
{
if(pMCB == NULL || pMCB->size == 0)
{
printf("\t当前内存中没有任何作业!\n\n");
return;
}
MCB *p=pMCB;
printf("\t作业编号\t起始地址\t结束地址\t分区大小\n");
while( p != NULL)
{
printf("\t%d\t\t%d\t\t%d\t\t%d\n",p->jno,p->add,p->add+p->size,p->size);
p = p->next;
}
printf("\n");
}
void displayFt(MCB *pMCB)//显示空闲主存分区表
{
if(pMCB->size == 0)
{
printf("\t当前主存没有可用分区!\n\n");
return;
}
MCB *p=pMCB;
printf("\t起始地址\t结束地址\t分区大小\n");
while( p != NULL)
{
printf("\t%d\t\t%d\t\t%d\n",p->add,p->add+p->size,p->size);
p = p->next;
}
printf("\n");
}
void displayRt(MCB *pMCB)//显示空闲主存分区表
{
if(pMCB->size == 0)
{
printf("\t当前主存没有回收分区!\n\n");
return;
}
MCB *p=pMCB;
printf("\t起始地址\t结束地址\t分区大小\n");
while( p != NULL)
{
printf("\t%d\t\t%d\t\t%d\n",p->add,p->add+p->size,p->size);
p = p->next;
}
printf("\n");
}
int main()
{//菜单选择
int select=0,jno=0,size=0;
initFree_table();
initUsed_table();
initRecover_table();
printf("\t\t\t可变分区管理-首次适应算法实验\n");
printf("\t\t\t\t--Powered by wwh\n");
printf("\t本程序为便于计算,0号分区不使用,默认分区编号为1~128\n\n");
do{
printf("\t\t\t请选择操作命令:\n");
printf("\t\t\t1:分配作业存储空间\n");
printf("\t\t\t2:回收作业存储空间\n");
printf("\t\t\t3:查看作业存储空间\n");
printf("\t\t\t4:显示可用主存信息\n");
printf("\t\t\t5:显示已用主存信息\n");
printf("\t\t\t6:显示回收主存信息\n");
printf("\t\t\t0:退出\n\n");
scanf("%d",&select);
switch(select)
{
case 0:
exit(0);
break;
case 1:
printf("请输入作业编号(从1开始,请勿重复输入已存在的作业编号!):");
scanf("%d",&jno);
Select(jno);
printf("请再次输入作业编号(从1开始,请勿重复输入已存在的作业编号!):");
scanf("%d",&jno);
printf("请输入作业%d所需内存大小:",jno);
scanf("%d",&size);
allot(jno,size);
break;
case 2:
printf("请输入要回收的作业空间编号:");
scanf("%d",&jno);
Select(jno);
printf("请再次输入要回收的作业空间编号:");
scanf("%d",&jno);
reclaim(jno);
break;
case 3:
printf("请输入要查看的作业空间编号:");
scanf("%d",&jno);
Select(jno);
break;
case 4:
printf("\t\t\t可用分区情况如下:\n\n");
displayFt(free_table);
break;
case 5:
printf("\t\t\t已用分区情况如下:\n\n");
displayUt(used_table);
case 6:
printf("\t\t\t回收分区情况如下:\n\n");
displayRt(recover_table);
default:
printf("输入字符无效,请请重新输入!\n");
}
}while(select);
return 0;
}