描,节省时间*/
return (void *)(p+1); /*返回去头部单元的空闲空间*/
}
if(p == freep) /*闭环的空闲链表,第一次调用malloc申请,或扫描一遍,未发现足够大的空间*/
if((p = morecore(nunits)) == NULL) /*向系统申请空间*/
return NULL; /*未申请成功,*/
}
}
通过下面的morecore()和free()函数的程序分析可知,在向系统成功申请空间后,p将指向有足够空间的空闲块。但在此代码中,进入下一此空闲块扫描前,p将指向下一块不足的空闲块,导致多扫描了一遍。个人觉得,如果空间足够,可以多申请一个静态指针beforefreep,指向freep的前一个空闲块。这样上面代码可添加一句,提高效率:
if(p == freep){ /*这样要添加大括号*/
if((p = morecore(nunits)) == NULL)
return NULL;
p = beforefreep;
}
或
if(p == freep) /*这里可以不用加大括号,else与最近的if匹配*/
if((p = morecore(nunits)) == NULL)
return NULL;
else
p = beforefreep;
向系统申请空间的时,不是按需分配,而是有一个最小申请单元数。让您足够用,这次用不完可以留着下次用,不用每次都向系统申请,又不会系统浪费空间。
真正向系统申请空间,还需调用系统调用sbrk(n)(UNIX下),若申请成功,该指针返回指向n个字节的存储空间;若申请失败,返回-1(不是NULL)。返回的指针类型是char *(应该是最小的存储空间单元)。
#define NALLOC 1024 /*最小申请单元数*/
/*morecore函数:向系统申请更多的存储空间*/
static Header *morecore(unsigned nu) /*返回的是静态空闲块链表指针*/
{
char *cp, *sbrk(int);
Header *up;
if(nu < NALLOC)
nu =NALLOC;
cp = sbrk(nu * sizeof(Header)); /*调用系统调用申请系统空间*/
if(cp == (char *) -1)
return NULL; /*申请失败,没有空间*/
up = (Header *)cp; /*转换为Header*指针类型*/
up->s.size = nu; /*设置此空间块的大小*/
free((void *)(up +1)); /*释放空间*/
return freep;
}
这里的返回的freep,在free中更新了,才返回的。当初也想过既然freep都是静态全局变量了,那这里为什么还要返回一个静态变量呢,直接在函数里赋值就好了。其实这里有成功与失败,所以程序来需要判断申请结果,而且返回的freep是与申请最相关东西。
free(void *ap)函数就是释放指针ap所指的空间,具体要释放的大小在ap前一个指针,即头部信息里。释放主要就是为了把此空间插入到空闲块链表中。所以要找到此空间块两边的空闲块(也有可能只有一块空闲块,即入口base)。然后判断是否与前一块相连,与后一块相连,相连的话,合并成一块,否则直接在中间插入一个新的空闲块链表。
/*free函数:释放ap,将ap块放入空闲链表中*/
void free(void *ap)
{
Header *p, *bp;
bp =(Header *)ap -1; /*指向ap块的头部*/
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) /*找到bp所在空闲链表中的位置*/
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr)) /*判断是否在链表的开头或末尾*/
break;
if(bp + bp->s.size == p->s.ptr){ /*先判断能否与高地址的空闲块合并,即与后一块合并*/
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
}
else
bp->s.ptr = p->s.ptr; /*不能合并,bp指向后一块地址*/
if(p + p->s.size == bp){ /*再判断能否与地地址的空闲块合并,即与前一块合并*/
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
}
else
p->s.ptr =bp; /*不能合并,p指向bp地址*/
freep =p;
}
注:中文版翻译的又有歧义了,原著分别是“join to upper nbr”和“jointo lower nbr”。

这个free程序,处理的太妙了。一般思维,先与前一块合并,再与下一块合并,如下面的程序(显然比我的好多了):
if(p + p->s.size == bp){ /*与前一块相连?*/
if(bp + bp->s.size == p->s.ptr){ /*与后一块相连?*/
p->s.size += bp->s.size + p->s.ptr->s.size;
p->s.ptr = p->s.ptr->s.ptr;
}else
p->s.size += bp->s.size;
}else{
if(bp + bp->s.size == p->s.ptr){ /*与后一块相连?*/
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
p->s.ptr = bp;
}else /*不与任何一块相连*/
bp->s.ptr = p->s.ptr;
p->s.ptr = bp;
}
从这里可以看出,通过malloc申请后的空间,并没有初始化,所以在使用前记得初始化,不小心当做右值使用,出错的概率很大。
《C程序设计语言》(第2版 新版)不愧是经典,值得细读和巩固。感谢作者!
写了很久才写完,有错误或不好的地方,欢迎各位指正和批评!也感谢您花时间阅读!