欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

模拟内存分配(链表实现)

程序员文章站 2024-03-19 09:03:28
...

仅仅是一个最简单的内存模拟……


规 则: 


我们拥有长度为m字节的内存,输入的第一行是两个整数,分别代表对内存的操作次数以及m的大小,输入的第二行是一个字符串,也就程序中所支持的三种操作:

1.alloc n – 分配n字节的连续内存,并输出被分配的内存块的id;

2.erase x – 释放id为x的内存块;

3.defragment – 对内存进行碎片整理。


首先我们来规定:

1.第一块成功分配的内存的id为1,第二块为2,以此类推;

2.执行alloc操作所开盘的内存必须是连续的,如果有多块符合这一条件的内存块,选择最靠前的那块来分配。如果不能分配这个大小的连续空闲内存块,则输

出“提示信息”;

3.erase操作释放完的内存可以重新使用,如果要释放的内存块在内存中没有找到,则返回“该内存块未找到”的提示信息,如果分配成功则不输出任何东西;

4.defragment操作将使所有内存尽量向前靠近,不打乱他们原本的顺序。


模拟内存分配(链表实现)

  • 既然是链表实现,一定少不了这个咯!每一个节点记录此处的ID以及该区域内存大小data,布尔型变量t代表这里是否已被占用。

struct ab
{
    int data;
    int id;
    bool t;
    struct ab* next;
};


  • 主程序呢,比较简单,主要是提示信息以及控制操作次数和输入,部分变量已定义为全局变量,比如mail。最重要的功能还在mallo/search/bing这几个函数里面!

int main()
{
    int n;
    cout<<"Please enter the number of operations and total memory size"<<endl;
    cin>>n>>mall;
    struct ab *head=NULL;
    while(n--)
    {
        string a;
        int size,id;
        struct ab *aa=head;
        cout<<"Please enter the operation to be performed: ";
        cin>>a;
        if(a=="alloc")
        {
            cout<<"Please enter the size you want to allocate memory: ";
            cin>>size;
            aa=mallo(head,size);
            if(aa==NULL)cout<<"\n\nNULL\tCould not find the assigned area.\n"<<endl;
            else head=aa;
        }
        else if(a=="erase")
        {
            cout<<"Please enter a ID that needs to be freed: ";
            cin>>id;
            if(search(head,id)==0)cout<<"\nThe ID does not exist.\n"<<endl;
        }
        else if(a=="defragment")
            head=bing(head);
        if(aa!=NULL)print(head);
    }
    return 0;
}


  • 这是mallo函数,之前在主函数里面定义head=NULL,因此第一次分配内存的时候整个内存都是空的(NULL),所以使用if(head==NULL){} 实现建立一个链表的头节点,并且返回头节点的地址,成功分配内存则赋值给head。
  • 若第二次调用mallo函数,而此时head不是NULL,则从头遍历整个链表,若发现有一段内存未用并且大于需要分配的内存大小(p1->data>size&&p1->t==false),则用两个结构体指针,一个指向此时的位置,另一个新开辟一个节点,表示完成这次分配内存后该区域剩余的内存,而当前分配的空间则缩小到指定大小,然后将新节点插入到链表这个位置中这样就模拟出了内存分配。
  • 假如遍历的时候刚好碰见和指定大小一样的一段空内存,这样的话就把该段内存标记为已占用的就可以了,p1->t=true;要是遍历到最后一个区域,也就是前面内存空缺的位置还是不满足指定的要求,需要在最后面分配,这是先检测最后面的区域大小是否符合,若不符合,返回NULL,代表未成功分配内存,若符合,便和上面的情况一样了,新建一个节点来储存剩余内存的信息,而此时的节点就将大小缩小到指定大小,节点内标记为已占用。
  • 代码中的k便是检测前面是否已经分配,若分配k==false,若没有成功分配k==true;这样便是内存最后面的区域了!成功分配返回head,未成功分配返回NULL,其他操作就在主函数里面了。

int di=1,mall;
ab* mallo(struct ab *head,int size)
{
    struct ab *p1=head,*p2=head;
    if(head==NULL)
    {
        if(size>mall)return NULL;
        p1=(struct ab*)malloc(len);
        p1->data=size;
        p1->id=di++;
        p1->t=true;
        p1->next=NULL;
        return p1;
    }
    else
    {
        bool k=false;
        int s=0;
        while(p1!=NULL)
        {
            p2=p1;
            s+=p1->data;
            if(p1->data>size&&p1->t==false)
            {
                p2=(struct ab*)malloc(len);
                p2->data=p1->data-size;
                p2->t=false;
                p2->id=0;
                p2->next=p1->next;
                p1->data=size;
                p1->t=true;
                p1->id=di++;
                p1->next=p2;
                k=true;
                break;
            }
            else if(p1->data==size&&p1->t==false)
            {
                p1->id=di++;
                p1->t=true;
                k=true;
                break;
            }
            else p1=p1->next;
        }
        if(k==false)
        {
            if(mall-s>=size)
            {
                p1=(struct ab*)malloc(len);
                p1->next=NULL;
                p2->next=p1;
                p1->data=size;
                p1->t=true;
                p1->id=di++;
            }
            else return NULL;
        }
    }
    return head;
}


  • 最重要的一个已经说完了,search这个功能实现很简单,假如释放一个指定ID的内存,把该内存标记为未被占用(false)就行,假如ID未找到,返回 0,找到并成功释放,返回1,判断的条件当然在主函数啦!

int search(struct ab *p,int id)
{
    bool k=false;
    while(p!=NULL)
    {
        if(p->id==id)
        {
            p->t=false;
            k=true;
            break;
        }
        p=p->next;
    }
    if(k==false)return 0;
    return 1;
}

  • 嗯,这个功能是实现内存整理的,本来可以将标记为(false)的内存块大小变为0,就能实现,不过既然是模拟内存分配,就要把未被分配的内存节点从链表中摘下来,好像有delete这个函数可以把摘下来的内存在计算机内存(此内存非彼内存模拟内存分配(链表实现)中释放!但终究没有加入,下面的代码,第四行,是除去整个内存开始的空区域,将头节点重新选择至链表中第一个出现的已占用的区域,然后在循环里面用p2遍历下面连续的空区域,重新连接整个链表,最后便把链表中标记(false)的区域都摘除了下来!返回新链表的头节点head;

ab* bing(struct ab* head)
{
    struct ab *p1=head,*p2=head;
    while(p1!=NULL&&p1->t==0)p1=p1->next;
    head=p1;
    while(p1!=NULL)
    {
        if(p1->next==NULL)return head;
        else p2=p1->next;
        while(p2!=NULL&&p2->t==0)p2=p2->next;
        p1->next=p2;
        p1=p2;
    }
    return head;
}

  • 最后一个功能,输出整个链表,这样大家便可以查看到此时的内存分配状况了!

void print(struct ab *p1)
{
    cout<<"\nSize\tID\tT/F"<<endl;
    while(p1!=NULL)
    {
        cout<<p1->data<<"\t"<<p1->id<<"\t";
        if(p1->t==true)cout<<"true"<<endl;
        else cout<<"false"<<endl;
        p1=p1->next;
    }
    cout<<endl;
}
  • 好了,用链表模拟内存的分配就是这样。

下面附上完整源代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
#define len sizeof(struct ab)
struct ab
{
    int data;
    int id;
    bool t;
    struct ab* next;
};
int di=1,mall;
ab* mallo(struct ab *head,int size)
{
    struct ab *p1=head,*p2=head;
    if(head==NULL)
    {
        if(size>mall)return NULL;
        p1=(struct ab*)malloc(len);
        p1->data=size;
        p1->id=di++;
        p1->t=true;
        p1->next=NULL;
        return p1;
    }
    else
    {
        bool k=false;
        int s=0;
        while(p1!=NULL)
        {
            p2=p1;
            s+=p1->data;
            if(p1->data>size&&p1->t==false)
            {
                p2=(struct ab*)malloc(len);
                p2->data=p1->data-size;
                p2->t=false;
                p2->id=0;
                p2->next=p1->next;
                p1->data=size;
                p1->t=true;
                p1->id=di++;
                p1->next=p2;
                k=true;
                break;
            }
            else if(p1->data==size&&p1->t==false)
            {
                p1->id=di++;
                p1->t=true;
                k=true;
                break;
            }
            else p1=p1->next;
        }
        if(k==false)
        {
            if(mall-s>=size)
            {
                p1=(struct ab*)malloc(len);
                p1->next=NULL;
                p2->next=p1;
                p1->data=size;
                p1->t=true;
                p1->id=di++;
            }
            else return NULL;
        }
    }
    return head;
}
int search(struct ab *p,int id)
{
    bool k=false;
    while(p!=NULL)
    {
        if(p->id==id)
        {
            p->t=false;
            k=true;
            break;
        }
        p=p->next;
    }
    if(k==false)return 0;
    return 1;
}
void print(struct ab *p1)
{
    cout<<"\nSize\tID\tT/F"<<endl;
    while(p1!=NULL)
    {
        cout<<p1->data<<"\t"<<p1->id<<"\t";
        if(p1->t==true)cout<<"true"<<endl;
        else cout<<"false"<<endl;
        p1=p1->next;
    }
    cout<<endl;
}
ab* bing(struct ab* head)
{
    struct ab *p1=head,*p2=head;
    while(p1!=NULL&&p1->t==0)p1=p1->next;
    head=p1;
    while(p1!=NULL)
    {
        if(p1->next==NULL)return head;
        else p2=p1->next;
        while(p2!=NULL&&p2->t==0)p2=p2->next;
        p1->next=p2;
        p1=p2;
    }
    return head;
}
int main()
{
    int n;
    cout<<"Please enter the number of operations and total memory size"<<endl;
    cin>>n>>mall;
    struct ab *head=NULL;
    while(n--)
    {
        string a;
        int size,id;
        struct ab *aa=head;
        cout<<"Please enter the operation to be performed: ";
        cin>>a;
        if(a=="alloc")
        {
            cout<<"Please enter the size you want to allocate memory: ";
            cin>>size;
            aa=mallo(head,size);
            if(aa==NULL)cout<<"\n\nNULL\tCould not find the assigned area.\n"<<endl;
            else head=aa;
        }
        else if(a=="erase")
        {
            cout<<"Please enter a ID that needs to be freed: ";
            cin>>id;
            if(search(head,id)==0)cout<<"\nThe ID does not exist.\n"<<endl;
        }
        else if(a=="defragment")
            head=bing(head);
        if(aa!=NULL)print(head);
    }
    return 0;
}

程序截图:


模拟内存分配(链表实现)

模拟内存分配(链表实现)

执行的操作:

1.alloc n – 分配n字节的连续内存,并输出被分配的内存块的id;

2.erase x – 释放id为x的内存块;

3.defragment – 对内存进行碎片整理。


  • 6 10
  • alloc 5
  • alloc 3
  • erase 1
  • alloc 6
  • defragment
  • alloc 6

迷失在幽谷中的鸟儿,独自飞翔在这偌大的天地间,却不知自己该飞往何方……