在这段代码中:
void push(node **head, int data) {
node *temp = malloc(sizeof(node));
temp->data = data;
temp->next = *head;
*head = temp;
}
为什么temp->next = *head
还不够?
为什么有必要将*head
设置为等于temp
?这究竟起到了什么作用?
方法push()
接受两个参数:指向指向node
的指针(指向链表的指针)的指针和要插入到列表中的值。
*head = temp;
是必要的原因是,调用方的链表最终会被修改。如果没有此行,则不会修改调用方的链表。
这是一个高度简化的示例,说明为什么这是必要的。假设我有一个修改 int 的方法:
void foo(int *bar) {
int baz;
baz = *bar;
baz = 42;
}
通过传入指针调用foo()
后,指针指向的变量不会发生任何变化。当foo()
完成时,所有堆栈变量(即 bar
和 baz
) 将消失,对 bar
值所做的修改永远不会保存)。
回到你问题中的例子。如果该行从未被调用,则调用者的副本不会发生任何变化(即在调用函数后,就好像该元素从未添加到列表中一样),原因与调用者传递给foo()
的任何内容的副本没有更改的原因相同。
因此,您经常会看到 insert()
函数的不同方法签名:
node *push(node *head, int data);
这被称为:
// assume head is a pointer to a node
head = push(head, 42);
效果是相同的,但由于只有一个指向传入节点的指针,因此push()
对列表结构执行的任何操作都不会应用于head
,直到分配发生。
它将头部重置为新节点,允许我们迭代所有元素。推送将新节点放在列表的开头。Head 就像一个链表的起点,使用它你可以到达所有的元素。如果 head 未设置为新节点,您将丢失对新插入数据的引用,从而导致内存泄漏。
假设它是一个基于列表的堆栈(根据Push
操作进行猜测),那么该项目应该添加到列表的开头,以便可以轻松弹出。这样,当调用方尝试再次使用堆栈时,列表的头部将使用新的数据项进行更新。