操作系统首次适应法为作业分配存储空间代码及注释

#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;
}
 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值