簡體   English   中英

需要幫助來了解C中的鏈接列表代碼

[英]Need help in understanding linked list code in C

下面的代碼是我從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; 

如果沒有,為什么?

更新:

博客中的代碼不完整,並假定將僅刪除一個元素,並且不需要免費。 如果要刪除兩個或多個連續元素,則序列中的第二個元素將不會刪除。

正確的代碼是,它還假定不必釋放節點:

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; 與第一個示例相比,唯一的區別是您指向當前struct Node next的成員的地址,而不是指向整個當前struct Node

在此示例代碼中,pp存儲前一個鏈的“下一個”成員的地址,以便在標記當前鏈為要刪除的情況下,可以修改前一個鏈的“下一個”成員以指向現在要刪除的鏈的“下一個”。 間接修改是通過應用*運算符完成的。

不能根據您的問題修改第6行和第8行,因為這樣代碼將無法達到預期的效果。

  1. 保留上一個(或頭)鏈的“下一個”成員的地址。

  2. 檢查當前鏈條是否標記為要移除。

  3. 如果使用pp引用間接操縱前一個鏈的“ next”成員指向當前鏈的“ next”,則實際上,鏈表將跳過當前鏈,同時保持其完整性。

這里發生了什么:

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指向head,則意味着head被丟棄,它開始指向下一個元素。 如果pp指向列表中間的元素,則意味着該元素已刪除(因為現在,上一個元素將指向被刪除元素之后的元素)。

  • 完成之后,它將移動entry點以檢查列表中的下一個值。

&表示返回某物的地址。 *表示訪問指針所指向的變量。

所以這行:

pp = &entry->next;

*pp= entry->next;

是不同的。

第一個將指針設置為包含entry->next的地址,第二個將pp指向的變量的值設置為等於entry->next

“刪除” entry->next之后可以引用entry->next的原因是,當它從鏈接列表中刪除時,它仍然存在於內存中並且仍然可以訪問。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM