2

回头看两星编程文章不禁看不出下面两行区别的意义:

*curr = entry->next;
curr = &entry->next;

我能看到的唯一区别是第一行更改*curr为指向下一个节点,第二行使一个全新的**指向节点成员(这是下一个循环中的前一个节点)

我突然想到free,在第一个 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;
    }
}

我认为这curr = &entry->next;条线没有必要,您可以使用另一条线两次:

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;
    }
}

然后你可以将它移到 if 语句之上,并为自己节省几行:

void remove_if(node ** head, remove_fn rm)
{
    for (node** curr = head; *curr; )
    {
        node * entry = *curr;
        *curr = entry->next;
        if (rm(entry))
        {
            free(entry);
        }
    }
}

实际上,看起来您根本不需要指针指针,并且可以这样做:

void remove_if(node * head, remove_fn rm)
{
    for (node* curr = head; curr; )
    {
        node * entry = curr;
        curr = entry->next;
        if (rm(entry))
        {
            free(entry);
        }
    }
}

那么他们为什么采用第一种方式呢?表现?还有什么不为人知的?

4

2 回答 2

5

两者完全不同。

curr = &entry->next;

获取变量的地址entry->next,并将其分配给指针变量curr。在这个赋值之后,任何 curr 之前指向的东西都不会改变,但是会少一个对它的引用。

*curr = entry->next;

根本不改变 的值curr,但改变它所指向的任何东西的值,这将具有与以前相同数量的引用,但值不同。

是的,这两者都将具有*curr等于 的效果entry->next,但实际上它们将不同的值写入不同的内存位置并具有其他重要的副作用。

于 2013-06-09T20:47:06.390 回答
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的场景。在这种情况下,您绝不能修改列表,但每次循环时都要修改它。

最后一个变体是错误的,因为您只传入 anode *那么调用者的头指针无法修改。事实上,最终的变体根本没有修改列表。

于 2013-06-09T22:12:16.267 回答