将元素添加到链表时,为什么不使用指针指针?

时间:2013-02-13 17:58:42

标签: c pointers

我见过这个问题:

使用以下代码在列表中添加元素:C linked list inserting node at the end

int addNodeBottom(int val, node *head){

    //create new node
    node *newNode = (node*)malloc(sizeof(node));

    if(newNode == NULL){
        fprintf(stderr, "Unable to allocate memory for new node\n");
        exit(-1);
    }

    newNode->value = val;
    newNode->next = NULL;  // Change 1

    //check for first insertion
    if(head->next == NULL){
        head->next = newNode;
        printf("added at beginning\n");
    }

    else
    {
        //else loop through the list and find the last
        //node, insert next to it
        node *current = head;
        while (true) { // Change 2
            if(current->next == NULL)
            {
                current->next = newNode;
                printf("added later\n");
                break; // Change 3
            }
            current = current->next;
        };
    }
    return 0;
} 

如果我们要在内部更改并且我们希望更改在函数外部传播,为什么head作为节点*head而不是node **head传递?我在这里缺少什么?

3 个答案:

答案 0 :(得分:3)

head永远不会直接在此函数中修改。只有head->next被分配给另一个值。因此,您不需要使用指针指针。

答案 1 :(得分:0)

从根本上说,没有理由不能。事实上,这是Linus Torvalds指出的展示掌握指针的事情之一。相关问题:Using pointers to remove item from singly-linked list

答案 2 :(得分:0)

使用指向指针的指针可能会使代码变得更优雅,如下所示:

int addNodeBottom(int val, node **link){
    node *newNode = ...;
    ...
    if(*link == NULL){
        printf("added at beginning\n");
    }
    else
    {
        while (*link)
            link = &(*link)->next;
        printf("added later\n");
    }
    *link = newNode;
    return 0;
}

...
addNodeBottom(some_val, &head->next);

......这样的事情。虽然不是最大的区别,但也许更好一点。如果列表没有为头部使用虚拟节点,并且当它添加到列表的开头而不是结尾时不需要打印,则会更简单。在这种情况下,我们可以做到:

void addNodeBottom(int val, node **link){
    node *newNode = ...;
    ...
    while (*link)
        link = &(*link)->next;
    *link = newNode;
}
...
addNodeBottom(some_val, &head);

...开始看起来更好,没有特殊情况需要处理。如果绝对需要使用这种虚拟头并打印出插入是否在列表的前面,也许它有助于返回指向新节点的指针(例如,失败时为null),如这样:

node* addNodeBottom(int val, node **link){
    node *newNode = ...;
    ...
    while (*link)
        link = &(*link)->next;
    *link = newNode;
    return newNode;
}
...
if (addNodeToBottom(some_val, &head->next) == head->next)
     printf("added at beginning\n");
else
     printf("added later\n");
  

为什么head作为node * head而不是node ** head传递给我们   要在里面改变它,我们希望传播变化   在功能之外?

正如其他人所指出的,这是一种不寻常的链表,其中head是某种虚拟节点或其他东西。它永远不会在该函数中被修改,只有head->next,因此对head的更改将传播并导致外部副作用。

我从未理解那些类型的链表实现在C和C ++等语言中存储虚拟节点的意义,因为它们不会减少特殊情况。他们只是没有充分理由浪费记忆。它们可能对于不允许多个间接层的语言有意义,但在具有指针的语言中根本没有意义。也许实现该链表的人最初来自没有指针的语言背景,比如Java或Python等等。可能这种与虚拟节点相关联的列表在这些语言中并不是那么罕见,因为它解决了这样一个问题,即该语言不允许指针指针(或对引用的引用)以避免一些if语句到处都是。