【问题标题】:Linked Lists && pass by reference链接列表 && 通过引用传递
【发布时间】:2021-08-15 01:12:52
【问题描述】:

嗨,我是 C 的初学者,你能解释一下为什么我在给定的 prev_node 之后插入一个新节点时不需要通过引用调用(我对 prev 节点进行了更改,我更改了 prev->next 所以我需要通过引用调用) 但是当我在列表的开头或结尾插入一个新节点时我需要双指针(为什么只有当我将头部作为参数时我才需要通过引用调用)

/* Given a reference (pointer to pointer) to the head of a list and
           an int, inserts a new node on the front of the list. */
        void push(struct Node** head_ref, int new_data)
        {
            /* 1. allocate node */
            struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
         
            /* 2. put in the data  */
            new_node->data  = new_data;
         
            /* 3. Make next of new node as head */
            new_node->next = (*head_ref);
         
            /* 4. move the head to point to the new node */
            (*head_ref)    = new_node;
        } 
 
        /* Given a reference (pointer to pointer) to the head
           of a list and an int, appends a new node at the end  */
        void append(struct Node** head_ref, int new_data)
        {
            /* 1. allocate node */
            struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
         
            struct Node *last = *head_ref;  /* used in step 5*/
         
            /* 2. put in the data  */
            new_node->data  = new_data;
         
            /* 3. This new node is going to be the last node, so make next of
                  it as NULL*/
            new_node->next = NULL;
         
            /* 4. If the Linked List is empty, then make the new node as head */
            if (*head_ref == NULL)
            {
               *head_ref = new_node;
               return;
            }


/* Given a node prev_node, insert a new node after the given
           prev_node */
        void insertAfter(struct Node* prev_node, int new_data)
        {
            /*1. check if the given prev_node is NULL */
            if (prev_node == NULL)
            {
              printf("the given previous node cannot be NULL");
              return;
            }
         
            /* 2. allocate new node */
            struct Node* new_node =(struct Node*) malloc(sizeof(struct Node));
         
            /* 3. put in the data  */
            new_node->data  = new_data;
         
            /* 4. Make next of new node as next of prev_node */
            new_node->next = prev_node->next;
         
            /* 5. move the next of prev_node as new_node */
            prev_node->next = new_node;
        }

【问题讨论】:

  • “引用调用”是一个高级语言概念,不适用于 C。所有函数参数都是按值传递的——只是其中一些值是内存地址,你可以取消引用以访问它们指向的内容。

标签: c pass-by-reference singly-linked-list


【解决方案1】:

您需要通过引用传递一个对象,您将在函数中自行更改它。否则该函数将处理传递对象的副本。

在所有函数示例中,您都传递了一个可以通过引用更改的对象。

在函数 push 和 append 中,您通过引用传递指向可能在函数中更改的头节点的指针。

在函数insertAfter 中,您通过引用传递当前节点的下一个对象(数据成员)

void insertAfter(struct Node* prev_node, int new_data)
                 ^^^^^^^^^^^^^^^^^^^^^^

所以取消引用指针,您可以更改下一个对象,它是指向节点的数据成员

prev_node->next = new_node;

【讨论】:

    【解决方案2】:

    push()append() 需要修改正在传入的Node* 指针本身。他们正在将新的Node 对象的内存地址分配给传递的Node*。因此,您需要通过指针传递Node*,以便修改可以反映回调用者。例如:

    struct Node* head = NULL;
    push(&head, 12345);
    // head points at the new Node...
    

    如果调用者的Node* 改为按值传递,则Node* 不会被更新,例如:

    struct Node* head = NULL;
    push(head, 12345);
    // head is still NULL, and the new Node is leaked!
    

    insertAfter() 不需要修改被传入的Node* 指针本身。它只修改被指向的Node 对象的内容(具体来说, Nodenext 字段)。 Node* 指针本身并没有被更改为指向不同的 Node 对象,它将继续指向与它开始时相同的 Node,因此它可以按值传递。

    【讨论】:

    • 您能否再解释一下,因为在我修改了 prev_node 的一个成员之后,我在 Insert 中可能有一些误解(最后一行 prev_node->next 如何将此更改反映给调用者如果我不通过引用?
    • 您正在修改Node 对象的成员,您并未修改指向该Node 对象的Node* 指针。它们是有区别的。因此,将Node* 指针按值传递给insertAfter() 是安全的,因为Node* 本身并没有被更改为指向不同的Node 对象,例如push()append()。正在修改 Nodenext 字段。退出时,传递的Node* 将继续指向与进入时相同的Node
    猜你喜欢
    • 2021-08-04
    • 2019-09-11
    • 1970-01-01
    • 2023-03-11
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多