C语言 在链表中添加节点时使用双指针的原因是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7271647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the reason for using a double pointer when adding a node in a linked list?
提问by a6h
The two code examples below both add a node at the top of a linked list. But whereas the first code example uses a double pointer the second code example uses a single pointer
下面的两个代码示例都在链表的顶部添加了一个节点。但是第一个代码示例使用双指针,第二个代码示例使用单指针
code example 1:
代码示例 1:
struct node* push(struct node **head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data = data;
newnode->next = *head;
return newnode;
}
push(&head,1);
code example 2:
代码示例2:
struct node* push(struct node *head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data = data;
newnode->next = head;
return newnode;
}
push(head,1)
Both strategies work. However, a lot of programs that use a linked list use a double pointer to add a new node. I know what a double pointer is. But if a single pointer would be sufficient to add a new node why do a lot of implementations rely on double pointers?
这两种策略都有效。但是,很多使用链表的程序使用双指针来添加新节点。我知道什么是双指针。但是如果单个指针就足以添加一个新节点,为什么很多实现都依赖于双指针呢?
Is there any case in which a single pointer does not work so we need to go for a double pointer?
是否存在单指针不起作用的情况,因此我们需要使用双指针?
回答by R. Martinho Fernandes
Some implementations pass a pointer to pointer parameter to allow changing the head pointer directly instead of returning the new one. Thus you could write:
一些实现传递一个指向指针参数的指针,以允许直接更改头指针而不是返回新指针。因此你可以写:
// note that there's no return value: it's not needed
void push(struct node** head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=*head;
*head = newnode; // *head stores the newnode in the head
}
// and call like this:
push(&head,1);
The implementation that doesn't take a pointer to the head pointer must return the new head, and the caller is responsible for updating it itself:
不带头指针的实现必须返回新头,调用者负责更新它自己:
struct node* push(struct node* head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=head;
return newnode;
}
// note the assignment of the result to the head pointer
head = push(head,1);
If you don't do this assignment when calling this function, you will be leaking the nodes you allocate with malloc, and the head pointer will always point to the same node.
如果你在调用这个函数的时候不做这个赋值,你会泄漏你用malloc分配的节点,头指针会一直指向同一个节点。
The advantage should be clear now: with the second, if the caller forgets to assign the returned node to the head pointer, bad things will happen.
优点现在应该很明显了:对于第二个,如果调用者忘记将返回的节点分配给头指针,就会发生不好的事情。
回答by user1164937
Although the previous answers are good enough, I think it's much easier to think in terms of "copy by value".
虽然前面的答案已经足够好,但我认为从“按值复制”的角度考虑要容易得多。
When you pass in a pointer to a function, the address value is being copied over to the function parameter. Due to the function's scope, that copy will vanish once it returns.
当您传入一个指向函数的指针时,地址值将被复制到函数参数中。由于函数的作用域,该副本一旦返回就会消失。
By using a double pointer, you will be able to update the original pointer's value. The double pointer will still be copied by value, but that doesn't matter. All you really care is modifying the original pointer, thereby bypassing the function's scope or stack.
通过使用双指针,您将能够更新原始指针的值。双指针仍将按值复制,但这无关紧要。您真正关心的是修改原始指针,从而绕过函数的作用域或堆栈。
Hope this answers not just your question, but other pointer related questions as well.
希望这不仅能回答您的问题,还能回答其他与指针相关的问题。
回答by patryk.beza
As @R. Martinho Fernandespointed out in his answer, using pointer to pointeras an argument in void push(struct node** head, int data)allows you to change the headpointer directly from within pushfunction instead of returning the new pointer.
作为@R。Martinho Fernandes在他的回答中指出,使用指向指针的指针作为参数void push(struct node** head, int data)允许您head直接从push函数内部更改指针,而不是返回新指针。
There is yet another good example which shows why using pointer to pointerinstead a single pointer may shorten, simplify and speed up your code. You asked about addinga new node to the list which probably typically doesn't need pointer-to-pointer in contrast to removingthe node from the singly-linked list. You can implement removing node from the list without pointer-to-pointer but it is suboptimal. I described the details here. I recommend you also to watch this YouTube videowhich addresses the problem.
还有另一个很好的例子说明了为什么使用指向指针的指针而不是单个指针可以缩短、简化和加速您的代码。您询问了向列表中添加一个新节点的问题,与从单向链表中删除节点相比,该节点通常不需要指针到指针。您可以在没有指针到指针的情况下实现从列表中删除节点,但它是次优的。我在这里描述了细节。我还建议您观看这个解决问题的YouTube 视频。
BTW: If you count with Linus Torvaldsopinion, you would better learn how to use pointer-to-pointer. ;-)
BTW:如果你算上Linus Torvalds 的意见,你最好学习如何使用指针到指针。;-)
Linus Torvalds:(...) At the opposite end of the spectrum, I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc. For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like
if (prev) prev->next = entry->next; else list_head = entry->next;and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a "*pp = entry->next". (...)
Linus Torvalds:(...) 在光谱的另一端,我实际上希望更多人理解真正核心的低级编码。不是像无锁名称查找这样的大而复杂的东西,而只是很好地使用了指向指针的指针等。例如,我见过太多人通过跟踪“prev”条目来删除单链表条目,然后删除条目,做类似的事情
if (prev) prev->next = entry->next; else list_head = entry->next;每当我看到这样的代码时,我就会说“这个人不懂指针”。可悲的是,这很常见。
了解指针的人只使用“指向入口指针的指针”,并使用 list_head 的地址对其进行初始化。然后当他们遍历列表时,他们可以在不使用任何条件的情况下删除条目,只需执行“*pp = entry->next”即可。(……)
Other resources that may be helpful:
其他可能有用的资源:
回答by Armen Tsirunyan
In your particular example there is no need for the double pointer. However it can be needed, if, for example, you were to do something like this:
在您的特定示例中,不需要双指针。但是,如果您要执行以下操作,则可能需要它:
struct node* push(struct node** head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=*head;
//vvvvvvvvvvvvvvvv
*head = newnode; //you say that now the new node is the head.
//^^^^^^^^^^^^^^^^
return newnode;
}
回答by roottraveller
Observation and Finding, WHY...
观察和发现,为什么...
I decided to do some experiments and make some conclusion,
我决定做一些实验并得出一些结论,
OBSERVATION 1-If the linked list is not empty then we can add the nodes in it (obviously at the end) by using a single pointer only.
观察 1-如果链表不为空,那么我们可以仅使用单个指针在其中添加节点(显然在末尾)。
int insert(struct LinkedList *root, int item){
struct LinkedList *temp = (struct LinkedList*)malloc(sizeof(struct LinkedList));
temp->data=item;
temp->next=NULL;
struct LinkedList *p = root;
while(p->next!=NULL){
p=p->next;
}
p->next=temp;
return 0;
}
int main(){
int m;
struct LinkedList *A=(struct LinkedList*)malloc(sizeof(struct LinkedList));
//now we want to add one element to the list so that the list becomes non-empty
A->data=5;
A->next=NULL;
cout<<"enter the element to be inserted\n"; cin>>m;
insert(A,m);
return 0;
}
Its simple to explain (Basic). We have a pointer in our main function which points to the first node (root) of the list. In the insert()function we pass the address of the root node and using this address we reach the end of the list and add a node to it. So we can conclude that if we have address of a variable in a function (not the main function) we can make permanent changes in the value of that variable from that function which would reflect in the main function.
它的解释很简单(基本)。我们的 main 函数中有一个指向列表的第一个节点(根)的指针。在insert()函数中,我们传递根节点的地址,并使用此地址到达列表的末尾并向其添加一个节点。所以我们可以得出结论,如果我们在一个函数(不是主函数)中有一个变量的地址,我们可以从那个函数中对该变量的值进行永久更改,这将反映在主函数中。
OBSERVATION 2-The above method of adding node failed when the list was empty.
观察 2-当列表为空时,上述添加节点的方法失败。
int insert(struct LinkedList *root, int item){
struct LinkedList *temp = (struct LinkedList*)malloc(sizeof(struct LinkedList));
temp->data=item;
temp->next=NULL;
struct LinkedList *p=root;
if(p==NULL){
p=temp;
}
else{
while(p->next!=NULL){
p=p->next;
}
p->next=temp;
}
return 0;
}
int main(){
int m;
struct LinkedList *A=NULL; //initialise the list to be empty
cout<<"enter the element to be inserted\n";
cin>>m;
insert(A,m);
return 0;
}
If you keep on adding elements and finally display the list then you would find that the list has undergone no changes and still it is empty. The question which struck my mind was in this case also we are passing the address of the root node then why modifications are not happening as permanent modifications and list in the main function undergoes no changes. WHY? WHY? WHY?
如果您继续添加元素并最终显示列表,那么您会发现列表没有发生任何变化,并且仍然是空的。我想到的问题是,在这种情况下,我们也在传递根节点的地址,那么为什么修改不会作为永久修改发生,并且主函数中的列表没有发生任何变化。为什么?为什么?为什么?
Then I observed one thing, when I write A=NULLthe address of Abecomes 0. This means now Ais not pointing to any location in memory. So I removed the line A=NULL;and made some modification in the insert function.
然后我观察到一件事,当我写A=NULL的地址A变为 0 时。这意味着现在A没有指向内存中的任何位置。所以我删除了该行A=NULL;并在插入函数中进行了一些修改。
some modifications,(below insert()function can add only one element to an empty list, just wrote this function for testing purpose)
一些修改,(下面的insert()函数只能向空列表添加一个元素,只是为了测试目的而写了这个函数)
int insert(struct LinkedList *root, int item){
root= (struct LinkedList *)malloc(sizeof(struct LinkedList));
root->data=item;
root->next=NULL;
return 0;
}
int main(){
int m;
struct LinkedList *A;
cout<<"enter the element to be inserted\n";
cin>>m;
insert(A,m);
return 0;
}
the above method also fails because in the insert()function root stores same address as Ain the main()function but after the line root= (struct LinkedList *)malloc(sizeof(struct LinkedList));the address stored in rootchanges. Thus now , root(in insert()function) and A(in main()function) store different addresses.
上述方法也失败了,因为在insert()函数 root 中存储的地址A与main()函数中的地址相同,但在该行之后,root= (struct LinkedList *)malloc(sizeof(struct LinkedList));存储的地址root发生了变化。因此现在 , root(in insert()function) 和A(in main()function) 存储不同的地址。
So the correct final program would be,
所以正确的最终程序是,
int insert(struct LinkedList *root, int item){
root->data=item;
root->next=NULL;
return 0;
}
int main(){
int m;
struct LinkedList *A = (struct LinkedList *)malloc(sizeof(struct LinkedList));
cout<<"enter the element to be inserted\n";
cin>>m;
insert(A,m);
return 0;
}
But we dont want two different functions for insertion, one when list is empty and other when list is not empty. Now comes double pointer which makes things easy.
但是我们不想要两种不同的插入函数,一种是当列表为空时,另一种是当列表不为空时。现在出现了双指针,这使事情变得容易。
One thing I noticed which is important is that pointers store address and when used with '*' they give value at that address but pointers themselves have their own address.
我注意到很重要的一件事是指针存储地址,当与 '*' 一起使用时,它们在该地址给出值,但指针本身有自己的地址。
Now here is the complete program and later explain the concepts.
现在这里是完整的程序,稍后解释概念。
int insert(struct LinkedList **root,int item){
if(*root==NULL){
(*root)=(struct LinkedList *)malloc(sizeof(struct LinkedList));
(*root)->data=item;
(*root)->next=NULL;
}
else{
struct LinkedList *temp=(struct LinkedList *)malloc(sizeof(struct LinkedList));
temp->data=item;
temp->next=NULL;
struct LinkedList *p;
p=*root;
while(p->next!=NULL){
p=p->next;
}
p->next=temp;
}
return 0;
}
int main(){
int n,m;
struct LinkedList *A=NULL;
cout<<"enter the no of elements to be inserted\n";
cin>>n;
while(n--){
cin>>m;
insert(&A,m);
}
display(A);
return 0;
}
following are the observations,
以下是观察结果,
1.root stores the address of pointer A (&A), *rootstores the address stored by pointer Aand **rootstores the value at address stored by A. In simple language root=&A, *root= Aand **root= *A.
1.根存储指针A的地址(&A),*root存储由指针所存储的地址A和**root存储在地址由存储的值A。用简单的语言root=&A,*root= A和**root= *A。
2.if we write *root= 1528then it means that value at address stored in rootbecomes 1528 and since address stored in rootis the address of pointer A (&A)thus now A=1528(i.e. address stored in Ais 1528) and this change is permanent.
2.如果我们写*root= 1528那么这意味着存储在地址中的值root变为 1528 并且由于存储在root的地址是指针 A 的地址,(&A)因此现在A=1528(即存储在的地址A是 1528)并且此更改是永久性的。
whenever we are changing value of *rootwe are indeed changing value at address stored in rootand since root=&A( address of pointer A) we are indirectly changing value of Aor address stored in A.
每当我们更改 的值时,*root我们确实在更改存储在的地址处的值,root并且由于root=&A(指针的地址A)我们间接地更改了 的值A或存储在A.
so now if A=NULL(list is empty) *root=NULL, thus we create the first node and store its address at *rooti.e. indirectly we storing the address of first node at A. If list is not empty , everything is same as done in previous functions using single pointer except we have changed root to *rootsince what was stored in root is now stored in *root.
所以现在 if A=NULL(list is empty) *root=NULL,因此我们创建第一个节点并将其地址*root存储在即间接我们将第一个节点的地址存储在A。如果 list 不为空,则一切都与使用单指针的先前函数中所做的相同,除了我们将 root 更改为*root因为存储在 root 中的内容现在存储在*root.
回答by bsd
Let's take this simple eg:
让我们以这个简单的例子为例:
void my_func(int *p) {
// allocate space for an int
int *z = (int *) malloc(sizeof(int));
// assign a value
*z = 99;
printf("my_func - value of z: %d\n", *z);
printf("my_func - value of p: %p\n", p);
// change the value of the pointer p. Now it is not pointing to h anymore
p = z;
printf("my_func - make p point to z\n");
printf("my_func - addr of z %p\n", &*z);
printf("my_func - value of p %p\n", p);
printf("my_func - value of what p points to: %d\n", *p);
free(z);
}
int main(int argc, char *argv[])
{
// our var
int z = 10;
int *h = &z;
// print value of z
printf("main - value of z: %d\n", z);
// print address of val
printf("main - addr of z: %p\n", &z);
// print value of h.
printf("main - value of h: %p\n", h);
// print value of what h points to
printf("main - value of what h points to: %d\n", *h);
// change the value of var z by dereferencing h
*h = 22;
// print value of val
printf("main - value of z: %d\n", z);
// print value of what h points to
printf("main - value of what h points to: %d\n", *h);
my_func(h);
// print value of what h points to
printf("main - value of what h points to: %d\n", *h);
// print value of h
printf("main - value of h: %p\n", h);
return 0;
}
Output:
输出:
main - value of z: 10
main - addr of z: 0x7ffccf75ca64
main - value of h: 0x7ffccf75ca64
main - value of what h points to: 10
main - value of z: 22
main - value of what h points to: 22
my_func - value of z: 99
my_func - value of p: 0x7ffccf75ca64
my_func - make p point to z
my_func - addr of z 0x1906420
my_func - value of p 0x1906420
my_func - value of what p points to: 99
main - value of what h points to: 22
main - value of h: 0x7ffccf75ca64
we have this signature for my_func:
我们有 my_func 的签名:
void my_func(int *p);
If you look at the output, in th end, the value that h points to is still 22 and the value of h is the same, altough in my_func it was changed. How come ?
如果你看输出,最后,h 指向的值仍然是 22,h 的值是一样的,虽然在 my_func 中它被改变了。怎么来的 ?
Well, in my_func we are manipulating the value of p, which is just a local pointer. after calling:
好吧,在 my_func 中,我们正在操纵 p 的值,它只是一个本地指针。调用后:
my_func(ht);
in main(), p will hold the value that h holds, which represents the address of z variable, declared in main function.
在 main() 中,p 将保存 h 保存的值,该值表示在 main 函数中声明的 z 变量的地址。
In my_func(), when we are changing the value of p to hold the value of z, which is a pointer to a location in memory, for which we have allocated space, we are not changing the value of h, that we've passed in, but just the value of local pointer p. Basically, p does not hold the value of h anymore, it will hold the address of a memory location, that z points to.
在 my_func() 中,当我们更改 p 的值以保存 z 的值时,z 是指向内存中某个位置的指针,我们为其分配了空间,我们没有更改 h 的值,因为我们已经传入,但只是本地指针p的值。基本上,p 不再保存 h 的值,它将保存 z 指向的内存位置的地址。
Now, if we change our example a little bit:
现在,如果我们稍微改变一下我们的例子:
#include <stdio.h>
#include <stdlib.h>
void my_func(int **p) {
// allocate space for an int
int *z = (int *) malloc(sizeof(int));
// assign a value
*z = 99;
printf("my_func - value of z: %d\n", *z);
printf("my_func - value of p: %p\n", p);
printf("my_func - value of h: %p\n", *p);
// change the value of the pointer p. Now it is not pointing to h anymore
*p = z;
printf("my_func - make p point to z\n");
printf("my_func - addr of z %p\n", &*z);
printf("my_func - value of p %p\n", p);
printf("my_func - value of h %p\n", *p);
printf("my_func - value of what p points to: %d\n", **p);
// we are not deallocating, because we want to keep the value in that
// memory location, in order for h to access it.
/* free(z); */
}
int main(int argc, char *argv[])
{
// our var
int z = 10;
int *h = &z;
// print value of z
printf("main - value of z: %d\n", z);
// print address of val
printf("main - addr of z: %p\n", &z);
// print value of h.
printf("main - value of h: %p\n", h);
// print value of what h points to
printf("main - value of what h points to: %d\n", *h);
// change the value of var z by dereferencing h
*h = 22;
// print value of val
printf("main - value of z: %d\n", z);
// print value of what h points to
printf("main - value of what h points to: %d\n", *h);
my_func(&h);
// print value of what h points to
printf("main - value of what h points to: %d\n", *h);
// print value of h
printf("main - value of h: %p\n", h);
free(h);
return 0;
}
we have the follwoing output:
我们有以下输出:
main - value of z: 10
main - addr of z: 0x7ffcb94fb1cc
main - value of h: 0x7ffcb94fb1cc
main - value of what h points to: 10
main - value of z: 22
main - value of what h points to: 22
my_func - value of z: 99
my_func - value of p: 0x7ffcb94fb1c0
my_func - value of h: 0x7ffcb94fb1cc
my_func - make p point to z
my_func - addr of z 0xc3b420
my_func - value of p 0x7ffcb94fb1c0
my_func - value of h 0xc3b420
my_func - value of what p points to: 99
main - value of what h points to: 99
main - value of h: 0xc3b420
Now, we actually have changed the value which h holds, from my_func, by doing this:
现在,我们实际上已经通过执行以下操作更改了 my_func 中 h 持有的值:
- changed function signature
- calling from main(): my_func(&h); Basically we are passing the address of h pointer to double pointer p, declared as a parameter in function's signature.
- in my_func() we are doing: *p = z; we are dereferencing the double pointer p, one level. Basically this got translated as you would do: h = z;
- 更改了函数签名
- 从 main() 调用:my_func(&h); 基本上我们将 h 指针的地址传递给双指针 p,在函数签名中声明为参数。
- 在 my_func() 我们正在做: *p = z; 我们正在取消引用双指针 p,一级。基本上这被翻译成你会做的:h = z;
The value of p, now holds the address of h pointer. h pointer holds the address of z.
p 的值,现在保存 h 指针的地址。h 指针保存 z 的地址。
You can take both examples and diff them. So, getting back to your question, you need double pointer in order to make modifications to the pointer that you've passed in straight from that function.
您可以采用这两个示例并对其进行比较。因此,回到您的问题,您需要双指针才能修改直接从该函数传入的指针。
回答by Napstablook
Think of memory location for head like [HEAD_DATA].
想想像 [HEAD_DATA] 这样的 head 的内存位置。
Now in your second scenario, the calling function's main_head is the pointer to this location.
现在在您的第二个场景中,调用函数的 main_head 是指向该位置的指针。
main_head--->[HEAD_DATA]
main_head--->[HEAD_DATA]
In your code, it sent the value of the pointer main_head to the function(i.e the address of the memory location of head_data) You copied that to local_head in the function. so now
在您的代码中,它将指针 main_head 的值发送到函数(即 head_data 的内存位置的地址)您将其复制到函数中的 local_head。所以现在
local_head---> [HEAD_DATA]
local_head---> [HEAD_DATA]
and
和
main_head---> [HEAD_DATA]
main_head---> [HEAD_DATA]
Both point to the same location but are essentially independent of each other. So when you write local_head = newnode; what you did is
两者都指向同一个位置,但本质上是相互独立的。所以当你写local_head = newnode; 你所做的是
local_head--/-->[HEAD_DATA]
local_head--/-->[HEAD_DATA]
local_head-----> [NEWNODE_DATA]
local_head-----> [NEWNODE_DATA]
You simply replaced the memory address of previous memory with new one in local pointer. The main_head (pointer) still points to the old [HEAD_DATA]
您只需用本地指针中的新地址替换先前内存的内存地址。main_head(指针)仍然指向旧的[HEAD_DATA]
回答by WilderField
The standard way to handle linked lists in C is to have the push and pop functions automatically update the head pointer.
在 C 中处理链表的标准方法是让 push 和 pop 函数自动更新头指针。
C is "Call by value" meaning copies of parameters are passed into functions. If you only pass in the head pointer any local update you make to that pointer will not be seen by the caller. The two workarounds are
C 是“按值调用”,意思是参数的副本被传递到函数中。如果您只传入头指针,则调用者将看不到您对该指针所做的任何本地更新。两种解决方法是
1) Pass the address of the head pointer. (Pointer to head pointer)
1) 传递头指针的地址。(指向头指针的指针)
2) Return a new head pointer, and rely on the caller to update the head pointer.
2)返回一个新的头指针,依靠调用者更新头指针。
Option 1) is the easiest even though a little confusing at first.
选项 1) 是最简单的,尽管一开始有点混乱。
回答by vishnu vardhan
Lets say I noted down your house address on a card-1. Now if I want tell your house address to somebody else, I can either copy the address from card-1 to card-2 and give card-2 OR I can give card-1 directly. Either ways the person will know the address and can reach you. But when I give card-1 directly, the address can be changed on card-1 but if I gave card-2 only the address on card-2 can be changed but not on card-1.
假设我在卡片 1 上记下了您的住所地址。现在如果我想把你的房子地址告诉别人,我可以把地址从card-1复制到card-2然后给card-2,或者我可以直接给card-1。无论哪种方式,此人都会知道地址并可以联系到您。但是当我直接给card-1时,card-1上的地址可以更改,但是如果我给card-2,则只能更改card-2上的地址,而不能更改card-1上的地址。
Passing a pointer to pointer is similar to giving the access to card-1 directly. Passing a pointer is similar to creating a new copy of the address.
将指针传递给指针类似于直接访问 card-1。传递指针类似于创建地址的新副本。
回答by user3463521
I think your confusion might come from the fact that both functions have a parameter named head. The two headare actually different things. headin the first code stores the address of of the head node pointer(which itself stores an address of the head node structure). Whereas the second headstores an address of the head node structure directly. And since both function returns the newly created node(which should be the new head), I think there is no need to go for the first approach. Callers of this function is responsible to update the head reference they have. I think the second one is good enough and simple to look at. I'd go with the second one.
我认为您的困惑可能来自于两个函数都有一个名为head. 两者head其实是不同的东西。head在第一个代码中存储了头节点指针的地址(它本身存储了头节点结构的地址)。而第二个直接head存储头节点结构的地址。由于这两个函数都返回新创建的节点(应该是新的头),我认为没有必要采用第一种方法。此函数的调用者负责更新他们拥有的头部引用。我认为第二个已经足够好,而且看起来很简单。我会选择第二个。

