我在一些书/教程中看过这个。
将头指针(链表)传入函数时,需要将其作为双指针传递。
例如: //这是为了反转一个链接列表,其中head指向第一个节点。
void nReverse(digit **head)
{
digit *prev=NULL;
digit *curr=*head;
digit *next;
while(curr!=NULL)
{
next=curr->next;
curr->next=prev;
prev=curr;
curr=next;
}
*head=prev;
return;
}
这很好用。
当我使用像
这样的单指针时,它也有效void nReverse(digit *head)
{
digit *prev=NULL;
digit *curr=head;
digit *next;
while(curr!=NULL)
{
next=curr->next;
curr->next=prev;
prev=curr;
curr=next;
}
head=prev;
return;
}
我尝试使用头指针打印列表。这两个功能都可以正常工作。
我错过了什么吗?
谢谢,
答案 0 :(得分:4)
这是非常类似C的代码,而不是C ++。
基本上,当按值传递某些内容时,该函数会对数据副本进行操作:
void foo(int i)
{
i = 5; // copy is set to 5
}
int x = 7;
foo(x);
// x is still 7
在C中,您改为传递指向变量的指针,并可以这样改变:
void foo(int* i)
{
*i = 5; // whatever i points to is set to 5
}
int x = 7;
foo(&x);
// x is 5
对你来说,而不是int
它是digit*
。 (导致指向指针的指针。)
在C ++中,引入了参考文献。引用是另一个对象的别名。所以你会做这样的事情:
void foo(int& i) // i is an alias to another value
{
i = 5; // x is set to 5
}
int x = 7;
foo(x); // pass x as alias, not address of x.
// x is 5
通常首选引用,因为它强制您实际引用对象,并简化调用和操作代码。
当然在C ++中你不会自己实现一个列表,你可以使用std::list
。
答案 1 :(得分:2)
最后一个head=prev;
不会更改第二个示例中传递的指针的值。对于此功能而言,该行是否必要取决于您自己。但是有区别。
你是如何测试它“工作正常”的?您是否能够迭代列表并打印出节点的值并看到它们实际上已被反转?第一个函数(可能称为nReverse(&list);
更改 list
指向的内容,第二个函数没有(因此对于第二个函数,您如何知道哪个节点是列表的开头)毕竟它刚刚改变了......)。
答案 2 :(得分:0)
在第一个示例中,您传入的内容仍然指向列表的“开头”。
在第二个例子中,它指向列表的末尾(这是您开始时的开始,但此后已移动)。
答案 3 :(得分:0)
双重间接的原因是nReverse
可以修改调用者的指针,因为在反转列表之后,列表的头部现在是一个不同的节点。
在第二个版本中,您正在修改函数本地的head
副本,因此调用者仍然可以引用旧的头节点,现在是尾部。
答案 4 :(得分:0)
双指针传递的原因(第一个例子)是你想要改变列表的头部。由于您正在反转列表,因此在完成反转后,头应指向列表的最后一个元素。
digit* list;
// initialize list
nReverse(&list);
// now list is pointing to the last element of the chain (and not the first)
如果你不使用双指针,那么list仍将指向原来的第一个元素,下一个现在指向NULL,因为它是反转后的最后一个元素。所以你放弃了所有其他元素。