C++ 关于通过引用传递指针的说明

C++ 关于通过引用传递指针的说明,c++,pointers,linked-list,C++,Pointers,Linked List,这有点傻,但我真的无法解释为什么会发生这种情况。作为练习,我想反转单个linkedlist,并通过定义方法实现了这一点: class solution { void reverseLinkedList(Node*& head) { Node* curr = head; Node* prev = NULL; while (curr != NULL) { Node* _next = curr->next; cu

这有点傻,但我真的无法解释为什么会发生这种情况。作为练习,我想反转单个linkedlist,并通过定义方法实现了这一点:

class solution {
    void reverseLinkedList(Node*& head) {
      Node* curr = head;
      Node* prev = NULL;
      while (curr != NULL) {
        Node* _next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = _next;
      }
      head = prev;
}
在我的主要功能中,我打电话

solution s;
s.reverseLinkedList(head);

Node* iterator = head;
while (iterator != NULL) {
    std::cout<<iterator->data<<std::endl;
    iterator = iterator->next;
}
解决方案s;
s、 反向列示器(头);
节点*迭代器=头;
while(迭代器!=NULL){

std::cout当您定期传递指针(即通过值)时,它会创建指针的副本。对该指针所做的任何更改都不会影响原始指针

通过引用传递指针就是向该指针发送引用(非常类似于向指针传递指针),因此对该指针所做的任何更改都会影响其“原始”状态

例如:

//WRONG does not modify the original pointer, causes memory-leak.
void init(Object* ptr, int sz) {
    ptr = new T[sz]; 
}
vs

我以为传球就足够了

通过值传递
指针
将创建一个用于函数内部的副本。

在函数内对该指针所做的任何更改都只反映在函数作用域中。
因为这些更改只反映在指针的副本中,而不反映在原始指针中

一旦
指针
(副本)超出范围,这些更改将因使用寿命终止而“放弃”

因此,您需要一个参考

void reverseLinkedList(Node&* head) // changes made in head will be
                                    // reflected in original head pointer

指针按值传递

这听起来很傻,这是一个奇怪的指针,对吧?有点像通过引用传递的定义。嗯,被指向的
节点
是通过引用传递的。指针本身,
head
只是另一个变量,恰好包含其他变量的地址,而不是通过引用传递

< > >代码>头<代码>包含用于调用<代码> ReSeleNeKeDistabs/COD>的节点> /Cult>指针,并且对于所有通过参数传递的参数,对复制、指向“代码>头/代码>其他地方的任何修改,都不在调用函数中表示。

C++中的局部变量(存储在堆栈中)具有块作用域,即,它们在定义它们的块执行后超出作用域

当您传入指向函数的指针时,将创建指针的副本,该副本就是传递的副本。一旦执行函数,函数工作区中的变量将超出范围。在函数中创建的任何非静态自动变量都将被销毁

通过引用传入时,不会传入变量的副本,而是传入实际变量,因此对变量所做的任何更改都会反映在传入函数(通过引用)的实际变量上

我想指出,指向下一个节点的指针存储在内存中,并且有一个指向其存储位置的地址。因此,如果您不想通过引用传入,可以执行以下操作:

  • 使用指向指针的指针,该指针指向存储指向下一个节点的指针变量(地址)的内存位置
  • 将其传递给函数(不是通过引用)
  • 取消对指针的引用并存储要指向的新地址
  • 我知道这有点让人困惑,但看看这段向链表中添加节点的代码

    void addNode(Node** head, int newData)
    {
        Node* newNode = new Node;
        newNode->data = newData; // Can also be done using (*newNode).data
        newNode->next = *head;
        *head = newNode;
    }
    

    如果按值传递指针,您将看不到指针的修改(
    head=prev
    ),而通过引用您可以。**一点切线,实际上很少有理由反转双链接列表,因为您可以简单地向后迭代并保存O(n)。尽管这总是很好的做法!以上假设您有一个尾部指针来记住列表的结尾。没有它,您将遭受O(n)查找列表结尾以便向后迭代的痛苦。大多数双链接列表实现都包含一个
    节点*last
    ,因此您可以在
    O(1)中添加到列表的结尾
    您所说的“函数一旦执行,我们就超出了函数的范围”是什么意思?@codekaizer:程序的内存分为数据段、堆、堆栈等。数据是存储初始化的全局变量和静态变量的地方。堆用于动态内存分配,堆栈用于存储函数参数、局部变量和函数相关信息。当我们输入函数时,它是allo在堆栈和此工作区中的特定内存中,将创建函数中定义的变量。当我们退出函数时,将删除函数中创建的变量(如果是非静态的)你不能访问它。我已经在Matlab、C++和Python之间切换,只是有点困惑。谢谢指点。推荐一个编辑:“因此,函数内创建的任何变量(非静态)都被破坏了。”->“函数内创建的任何非静态自动变量都被破坏了。”原始版本允许销毁动态变量,但事实并非如此。
    void reverseLinkedList(Node&* head) // changes made in head will be
                                        // reflected in original head pointer
    
    void reverseLinkedList(Node* head)
    
    void addNode(Node** head, int newData)
    {
        Node* newNode = new Node;
        newNode->data = newData; // Can also be done using (*newNode).data
        newNode->next = *head;
        *head = newNode;
    }