1

下面是我从linus 获得的关于理解指针的代码。

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

4 回答 4

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;从第一个例子,唯一的区别是你指向 current 的成员的地址nextstruct Node不是指向整个 current struct Node

于 2014-10-20T18:30:15.800 回答
0

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

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

  1. 保留前一个(或头)链的“下一个”成员的地址。

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

  3. 如果是,则使用 pp 引用间接操纵前一个链的“下一个”成员以指向当前链的“下一个”,因此实际上链表将跳过当前链,同时保持其完整性。

于 2014-10-20T18:13:54.050 回答
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点以检查列表中的下一个值。

于 2014-10-20T19:43:34.463 回答
-1

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

所以这些行:

pp = &entry->next;

*pp= entry->next;

是不同的。

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

之所以entry->next被“移除”后可以被引用,是因为它在被从链表中移除的同时,仍然存在于内存中,仍然可以被访问。

于 2014-10-20T17:52:26.157 回答