繁体   English   中英

C ++通过Refrence或Value传递指针

[英]C++ passing pointers by Refrence or Value

考虑以下代码:

#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* head. 为什么??

我们需要Node* &head才能使appendAtHead起作用。 为什么?

按值传递表示函数将创建参数的副本,因此它不会更改传递的实际参数,而按引用传递将使您可以修改函数中的参数。 知道这一点,这就是为什么Node* &head可以工作但Node* head对于您的insertAtHead()函数不起作用的原因。

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

原因很简单:

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

这就是为什么必须通过引用传递的原因,因此head并不是堆栈上节点的副本,而是您要操作的实际节点。

编辑以回答您的评论:

append之所以有效,是因为您获得了指针的副本,因此可以修改其指向的下层数据,但是您无法更改所获得的实际指针,因为它是存在于堆栈中的临时副本。

在函数中附加指针h1不变

在函数insertAtHead中应该更改head,但是要更改局部变量。 您应考虑到参数是函数的局部变量。 因此,退出函数后,所有局部变量均被销毁。

如果函数append处理一个空列表,您将获得相同的效果。 在这种情况下,您必须在函数内部分配磁头,并且磁头的这些更改不会影响原始磁头。

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

例如,考虑如果列表为空,即当第一个参数等于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将被更改,然后在退出函数后销毁。 原始变量头将保持与以前相同的旧值。

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

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

这是Java区别的说明(使用C ++作为能够通过引用传递Java不能做到的示例):

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM