簡體   English   中英

了解推送 function

[英]Understanding the push function

我很難理解 C 中的鏈表的推送 function。 以我有以下結構為例

typedef struct node {
    int val;
    struct node * next;
} node_t;

我已經創建了一個這樣的鏈接列表

  // creating list
  node_t * head = NULL;
  head = (node_t *) malloc(sizeof(node_t));

  // checking if list is initialised sucessfully
  if (head == NULL) {
      return 1;
  }

  // 1st and 2nd element
  head = (node_t *) malloc(sizeof(node_t));
  head->val = 1;    
  head->next = (node_t *) malloc(sizeof(node_t));
  head->next->val = 2;
  head->next->next = NULL;

推送 function 是這樣給出的

void push(node_t ** head, int val) {
    node_t * new_node;
    new_node = (node_t *) malloc(sizeof(node_t));

    new_node->val = val;
    new_node->next = *head;
    *head = new_node;
}

我的問題是為什么new_node->next分配給取消引用的head 我認為head應該是一個指針,因此使*head成為下一個node_t本身。 new_node.next是一個指針,因此它應該是new_node->next = head嗎?

其次,最后一行*head = new_node是否與head = &new_node相同? 更何況,它和**head = &new_node嗎? 最后一個對我來說最有意義,因為我們將指針的指針作為push的參數傳遞。

我的問題是為什么new_node->next分配給取消引用的head

因為function pushhead參數是指向head指針的指針。 您必須取消引用它一次才能獲得(假定的)指向鏈表頭節點的指針。 這當然必須在調用方匹配——它們必須傳遞列表頭指針的地址。

我認為head應該是一個指針,因此使*head成為下一個node_t本身。

所呈現的代碼通過在不同的范圍內使用相同的標識符“ head ”來表示不同級別的間接性,從而稍微混淆了這一點。 在 function push中,參數head是一個node_t ** 是的,這是一個指針,但不是指向頭節點。 相反,它指向另一個指針,該指針又指向頭節點。 *head有一個node_t * ,而不是node_t

其次,最后一行*head = new_node是否與head = &new_node相同? 更何況,它和**head = &new_node嗎?

不,這些都是不同的,這直接源於head*head**head都指定不同的對象這一事實。 在 function push()中,

  • head指定 function 參數,其類型為node_t **並且是 function 的本地參數 賦值head = &new_node將是類型正確且整體有效的,將head設置為指向函數的局部變量new_node ,但這沒什么用,因為它不會向函數的調用者傳達任何內容,並且它在內部沒有特殊用途function 本身。

  • *head當然指定 object 指向哪個head ,由函數調用者選擇。 它的類型為node_t * 調用者可以訪問該指針 object,例如,它可以是調用者的局部變量之一。 賦值*head = new_node修改了調用者可訪問的 object,因此調用者可以看到其效果,這就是參數作為雙指針的目的。

  • **head指定*head指向的 object,一個node_t 調用者也可以訪問 object,但修改它不會滿足函數的目的。 然后調用者將留下相同的node_t object,只是內容不同。 在任何情況下,表達式&new_node ,一個node_t ** ,都沒有正確的類型來分配給**head 如果一個人真的打算分配給它,那么一個類型正確(但在語義上不合適)的選項將是**head = *new_node

最后一個對我來說最有意義,因為我們將指針的指針作為push的參數傳遞。

將指針傳遞給指針的原因是為了讓指向的指針可以被 function 修改。 結果是之后,調用者的指針指向由push分配的節點,而該節點的next指針指向調用者的指針最初指向的節點。 這正是將節點添加到列表中所需要的。 調用者的視圖如下所示:

在推()之前

  X --next--> ... --next--> NULL
  |
  v
Value1        ...

推送后(Value2)

  Y --next--> X --next--> ... --next--> NULL
  |           |
  v           v
Value2      Value1        ...

但是,如果push分配給**head ,則結果將是

  X --next--> (depends)
  |
  v
Value2

請注意,現在Value1消失了,取而代之的是Value2

push function 中, head是一個 ' pointer ' 指向一個 '指向頭節點的指針'。 出於理解代碼的目的,將head視為“指向頭節點的指針的地址可能會更有幫助。

push function 中的代碼為:

  1. 獲取當前的“指向頭節點的指針”(通過取消引用head )並將其附加到new_nodenext成員,並且
  2. 通過獲取指向new_node的指針並通過取消引用 head 將其寫回“指向頭節點的指針”,使new_node成為新的列表head

除了前面的答案。

當您的彈出/推送操作為空時,請注意您對“列表”的處理。 想想你會在你的內部表現中考慮什么“空虛”。 是否會有一個指向任何東西的頭,或者會有“假”節點?

從技術上講,您所做的是隊列,典型的測試是填充它,然后排空,然后再次嘗試從空排空。

PS。 一點風格評論。 您正在使用'struct node => node_t'。 您可以簡單地將代碼中的“node_t”替換為“struct node”。 只是沒有實際區別。 但是如果你選擇它作為指向結構的指針,代碼會更好讀(在進一步的開發中)。

暫無
暫無

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

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