How does reference to pointer exactly work in C++, and when do we need them (in the case of linked list)

不问归期 提交于 2020-01-30 11:00:07

问题


I know that pointers hold the address of a variable. And references point to the same address in the symbol table (that is, the same address of the variable, that they are assigned to).

My question is, how do reference to pointers exactly work. And when do we need them, as opposed to using pointer alone (and not using reference to pointer). It will be helpful if you could explain me the use of reference to pointer, with respect to a singly linked list.

I have the following code that deletes the head pointer of a linked list using a function:

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

struct Node* newNode(int data)
{
    Node* temp = new Node;
    temp->data = data;
    temp->next = nullptr;
    return temp;
}

Node* deleteHead(Node* &head)
{
    if (head)
    {
        Node* temp = head;
        head = head->next;
        delete temp;
    }
    return head;
}

int main()
{
    Node* head = newNode(1);
    head->next = newNode(6);
    head->next->next = newNode(4);
    head->next->next->next = newNode(8);

    head = deleteHead(head);
    Node* temp = head;
    while (temp != nullptr)
    {
        cout << temp->data << " " << endl;
        temp = temp->next;
    }
    return 0;
}

In the deleteHead(Node* &head) function, the function takes the argument, Node* &head. But, the code works fine, even when the argument is Node* head. for what cases do we need to pass Node* & instead of Node* in a linked list?

Following is the deleteHead(Node* &head) function above, which works the same, if we only use Node* head as the argument, instead of Node* &head -


回答1:


You pass a pointer by reference for the same reason you pass a non-pointer by reference: To let the function modify its value.

Let me use a simpler example

#include <iostream>

void foo(int*& x) {
    *x = 42;        // change the value of the int x points to
    x = nullptr;    // change the value of x
}

The first line modifies the value x points to (but it does not modify x). The second line modifies x itself.

int main() {
    int y = 42;
    int* y_ptr = &y;
    foo(y_ptr);
    if (y_ptr == &y) std::cout << "cannot happen";
}

Because we set x = nullptr, y_ptr will not point to y anymore after the call.

Now if we modify foo to not take a reference we get:

#include <iostream>

void foo(int* x) {
    *x = 42;        // change the value of the int x points to
    x = nullptr;    // change the value of x
}

Again the first line modifies the int pointed to by x. However, now the second line only has an effect on x local to the function.

int main() {
    int y = 42;
    int* y_ptr = &y;
    foo(y_ptr);
    if (y_ptr == nullptr) std::cout << "cannot happen";
}

The value of y_ptr cannot change by passing it to foo, because it is passed by value.

In your code you have

Node* deleteHead(Node* &head)
{
    if (head)
    {
        Node* temp = head;
        head = head->next;
        delete temp;
    }
    return head;
}

And when you write head = deleteNode(head) two things are happening:

  • the function modifies head (because it is passed by reference) to point to head->next.
  • the function also returns this "new" head (pointing to head->next) and that is assigned to head.

So you basically asign to headtwice. Because head is passed by reference deleteNode would do the right thing without using the return value:

deleteNode(head);  // this already does modify head 

...or put the other way around: If you return the "new" head (head->next) from the fucntion and assign it to head, then it does not matter if you pass the pointer by reference, because the assignment done inside the function has the same effect.

Your code is similar to

int* bar(int*& x) {
   x = nullptr;
   return x;
}

and then call it via

int y = 42;
int* y_ptr = &y;
y_ptr = bar(y_ptr);

where the same effect could be achieved by not using the returned value bar(y_ptr). Or the same without pointers (because pointers really make no difference here):

int moo(int& x) {
    x = 0;
    return x;
}

int x = 42;
x = moo(x);     // same as `moo(x)`

PS: You dont need both (return the pointer and assign it already in the function), so better make the function return void.




回答2:


So,

both, reference and pointer contain an address of variable/memory. reference has semantic of variable (if you set the value, you write data into referenced memory), pointer has semantic of pointer (if you set the value, pointered memory isn't changed) and you can set the pointer which addresses an other memory.

about deleteHead(Node* &head) - you use the reference of real variable that contains pointer of Node. The function returns new value of head in the same variable and as return value too.




回答3:


References are "safe pointers" that are used with value semantics (which is really helpful in an operator overloading context), so the usage of references is very similar to the usage of pointers in C, except these points:

  1. References hold a single value and not an array
  2. References are non-null (which is not always desirable)

It means that you can (or, should) pass a reference whenever you want to change the original passed variable (and not a copy of it).

Saying that, the C (rought) equivalent to your function is Node* deleteHead(Node** head). Note that since you passed a reference, the original head variable was modified and thus your function becomes a bit weird, since it both modifies head and returns its value. You can use one of the following options:

(1) deletes head (if the list size is non-empty) and returns a pointer to the next element, this is not advisable since it will leave head as a dangling pointer. This is your original function but it does not receive a reference.

Node* deleteHead(Node* head)
{
    if (head)
    {
        Node* temp = head; // You might want to use auto
        head = head->next;
        delete head;
    }
    return head;
}

(2) The same as your function, but returns no value (because you already modified head). This one will not work without passing a reference.

void deleteHead(Node* &head)
{
    if (head)
    {
        Node* temp = head->next; 
        delete head; // deletes the content of head
        head = temp;
    }
}



回答4:


With the reference to pointer deleteHead function, you may use head = deleteHead(head) or deleteHead(head) since head is just a reference of head in the main function, any change on head in the deleteHead function is actually applied on head variable in the main function. With the pointer version, you must use head = deleteHead(head).



来源:https://stackoverflow.com/questions/59937678/how-does-reference-to-pointer-exactly-work-in-c-and-when-do-we-need-them-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!