指针指针:* a = b-> c和a =& b-> c之间的差异

时间:2013-06-09 20:37:41

标签: c pointers

回顾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);
        }
    }
}

那他们为什么要这样做呢?性能?还有其他一些模糊的东西?

2 个答案:

答案 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 *然后调用者的头指针无法被修改。实际上,最终变体根本不会修改列表。