我见过这个问题:
使用以下代码在列表中添加元素: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
传递?我在这里缺少什么?
答案 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
语句到处都是。