回顾two star programming文章,我忍不住看不出以下两行之间差异的重要性:
*curr = entry->next;
curr = &entry->next;
我能看到的唯一区别是第一行将*curr
更改为指向下一个节点,第二行创建一个全新的**
指向节点成员(这是之前的下一循环中的节点)
我发现{{1}第一个if块中的条目会阻止第二行在下一个循环中正常工作,但在这种情况下为什么不在这两种情况下只使用第一行?这是性能问题吗?
修改:请阅读link above标题为“双星编程”的第二个代码块
编辑:所以我似乎解释得很糟糕(抱歉!)所以让我看看我是否可以解释一下这个问题。
这是本文的源代码。
free
根据我的估算,void remove_if(node ** head, remove_fn rm)
{
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
curr = &entry->next;
}
}
行不是必需的,你可以使用另外两行:
curr = &entry->next;
然后你可以将它移到if语句之上并保存几行:
void remove_if(node ** head, remove_fn rm)
{
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
*curr = entry->next;
}
}
事实上,你看起来根本不需要指针指针,可以这样做:
void remove_if(node ** head, remove_fn rm)
{
for (node** curr = head; *curr; )
{
node * entry = *curr;
*curr = entry->next;
if (rm(entry))
{
free(entry);
}
}
}
那他们为什么要这样做呢?性能?还有其他一些模糊的东西?
答案 0 :(得分:5)
两者完全不同。
curr = &entry->next;
获取变量entry->next
的地址,并将其分配给指针变量curr
。在这个赋值之后,无论先前指向的curr都没有改变,但是对它的引用会少一些。
*curr = entry->next;
根本不会更改curr
的值,而是更改它所指向的任何值,其值与之前的引用数相同,但值不同。
是的,这两个都会产生*curr
等于entry->next
的效果,但它们实际上会将不同的值写入不同的内存位置,并产生其他重要的副作用。
答案 1 :(得分:1)
文章中的代码是正确的,并且您提出的所有三个变体都不正确。让我们先看看正确的代码,并附上一些注释:
void remove_if(node ** head, remove_fn rm)
{
// node ** passed to allow use to modify caller's head pointer
for (node** curr = head; *curr; )
{
// curr is a local variable, that points to a node pointer
// curr points either to the caller's head pointer, or to
// a next pointer within the list
node * entry = *curr;
if (rm(entry))
{
// remove this entry, which means modifying the list
*curr = entry->next;
// modify *curr modifies either caller's head pointer
// or a next pointer
free(entry);
}
else
// did not remove, so do not modify the list
curr = &entry->next;
}
}
这里需要注意的关键点:
*curr = entry->next
修改了列表。curr = &entry->next
不会修改列表。你提出的前两个版本是错误的,因为它们确实
*curr = entry->next
每次迭代。分配到*curr
会修改列表。想象一下rm()
总是返回false的情况。在这种情况下,您必须永远不要修改列表,但每次循环都要修改它。
最后的变体是错误的,因为你只传入node *
然后调用者的头指针无法被修改。实际上,最终变体根本不会修改列表。