问题
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 tohead->next
. - the function also returns this "new" head (pointing to
head->next
) and that is assigned tohead
.
So you basically asign to head
twice. 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:
- References hold a single value and not an array
- 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