0

以下代码来自《编程面试》一书 ,我在理解指针的概念时遇到了问题。为什么我们不能使用代码号。1.

代码编号 1

bool insertInFront( IntElement *head, int data )
{
    IntElement *newElem = new IntElement;
    if( !newElem ) return false;
    newElem->data = data;
    head = newElem; // Incorrect!
    return true;
}

代码编号 2

bool insertInFront( IntElement **head, int data )
{
    IntElement *newElem = new IntElement;
    if( !newElem ) return false;
    newElen->data = data;
    *head = newElem; // Correctly updates head
    return true;
}
4

4 回答 4

4
  • 在代码 1 中,您将 的指针位置分配给newElem本地副本head当函数返回时,head被销毁,并且您将发生内存泄漏(您丢失指向 的指针newElem,让您无路可走delete。)您只更改了函数的指针的本地副本,调用者的副本不受影响。

  • 在代码 2 中,head是一个指向指针的指针。您不仅有一个指针,实际上还有一个指向调用者的指针的指针。这允许您更改调用者的指针,将指针存储到newElem函数返回时,head被销毁,但它只是指向指针的指针。原始指针在调用者的范围内是完整的。

于 2013-07-10T23:33:00.933 回答
1

指针的概念非常复杂。基本上,您需要考虑指针的方式是它们本身就是“值”。所以:

*head = some_memory_address_that_points_to_head;

可以认为是:

int im_a_pointer_to_head = some_memory_address_value_to_head;

因此,如果我们将相同的概念应用于您的第一个函数:

bool insertInFront(int im_a_pointer_to_head, int data)...

您实际上是在传递头指针值的副本,在函数内更改它只会更改为此函数制作的临时副本,实际上不会更改原始指针指向的位置。

第二个函数解决了这个问题,因为您实际上是在传递指向指向头部的指针的指针的副本(尝试说快 3 倍!)。在这种情况下,您不会更改复制的值,而是更改实际指针指向的位置。

于 2013-07-10T23:01:18.437 回答
1

假设您将函数 1 称为:

insertInFront(H, data);

在调用函数时,计算机会复制参数,然后在函数返回时释放它们。所以在代码 1 中,head=newElem分配了newElemto的地址head(它是 的副本H),然后释放head,并且newElem永远丢失了的地址。然而,在代码 2 中,该函数应调用为:

insertInFront(&H, data);

这意味着 的 ADDRESSH被复制到head,并且 的地址newElem被分配到*head,即head指向哪里,这导致H。这样就可以得到newElem函数返回后的地址。

于 2013-07-11T02:44:33.657 回答
0

要在函数调用之外更改通过函数参数传递的任何值(并使该更改保持不变),您必须拥有要更改其值的任何内存地址。这是另一种说法,您必须“按引用传递”而不是“按值传递”——否则按值传递将导致函数仅更改 COPY。

于 2013-07-10T22:54:20.283 回答