在链接列表插入的这个实现中,作者使用双指针将链表传递给方法。
我无法理解为什么他没有使用单指针。你能解释一下使用双指针的原因吗?
void insert_list(list **l, item_type x)
{
list *p; /* temporary pointer */
p = malloc( sizeof(list) );
p->item = x;
p->next = *l;
*l = p;
}
换句话说,以下实施会出现什么问题?
void insert_list(list *l, item_type x)
{
list *p; /* temporary pointer */
p = malloc( sizeof(list) );
p->item = x;
p->next = l;
l = p;
}
答案 0 :(得分:4)
请注意,list** l
是指向list
的指针。声明p->next = *l
表示p->next
指向节点**l
。然后我们修改指针*l
以指向p
;我们可以这样做,因为我们传递了指向指针的指针。
以下是列表中发生的更改(以图形方式):
... -> some_node -> ...
我们在x
之前插入一个包含项l
的新节点:
... -> new_node -> some_node -> ...
关于代码的好处是它可以避免在没有指向指针的情况下出现的某些情况。它更干净。
您提供的代码,
void insert_list(list *l, item_type x)
{
list *p; /* temporary pointer */
p = malloc( sizeof(list) );
p->item = x;
p->next = l;
l = p;
}
接收指向节点的指针的副本;这意味着它无法修改变量(即它只能进行"本地"更改)。当函数返回时,l
仍将指向同一节点。但是,如果传递了指向该指针的指针,则可以对其进行修改(在第一个函数中就是这种情况)。
答案 1 :(得分:3)
考虑它的一个简单方法是:如果我们想要一个函数能够修改@if($a == 2)
A is 2
@endif
的值,那么我们传递一个指向它的指针(int
)
因此,如果我们希望函数能够修改指针,那么我们将指针传递给它。
另一种避免指向指针的方法是让函数返回新的int*
,如下所示:
list*
但是这种方法依赖于调用者正确使用该函数,如下所示:
list* insert_list(list *l, item_type x)
{
list *p = malloc( sizeof(list) ); // new node
p->item = x;
p->next = l;
return p;
}
引入了很多潜在错误的范围。通常,您应该总是尝试设计难以正确使用的API。
答案 2 :(得分:2)
在函数的第二个版本中,最后一个语句l = p;
是没有意义的,因为它只是修改了l
参数,它实际上是一个局部变量。
list *thelist = NULL;
insert_list(thelist, someitem);
// you expect thelist to point to some memory location allocated in insert_list
// but actually thelist will still be NULL here.
第一个版本会像这样调用:
list *thelist = NULL;
insert_list(&thelist, someitem);
// we pass a pointer to thelist, which is actually a pointer to a pointer
// now thelist points to the memory location allocated in insert_list
编写函数的另一种方法是这样的:
list *insert_list(list *l, item_type x)
{
list *p; /* temporary pointer */
p = malloc( sizeof(list) );
p->item = x;
p->next = l;
return p;
}
...
list *thelist = NULL;
thelist = insert_list(thelist, someitem);