#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define Type int
typedef struct MBox{
struct MBox * pre;
int size;
struct MBox * next;
int begin;
int tag; //是否被使用 0是空闲 1是占用
int end;
}MBox,*pMBox;
//存储内存块的信息
typedef struct Memory{
int size;
Type *base; //真正的内存
pMBox first; //指向第一个内存块
}Memory,*pMemory;
//一条内存
void fill(pMemory pM,int s,int e,int j){
for(s;s<=e;s++)
pM->base[s]=j;
}
//填充是否使用
//s是开始填充位置,e为结束填充位置
//j是0或1
//0是空闲内存,1是已使用内存
int init(pMemory pM){
int i;
printf("Well,please enter the memory size:");
scanf("%d",&pM->size);
if(pM->base=(Type *)malloc(sizeof(Type)*(pM->size))){
pM->first=(pMBox)malloc(sizeof(MBox));
pM->first->begin=0;
pM->first->size=pM->size;
pM->first->next=pM->first->pre=NULL;
pM->first->end=pM->size-1;
pM->first->tag=0;
for(i=0;i<pM->size;i++)
pM->base[i]=0;
fill(pM,pM->first->begin,pM->first->end,0);
return 1;
}
else return 0;
}
//初始化内存条信息
int ask_m(pMemory pM,int size){
int i,flag=0;
pMBox pMB1,pMB2;
for(pMB1=pMB2=pM->first;pMB1!=NULL;pMB1=pMB1->next){
pMB2=pMB1;
if(pMB2->tag==0 && pMB2->size>=size){
flag=1;
break;
}
}
if(pMB2->size<size) //找不到就返回假,请求失败
return 0;
else if(pMB2->size>size){ //找到比请求所需的大的内存,分割
pMB1=(pMBox)malloc(sizeof(MBox));
pMB1->next=pM->first;
pMB1->pre=NULL;
pMB1->next->pre=pMB1;
pM->first=pMB1;
pMB1->begin=pMB2->begin;
pMB1->end=pMB1->begin+size-1;
pMB2->begin=pMB1->end+1;
pMB2->size=pMB2->size-size;
pMB1->size=size;
pMB1->tag=1;
fill(pM,pMB1->begin,pMB1->end,1);
return 1;
}
else if(pMB2->size==size){ //找到大小刚好合适的直接使用
pMB2->tag=1;
fill(pM,pMB2->begin,pMB2->end,1);
return 1;
}
}
//请求内存
int free_m(pMemory pM,int MBox_num){
int i,flag=0;
pMBox pMB1,pMB2,pMB3;
if(MBox_num==0)
return 0;
for(i=1,pMB1=pM->first;i<MBox_num && pMB1!=NULL;i++,pMB1=pMB1->next); //索引需要释放的位置
if(pMB1==NULL || pMB1->tag==0) //空闲块,直接返回
return 0;
else {
for(pMB2=pMB1;pMB2!=NULL;pMB3=pMB2,pMB2=pMB2->next){ //寻找第MBox_num要释放的内存块,flag标记是否已经找到可合并内存块
if(pM->first==pMB1) //如果是第一个,则处理与其他有区别
pM->first=pMB1->next; //因为涉及到内存条的first
if(pMB2->begin==pMB1->end+1 && pMB2->tag==0){ //寻找是否能找到合并的,条件大家推导下
pMB2->begin=pMB1->begin;
pMB2->size=pMB2->size+pMB1->size;
flag=1;
break;
}else if(pMB2->end+1==pMB1->begin && pMB2->tag==0){ //也是寻找可合并的
if(pM->first==pMB1)
pM->first=pMB1->next;
pMB2->end=pMB1->end;
pMB2->size=pMB2->size+pMB1->size;
flag=1;
break;
}
}
if(pMB2==NULL) //当pMB2为NULL时,pMB2等于它的上一个备份pMB3
pMB2=pMB3;
if(flag==0){ //flag==0就是没有合并的情况
if(i==1){ //i==1意味着是第1个内存块要被处理,涉及到pM->first
pMB2->next=pMB1;
pM->first=pMB1->next;
pMB1->next->pre=NULL;
pMB1->pre=pMB2;
pMB1->next=NULL;
}else {
pMB2->next=pMB1;
pMB1->pre->next=pMB1->next;
pMB1->next->pre=pMB1->pre;
pMB1->pre=pMB2;
pMB1->next=NULL;
}
}
fill(pM,pMB1->begin,pMB1->end,0);
if(flag==1)
free(pMB1);
else pMB1->tag=0;
}
Man_m(pM);
}
//释放内存
//MBox_num是释放的占用块的索引
void Travel(pMemory pM){
int i;
printf("\nTraveling the mermory!\n");
for(i=0;i<pM->size;i++)
printf("%d ",pM->base[i]);
printf("\n\n");
}
//遍历内存使用情况
void showBox(pMemory pM){
int i=1;
pMBox pB=pM->first;
printf("\nTraveling the MBox!\n");
while(pB!=NULL){
printf("************************* MBox%d:0x%.8x *****************************\n",i++,pB);
printf("* pre size next begin tag end *\n");
printf("* 0x%.8x ",pB->pre);
printf(" %.10d ",pB->size);
printf(" 0x%.8x ",pB->next);
printf(" %.10d ",pB->begin);
printf(" %.10d ",pB->tag);
printf(" %.10d *\n",pB->end);
printf("**************************************************************************\n\n");
pB=pB->next;
}
}
//遍历内存块信息
int Man_m(pMemory pM){
pMBox pMB1,pMB2,pMB3;
MBox MB;
int i,j,k;
for (pMB3=pM->first;pMB3->tag==1 && pMB3!=NULL;pMB3=pMB3->next); //因为空闲块都在后面
//所以找到第一块空的,后面的都是空的了
if(pMB3==NULL)
return 0; //这是找不到占用块的情况
for(pMB2=pMB3,i=1;pMB2->next!=NULL;i++,pMB2=pMB2->next); //这是计算一共有多少个空闲块
if(i==1)
return 0;
else {
for(j=1;j<i;j++){ //简单用冒泡排序把小的空闲块排到前面
pMB1=pMB3;
pMB2=pMB3->next;
for(k=1;k<i;k++,pMB1=pMB1->next,pMB2=pMB2->next){
if(pMB2->size<pMB1->size){
MB.size=pMB1->size;
MB.begin=pMB1->begin;
MB.end=pMB1->end;
pMB1->size=pMB2->size;
pMB1->begin=pMB2->begin;
pMB1->end=pMB2->end;
pMB2->size=MB.size;
pMB2->begin=MB.begin;
pMB2->end=MB.end;
}
}
}
}
}
//整理空闲块,保持小空闲块在前,大的空闲在后
//易于请求内存时先利用小的,再拆分大的
int main(){
Memory m;
init(&m);
ask_m(&m,2);
Travel(&m);
showBox(&m);
ask_m(&m,4);
Travel(&m);
showBox(&m);
free_m(&m,2);
Travel(&m);
showBox(&m);
ask_m(&m,2);
Travel(&m);
showBox(&m);
return 0;
}