需要帮助理解C中的链表代码

时间:2014-10-20 17:47:28

标签: c pointers linked-list double-pointer

我从linus on understanding pointers获得了以下代码。

typedef struct list_entry {
   int val;
   struct list_entry *next;
} list_entry;    


list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;

while (entry) {
    if (entry->val == to_remove)
        *pp = entry->next;            //6      

    pp = &entry->next;                //8   
    entry = entry->next;
} 

有人可以帮助理解第6和第8行吗?如果entry-> val == to_remove,则评估第6行,并且* pp成为删除后的下一个条目,那么第8行之后会做什么?当前条目已被删除,如何在第8行重新使用此条目?

另外,我知道* pp表示指针pp的值,而& entry-> next表示pp的地址,我总是对何时使用*以及何时&应该使用。具体来说,第6行可以是:

pp = &entry->next; 

和第8行是:

*pp= entry->next; 

如果没有,为什么?

4 个答案:

答案 0 :(得分:1)

更新

博客中的代码不完整,并假设只删除一个元素,并且不需要免费。如果要删除两个或多个连续元素,则序列中的第二个元素将不会被删除。

正确的代码是,也假设不必释放节点:

while (entry) {
    if (entry->val == to_remove)
        *pp = entry->next;           
    else
        pp = &entry->next;  

    entry = entry->next;
} 

如果你必须释放节点:

while (entry) 
{
    if(entry->value == to_remove  )
    {
        *pp = entry->next;            
        free( entry ) ;
        entry = *pp ;
    }
    else
    {
        pp = &entry->next;               
        entry = entry->next;
    }
} 



编写整个结构确实有助于理解这一点。

struct Node
{
    int val ;
    struct Node* next ; //hint, this has an address too.

} ;

诀窍在声明中

pp = &entry->next ;

这看起来像是指向next节点,但实际上你只是获取当前节点指针的地址。 差异很大!

因此pp = &entry->next ;几乎等同于第一个示例中的prev = entry;,唯一的区别是您指向当前next的成员struct Node的地址指向整个当前struct Node

答案 1 :(得分:0)

在此示例代码中,pp存储了' next'的地址。上一个链的成员,以便在当前链标记为删除的情况下,然后' next'可以修改前一个链的成员以指向“下一个”'现在被删除的链。间接修改是通过应用*运算符完成的。

第6行和第8行不能根据您的问题进行修改,因为代码将无法达到预期的效果。

  1. 保留' next'的地址前一个(或头)链的成员。

  2. 检查当前链是否标记为要删除。

  3. 如果是,那么使用pp引用间接操纵前一个链接下一个'会员指向' next'当前,所以实际上链表将跳过当前链,同时保持其完整性。

答案 2 :(得分:0)

这里发生了什么:

list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;

// we start with entry being head and pp being an address of head
while (entry) {
// while there is a list_entry which is not NULL...
    if (entry->val == to_remove)
        // if entry points to value that should be removed, 
        // then store the address of the next entry in whatever pp points to now
        // (which effectively means removing that entry)
        *pp = entry->next;            //6      
    // pp is now an address of the next entry
    pp = &entry->next;                //8   
    // move to the next entry to start the next iteration
    entry = entry->next;
} 

此代码的作用:它遍历列表并删除所有标记为已删除的条目。

它是如何做到的:

  • 最初,pp指向头部。

  • 从头开始,它会越过列表。

  • 只要当前条目指向的值标记为“已删除”,pp就会在当前列表条目的地址中存储下一个列表条目的地址。如果pp指向头部,则意味着头部被丢弃并且它开始指向下一个元素。如果pp指向列表中间的元素,则表示此元素已被删除(因为现在前一个元素将指向被删除元素之后的元素。)

  • 完成后,它会移动entry点以检查列表中的下一个值。

答案 3 :(得分:-1)

&表示返回某些内容的地址。 *表示访问指针指向的变量。

所以行:

pp = &entry->next;

*pp= entry->next;

不同。

第一个设置指针包含entry->next的地址,而第二个设置pp指向的变量的值等于entry->next

entry->next被删除"之后可以被引用的原因是因为当它从链表中删除时,它仍然存在于内存中,仍然可以被访问。 / p>