【问题标题】:C++ passing pointers by Refrence or ValueC++ 通过引用或值传递指针
【发布时间】:2014-02-13 20:55:24
【问题描述】:

考虑这段代码:

#include <iostream>
using namespace std;

struct Node
{
    int x;
    Node *next;
};

void append(Node* h1, Node* h2)
{

    cout << h1 << ":" << h2;
    cout << endl;

    Node *ptr;
    ptr = h1;

    while ( ptr->next != NULL)
    {
        ptr = ptr->next;
    }

    ptr->next = h2;
}

void insertAtHead(Node* head, int k)
{

    Node *tmp = new Node;
    tmp -> x = k;
    tmp -> next = head;

    head = tmp; 
}

int main()
{
    Node *n1  = new Node;
    n1->x = 1;
    n1->next = NULL; 


    Node *n2  = new Node;
    n2->x = 2;
    n2->next = NULL;

    Node *n3  = new Node;
    n3->x = 3;
    n3->next = n2;

    cout << n1 << ":" << n3;
    cout << endl;

    append(n1,n3);

    insertAtHead(n1,4);

    while(n1 != NULL)
    {
        cout << n1->x;
        n1 = n1->next;
    }
    cout << endl;
}

即使我们有Node* h1,append 函数也可以工作,但是即使我们有相同的Node* head.,insertAtHead 也不能工作,为什么??

我们需要Node* &amp;head 才能使 appendAtHead 工作。为什么?

【问题讨论】:

    标签: c++ pointers pass-by-reference pass-by-value


    【解决方案1】:

    函数中追加指针h1没有改变

    在函数 insertAtHead 中,head 应该被改变,而不是一个局部变量被改变。您应该考虑到参数是函数的局部变量。所以退出函数后,所有的局部变量都被销毁了。

    如果函数 append 处理一个空列表,你可以获得同样的效果。在这种情况下,您必须在函数内部分配头部,头部的这些变化不会影响原始头部。

    有三种方法可以正确编写这些函数。每个函数要么返回更新的头部,要么必须通过引用或间接通过指向头部的指针传递头部。

    考虑例如,如果列表为空,即当第一个参数等于 NULL 时,函数 append 将如何工作。

    void append(Node* h1, Node* h2)
    {
    
        cout << h1 << ":" << h2;
        cout << endl;
    
        if ( h1 == NULL ) 
        {
            h1 = h2;
        }
        else
        {
            Node *ptr = h1;
    
            while ( ptr->next != NULL) ptr = ptr->next; 
    
            ptr->next = h2;
       }
    }
    

    正如您在本例中看到的,它与函数 insertAtHead 会出现相同的错误。函数内部 h1 的变化不会影响 head 的原始值。只有局部变量 h1 会被更改,然后在退出函数后被销毁。原始变量 head 将保持与以前相同的旧值。

    【讨论】:

      【解决方案2】:

      按值传递意味着函数将创建参数的副本,因此它不会更改传递的实际参数,而通过引用传递将允许您修改函数内的参数。知道了这一点,这就是为什么Node* &amp;head 可以工作,但Node* head 对你的insertAtHead() 函数不起作用的原因。

      对于 append() 函数,它正在被修改,因为 Node* ptr 变量指向 h1 的地址,这使您可以将下一个值设置为 h2(参数设置为 n3)而无需设置参数通过引用传递。在 n1 到达 append 函数之前,它的下一个节点设置为 NULL,而在调用 append 函数之后,它现在将下一个节点设置为 n3。 (IMO 我认为您应该给它们起不同的名称,看到 n1、h1、n2、h2 等会让人感到困惑......)

      【讨论】:

      • 因此在追加时正在修改副本,但我们仍然看到修改后的结果。为什么?
      【解决方案3】:

      原因很简单:

      在 void insertAtHead(Node* head, int k) 的情况下,当您按值传递 head 时,您正在处理实际 head 的副本,副本存在于堆栈中,因此在退出函数时它会被丢弃.

      这就是为什么你必须通过引用传递,所以 head 不是堆栈上节点的副本,而是你想要操作的实际节点。

      编辑以回答您的评论:

      append 之所以有效,是因为您获得了指针的副本,因此您可以修改它指向的下面的数据,但您不能更改您获得的实际指针,因为它是一个存在于堆栈上的临时副本。

      【讨论】:

      • 为什么它与 append 一起工作呢?不是要附加副本吗?
      【解决方案4】:

      指针按值传递(您传递指针值的副本 - 即指向的内存地址的副本)。

      引用通过引用传递(即,当函数参数在函数签名中具有 & 前缀时)。在这种情况下,如果您将引用指向函数内部的其他内容,那么当程序流退出函数范围并返回时,原始引用也指向其他内容。

      以下是 Java 差异的说明(以 C++ 为例,说明 Java 无法通过引用传递):

      http://blog.aaronshaw.net/2014/02/13/java-is-always-pass-by-value/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        • 1970-01-01
        • 1970-01-01
        • 2020-12-16
        • 2020-03-14
        • 2012-03-03
        • 2014-09-11
        相关资源
        最近更新 更多