首页 > 解决方案 > 了解推送功能

问题描述

我很难理解 C 中链表的推送功能。例如,我有以下结构

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;

推送功能是这样给出的

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.

标签: clistpointers

解决方案


我的问题是为什么new_node->next分配给取消引用head

因为head函数的参数push是指向头指针的指针。您必须取消引用它一次才能获得(假定的)指向链表头节点的指针。这当然必须在调用方匹配——它们必须传递列表头指针的地址。

我认为head应该是一个指针,从而使*head下一个node_t本身。

head所呈现的代码通过在不同的范围内使用相同的标识符“”来表示不同级别的间接性,从而稍微混淆了这一点。在函数push中,参数head是 a node_t **。是的,这是一个指针,但不是指向头节点。相反,它指向另一个指针,该指针又指向头节点。 *head有一个node_t *,没有一个node_t

其次,最后一行*head = new_node是否与head = &new_node? 更何况,是不是一样**head = &new_node

不,这些都是不同的,这直接来自于head,*head**head都指定不同的对象这一事实。在函数push()中,

  • head指定函数参数,它具有类型node_t ** 并且是函数的局部参数。赋值head = &new_node将是类型正确且总体有效的,设置head为指向函数的局部变量new_node,但这没什么用,因为它不会向函数的调用者传达任何内容,并且它在函数本身内没有任何特殊用途。

  • *head当然,指定对象head指向的对象,由函数调用者选择。它有类型node_t *。调用者可以访问该指针对象,例如,它可以是调用者的局部变量之一。赋值*head = new_node修改了调用者可访问的对象,因此调用者可以看到它的效果,这就是参数作为双指针的目的。

  • **head指定*head指向的对象 a node_t. 调用者也可以访问该对象,但修改它不会满足函数的目的。然后调用者将得到相同的一个node_t对象,只是内容不同。在任何情况下,表达式&new_nodeanode_t **都没有正确的赋值类型**head。如果一个人真的打算分配给它,那么一个类型正确(但在语义上不合适)的选项将是**head = *new_node.

最后一个对我来说最有意义,因为我们将指针的指针作为push.

将指针传递给指针的原因是函数可以修改指向的指针。结果是之后,调用者的指针指向由 分配的节点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.


推荐阅读