![](/img/trans.png)
[英]Why do we have different effect when setting pointer=nullpointer and pointer->next=nullpointer in linked list - C++
[英]How does reference to pointer exactly work in C++, and when do we need them (in the case of linked list)
我知道指針保存變量的地址。 並且引用指向符號表中的相同地址(即變量的相同地址,它們被分配到)。
我的問題是,對指針的引用究竟是如何工作的。 我們什么時候需要它們,而不是單獨使用指針(而不是使用對指針的引用)。 如果您能向我解釋對單向鏈表的引用的使用,將會很有幫助。
我有以下代碼使用函數刪除鏈表的頭指針:
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;
}
在deleteHead(Node* &head)
函數中,該函數采用參數Node* &head
。 但是,即使參數是Node* head
,代碼也能正常工作。 在什么情況下我們需要在鏈表中傳遞Node* &
而不是Node*
?
下面是上面的deleteHead(Node* &head)
函數,如果我們只使用Node* head
作為參數,而不是Node* &head
,它的工作原理是一樣的 -
所以,
引用和指針都包含變量/內存的地址。 引用具有變量的語義(如果設置值,則將數據寫入引用的內存),指針具有指針的語義(如果設置值,則指針內存不會更改)並且您可以設置指向其他內存的指針.
關於 deleteHead(Node* &head) - 您使用包含節點指針的真實變量的引用。 該函數在同一變量中返回 head 的新值,也作為返回值。
您通過引用傳遞指針的原因與通過引用傳遞非指針的原因相同:讓函數修改其值。
讓我用一個更簡單的例子
#include <iostream>
void foo(int*& x) {
*x = 42; // change the value of the int x points to
x = nullptr; // change the value of x
}
第一行修改x
指向的值(但不修改x
)。 第二行修改x
本身。
int main() {
int y = 42;
int* y_ptr = &y;
foo(y_ptr);
if (y_ptr == &y) std::cout << "cannot happen";
}
因為我們設置了x = nullptr
,調用后y_ptr
將不再指向y
。
現在,如果我們修改foo
以不引用引用,我們將得到:
#include <iostream>
void foo(int* x) {
*x = 42; // change the value of the int x points to
x = nullptr; // change the value of x
}
第一行再次修改x
指向的int
。 但是,現在第二行只對x
局部的x
有影響。
int main() {
int y = 42;
int* y_ptr = &y;
foo(y_ptr);
if (y_ptr == nullptr) std::cout << "cannot happen";
}
y_ptr
的值y_ptr
將其傳遞給foo
來更改,因為它是按值傳遞的。
在您的代碼中,您有
Node* deleteHead(Node* &head)
{
if (head)
{
Node* temp = head;
head = head->next;
delete temp;
}
return head;
}
當你寫head = deleteNode(head)
會發生兩件事:
head
(因為它是通過引用傳遞的)以指向head->next
。head->next
)並分配給head
。 所以你基本上指定了兩次head
。 因為head
是通過引用傳遞的, deleteNode
會在不使用返回值的情況下做正確的事情:
deleteNode(head); // this already does modify head
...或者反過來說:如果您從功能返回“新”頭( head->next
)並將其分配給head
,那么是否通過引用傳遞指針並不重要,因為分配已完成函數內部也有同樣的效果。
您的代碼類似於
int* bar(int*& x) {
x = nullptr;
return x;
}
然后通過調用它
int y = 42;
int* y_ptr = &y;
y_ptr = bar(y_ptr);
通過不使用返回值bar(y_ptr)
可以實現相同的效果。 或者沒有指針也一樣(因為指針在這里真的沒有區別):
int moo(int& x) {
x = 0;
return x;
}
int x = 42;
x = moo(x); // same as `moo(x)`
PS:你不需要兩者(返回指針並在函數中分配它),所以最好讓函數返回void
。
引用是與值語義一起使用的“安全指針”(這在運算符重載上下文中非常有用),因此引用的用法與 C 中指針的用法非常相似,除了以下幾點:
這意味着您可以(或應該)在您想要更改原始傳遞變量(而不是它的副本)時傳遞引用。
也就是說,與您的函數等效的 C(粗略)是Node* deleteHead(Node** head)
。 請注意,由於您傳遞了一個引用,原始head
變量被修改,因此您的函數變得有點奇怪,因為它既修改 head 又返回其值。 您可以使用以下選項之一:
(1) 刪除 head(如果列表大小非空)並返回指向下一個元素的指針,這是不可取的,因為它會將 head 作為懸空指針留下。 這是您的原始功能,但沒有收到參考。
Node* deleteHead(Node* head)
{
if (head)
{
Node* temp = head; // You might want to use auto
head = head->next;
delete head;
}
return head;
}
(2) 和你的函數一樣,但是沒有返回值(因為你已經修改了 head)。 如果不傳遞引用,此方法將無法工作。
void deleteHead(Node* &head)
{
if (head)
{
Node* temp = head->next;
delete head; // deletes the content of head
head = temp;
}
}
對於指針 deleteHead 函數的引用,您可以使用 head = deleteHead(head) 或 deleteHead(head) 因為 head 只是 main 函數中 head 的引用,deleteHead 函數中 head 上的任何更改實際上都應用於 head 變量中主要功能。 對於指針版本,您必須使用 head = deleteHead(head)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.