3

我在一些书/教程中看到了这一点。

当您将(链表的)头指针传递给函数时,您需要将其作为双指针传递。

例如: // 这是反转一个链表,其中 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;
}

我尝试使用头指针打印列表。这两个功能都可以正常工作。

我错过了什么吗?

谢谢,

4

5 回答 5

5

这是非常类似 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.

于 2010-07-22T20:43:09.697 回答
2

最后一个head=prev;不会更改第二个示例中传递的指针的值。对于此功能的目的是否需要该行取决于您。但是有区别。

你是如何测试它“工作正常”的?您是否能够迭代列表并打印出节点的值并看到它们实际上已被反转?第一个函数(大概称为 likenReverse(&list); 更改指向的内容list,第二个不更改(所以对于第二个函数,您如何知道哪个节点是列表的开头,毕竟它只是被更改了......)。

于 2010-07-22T20:40:48.050 回答
0

在第一个示例中,您传入的内容仍然指向列表的“开头”。

在第二个示例中,它指向列表的末尾(这是您开始时的开头,但后来移动了)。

于 2010-07-22T20:43:56.743 回答
0

双重间接的原因是nReverse可以修改调用者的指针,因为在反转列表之后,列表的头部现在是一个不同的节点。

在第二个版本中,您正在修改head函数本地的副本,因此调用者仍然具有对旧头节点的引用,现在是尾节点。

于 2010-07-22T20:46:54.460 回答
0

使用双指针传递(第一个示例)的原因是您想要更改列表的头部。由于您正在反转列表,因此在您完成反转后头部应该指向列表的最后一个元素。

digit* list; 
// initialize list
nReverse(&list); 
// now list is pointing to the last element of the chain (and not the first)

如果您不使用双指针,则 list 仍将指向原始第一个元素,该元素 next 现在指向 NULL,因为它是反转后的最后一个元素。所以你失去了所有其他元素。

于 2010-07-22T20:54:21.897 回答