【问题标题】:Why can't I pushback a new element to a list为什么我不能将新元素推回列表
【发布时间】:2015-05-08 01:53:48
【问题描述】:

当我尝试将新元素推回列表时遇到问题。

这个问题是根据主体中的调用编写PushBack()的函数实现。所以我的问题只是关于函数PushBack()

#include <iostream>

 class Node{
 public:
    static Node* MakeNode() { return new Node(100); }
    Node* prev;
    Node* next;
    int value;
 private:
    Node(int num) : value(num), prev(NULL), next(NULL) {}
};

void PushBack(Node* simple, Node* newNode){
    if (simple == NULL){
        //still a empty list
        simple = newNode;
       }
    else{
    //need to loop to the end of list because there is no "tail" in the class
    Node* itr = simple;
    while (itr->next != NULL){
        itr = itr->next;
    }
    newNode->prev = itr;
    itr->next = newNode;
}
return;
}

int main()
{
    Node* simple = NULL;
    PushBack(simple, Node::MakeNode());
    std::cout << (simple == NULL);
    PushBack(simple, Node::MakeNode());
    PushBack(simple, Node::MakeNode());
    PushBack(simple, Node::MakeNode());
    while (simple != NULL){
       std::cout << simple->value << std::endl;
       simple = simple->next;
    }
    return 0;
}

我有两个关于函数PushBack()的参数类型的问题:

  1. MakeNode()的返回类型是static Node*,但是为什么我们要把PushBack()中的第二个参数类型设置为Node*呢?为什么不static Node *

  2. 一开始,我尝试了void PushBack(Node* simple, Node* newNode),但是当程序完成并从PushBack()退出时,simple又变成了NULL。 所以新元素不能添加到列表中。我必须使用void PushBack(Node*&amp; simple, Node* newNode)

为什么我需要在此处添加&amp; 符号?我认为如果我将指针值传递给函数,可以直接更改指针简单。但似乎情况并非如此。

我的问题和这个段有什么区别:?

void changeVal(int* data){
    for (int i = 0; i < 9; i++)
        *(data + i) = 99;
  }
void main()
{
     int *data;
     data = new int[10];
     changeVal(data);
     for (int i = 0; i < 9; i++)
         std::cout << data[i] << std::endl;
 }

我将指针data传递给changeVal(),函数内部可以改变内容。我不太明白这两者的区别。

我没能在网上找到一些有用的解释,所以我在这里问。

【问题讨论】:

    标签: c++ pointers reference


    【解决方案1】:
    1. 不,MakeNode() 的返回类型是Node*。您可以将类方法声明为static,这样您就可以在不需要类实例的情况下调用该方法,您可以在类类型本身上调用该方法。在这种情况下,static 不是返回值的一部分,它是类方法本身的一部分。至于PushBack(),没有static 函数参数这样的东西。该函数作用于Node 类的特定实例,因此它只是一个常规指针。

    2. 当您将simple 参数声明为Node* 时,您将按值 传递Node* 变量。该参数接收Node* 变量的当前值 的本地副本。函数读取或更改参数值的任何操作都是使用该 copy 完成的,而不是 original 变量。这就是为什么main() 中的simple 变量在PushBack() 退出时没有改变。

      另一方面,当您将simple 参数声明为Node*&amp; 时,您将通过引用 传递您的Node* 变量。该参数接收原始Node* 变量的内存地址。函数读取或更改参数值的任何操作都是直接使用 original 变量完成的,而不是 copy。这就是为什么 main() 中的 simple 变量在 PushBack() 退出时发生变化的原因。

    引用本质上是编译器管理的指针。不允许将其设置为 NULL,并且每当您从/向其读取/写入值时,它都会自动取消引用。因此,如果您将引用视为隐式指针,PushBack(Node*&amp;) 的功能等同于PushBack(Node**)(带有额外的编译器验证),类似于以下内容:

    void PushBack(Node** simple, Node* newNode){
        if (*simple == NULL){
            //still a empty list
            *simple = newNode;
        }
        else{
            //need to loop to the end of list because there is no "tail" in the class
            Node* itr = *simple;
            while (itr->next != NULL){
                itr = itr->next;
            }
            newNode->prev = itr;
            itr->next = newNode;
        }
        return;
    }
    
    PushBack(&simple, ...);
    

    【讨论】:

    • 1.您完全可以拥有静态函数参数(在 VC++ 中),以及 2。这非常令人困惑。该函数可能会收到一个 copy,但该副本仍然是传入的 Node 对象的确切内存地址,因此您仍然可以修改内存地址处的数据,但不能修改 Node* 所在的位置指向。
    • VC++在哪里定义静态函数参数? static 不是有效的参数修饰符。
    • 当你传递一个指针变量按值时,你传递的是它的值,即被指向对象的内存地址。它没有传递指针变量本身的内存地址。当您将指针 通过引用 传递时,您会得到它。
    • 嗨 Remy,非常感谢您的详细分析,非常感谢。但我仍然不清楚你的第二点:我知道simple 是一个指针。收到的PushBack() 应该是它的值,即指向的节点地址simple?我的问题与此有什么区别:int *data; data = new int[10]; changeVal(data);
    • changeVal() 不会更改 data 参数本身的值,就像 PushBack() 需要更改其 simple 参数一样。 changeVal() 只是填充 data 指向的数组(使用指针算法访问数组元素)。
    【解决方案2】:

    你需要传递一个指针引用而不仅仅是一个指针,这样 可以在 PushBack 函数内部更改 simple 指向的地址。

    这是来自MSDN的定义。

    指针引用的声明方式与 对对象的引用。声明对指针的引用会产生一个 像普通指针一样使用的可修改值。

    让我创建一个简单的插图:

    地址 |价值

    [0001]->
    [0002]->
    [0003]->
    [0004]->
    ......
    [nnnn]->
    

    当你启动你的程序时,你的变量 simple 指向 NULL:

    [0001]->NULL 
    [0002]
    [0003]
    [0004]
    ......
    [nnnn]
    

    当您第一次调用 PushBack 时,您只是传递了指向的值 通过简单的变量,它只是 NULL。

    [0001]->NULL 
    

    当您在 PushBack 函数中更改它的值时,您只是 更改该函数的本地副本,而不是实际的指针简单变量。 完成对 PushBack 的调用后,您的简单变量仍然指向 为 NULL。

    现在,当您传递引用指针时,您传递的是用作指针的简单变量的可修改值。当您更改指针的值时,您也在更改实际简单变量所指向的值。 使用指针引用调用 PushBack 后,简单变量将 现在指向 MakeNode 返回的新实例的地址。

    [0001]->newNode 
    [0002]
    [0003]
    [0004]
    ......
    [nnnn]
    

    【讨论】:

    • 嗨克里斯蒂安,非常感谢您的回答。我试图理解它,但我仍然有点困惑。我认为内存地址已经传入函数,所以我认为操作可以直接影响原始值...为什么是本地副本?我在原始问题处添加了一段新代码。这两者有什么区别?非常感谢!
    • 这是一个很好的插图参考:www3.ntu.edu.sg/home/ehchua/programming/cpp/…
    • 非常感谢!!我真的很感激。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    相关资源
    最近更新 更多