我在free()实现中花了几个小时处理一个特定条件。我搜索了网络和stackoverflow,看看是否有其他人讨论过这个,但我没有找到。我理解第187页及其中描述的3种功能背后的一般概念。第二版188(ANSI)。我是一名专业人士,大多数代码对我来说都很有意义,但是当我弄清楚所有3个函数如何在第一次调用时工作(换句话说,* freep初始化为某些东西)时,我感到难过。
以下是我从代码中得出的步骤: 步骤1.有两个全局变量定义如下
typedef long Align;
union header { /* block header */
struct {
union header *ptr; /* next block if on free list */
unsigned size; /* size of this block */
} s;
Align x; /* force alignment of blocks */
};
typedef union header Header;
static Header base; /* empty list to get started */
static Header *freep = NULL; /* start of free list */
第2步:首先通过malloc()函数,因为第一次,当用户调用malloc()时,上面给出的2个全局变量将不包含任何可用数据。我在本节下面的书中附上了malloc()的代码。我理解' nunits'计算。如果freep == NULL,则freep& prevp被指向& base。因此,首次输入for循环,其中p == prevp-> s.ptr == base.s.ptr == freep == prevp ==& base(sic)。下一个if条件为false,因为base.s.size在第一次调用期间已设置为零。现在,下一个if条件(p == freep)为真,因为它们都指向' base'的地址。所以,此时我们调用morecore(),这将在下面的步骤3中描述。
/* malloc: general-purpose storage allocator */
void *malloc(unsigned nbytes)
{
Header *p, *prevp;
Header *morecore(unsigned);
unsigned nunits;
nunits = (nbytes+sizeof(Header)-1)/sizeof(header) + 1;
if ((prevp = freep) == NULL) { /* no free list yet */
base.s.ptr = freeptr = prevptr = &base;
base.s.size = 0;
}
for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr) {
if (p->s.size >= nunits) { /* big enough */
if (p->s.size == nunits) /* exactly */
prevp->s.ptr = p->s.ptr;
else { /* allocate tail end */
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits
}
freep = prevp;
return (void *)(p+1);
}
if (p == freep) /* wrapped around free list */
if ((p = morecore(nunits)) == NULL)
return NULL; /* none left */
} // end of for loop
}
第3步:morecore()
到目前为止,所有指针都指向& base(全局),我们输入morecore(),调用OS以获得可用的内存空间。 morecore()然后将此内存的开头初始化为Header结构,如下所示:
Header *up;
up = the memory from OS
up->s.size = nu; (number of units, each of size = sizeof(Header))
free( (void*) (up+1) );
return freep;
在init之后,morecore()使用指向下一个地址的参数(在初始Header结构之后)调用free()。 morecore()不会改变freep global,它仍然指向& base。
第4步:输入free()。
我的问题是自由功能,所以我只给出下面的相关部分。
void free( void* ap)
{
Header *bp, *p; // a pointer to base (ie. Header) and a temporary pointer p.
bp = (Header *)ap - 1; // point to block header
for (p = freep; !(bp > p && bp < p->s.ptr) ; p = p->s.ptr)
if ( p >= p->s.ptr && (bp > p || bp < p->s.ptr) )
break; // freed block at start or end of arena.
使用p == freep ==&amp; base仍然输入for循环。在此之后我在条件方面遇到麻烦。 for循环条件将首先执行 - 将基本(全局)地址(p == freep ==&amp; base still)与OS中新获得的空间的地址进行比较(注意 - 此地址通过free的参数得出)。在malloc中,我们将freep == p-&gt; s.ptr初始化为&amp; base。因此,此时p和p-> s.ptr都指向相同的地址。因此,for条件将为TRUE,因为bp不能同时为&gt;和&lt;相同的地址。注意否定,这使得循环条件为TRUE,我们输入if condition。
第5步:
if条件的第一部分是p> = p-> s.ptr。这是正确的,因为p == freep ==&amp; base == p-&gt; s.ptr(在malloc中设置)。 if条件的第二部分为TRUE,因为bp必须>或者&lt;相同的地址(p == p-> s.ptr)。因此,我们打破for循环因为释放的块是竞技场的开始(或竞技场的结束,如果我们通过malloc维护的循环链接的免费记忆列表达到这一点)。
第6步:我的问题在这里
if(bp + bp->s.size == p->s.ptr) { // join to upper nbr
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
}
else bp->s.ptr = p->s.ptr;
继续...... for循环后的第一个if条件为假,因为新分配的内存空间不等于p-&gt; s.ptr,这是&#39; base&#39;的地址。所以,执行else,并将新分配的标题设置为p-&gt; s.ptr == freep-&gt; s.ptr == freep ==&amp; base !!!为什么将这个新指针设置为&#39; base&#39;的地址?全球?
我的第二个问题是为什么2级间接(上面第3行代码)设置bp-&gt; s.ptr,以防条件满足? (我知道这是加入连续的块。)
STEP 7:加入较低的nbr(是书中的评论)
if (p + p->s.size == bp) {
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
}
else p->s.ptr = bp;
freep = p;
由于同样的原因,在第一次传递期间,下一个if条件也将为false,而else子句将p-&gt; s.ptr == base.s.ptr == freep-&gt; s.ptr设置为新分配的内存。那么,在我们第一次通过malloc / morecore / free序列时,下一个语句freep = p是多余的?在所有这些步骤结束时,freep仍然指向&#39; base&#39; ?没有变化 ?感觉就像我在逻辑上犯了一些错误。
关于ANSI标准C关于工会的说法的一点澄清。这可以追溯到我上面使用&#39; typedef&#39;的第一个代码snipet。我认为静态联合中的所有成员(比如静态Header基础)都被编译器初始化为零?如果我没有将它们声明为静态怎么办?在这种情况下struct s.header ptr会为NULL吗?
如果我在第7步的逻辑中犯了任何错误,请指出第一遍。我还要感谢,如果有人花时间写清楚(我已经完成的方式)free()如何工作以及free()中各种条件的伪代码。这个帖子对学生/新手非常有用。
感谢您的时间和解释。
答案 0 :(得分:1)
为什么要将这个新指针设置为&#39; base&#39;的地址?全球?
在malloc实现的描述中,它说最后一个块有指向第一个块的指针。因为第一次调用函数你不会有任何块,所以这个块指向自身。
那么,在我们第一次执行malloc / morecore / free序列时,下一个语句freep = p是多余的?在所有这些步骤结束时,freep仍然指向&#39; base&#39; ?没有变化 ?感觉就像我在逻辑上犯了一些错误。
我相信,在第一次调用malloc时,你的推理中没有错误 freep = p = &base
。
我想,通常这段代码非常棘手。在这个问题(Explain this implementation of malloc from the K&R book)中,您可以找到更多关于k&amp; r malloc()
实现的批评
但是对于你的情况,我认为名字free()
让你感到困惑。因为函数free()
实际上有两个目的:初始化全新的自由列表并显然释放以前分配的内存。另外&#34;代码完成&#34; S.Macconnell说,具有多种用途的功能并不是一个好主意。
所以在第一次通过中,实际上你不需要一些额外的任务(初始化free()
的制度)。但是在free
的下一次调用(实际释放先前分配的内存的状态)对于指向最后一块空闲列表内存以便合并内存非常有用。
关于ANSI标准C关于工会的说法的一点澄清。这可以追溯到我上面使用&#39; typedef&#39;的第一个代码snipet。我认为静态联合中的所有成员(比如静态Header基础)都被编译器初始化为零?
是的,引自c89 draft(3.5.7。初始化):
如果未初始化具有静态存储持续时间的对象 显式地,它被隐式初始化,好像每个成员都有 算术类型被赋值为0,每个成员都有指针类型 被赋予空指针常量。如果一个对象有自动 存储持续时间未明确初始化,其值为 不确定的。
如果我没有将它们声明为静态怎么办?在这种情况下struct s.header ptr会为NULL吗?
我相信这将是垃圾。