为什么在构建链表C ++时必须指向指针

时间:2016-05-17 21:06:42

标签: c++ pointers

构建链表结构时。我已经学会了正确的方法,但我不知道为什么一个更简单的方法不起作用。我在互联网上搜索,我买了一本书,我玩了代码和理论,我终于称它退出并愿意在我的问题上处理一些负面因素,如果我错过了什么。所以这就是:

#include <bits/stdc++.h>
using namespace std;


struct Node{
    int data;
    Node* next;

    // Constructor
    Node(int data)
    {
       this->data = data;
       next = NULL;
    }
};

// Class to represent Red-Black Tree
class LinkedList{
private:
    Node* root;
public:
    // Constructor
    LinkedList() { root = NULL; }
    //insert new value into list
    void insert(const int n);
    //print all values from root to end;
    void print();
};

// Function to insert a new node with given data
void LinkedList::insert(const int data){
    Node** pp = &root;
    while (*pp)
        pp = &((*pp)->next);
    *pp = new Node(data);
}

void LinkedList::print(){
    Node** pp = &root;
    while (*pp){
        cout << (*pp)->data << " ";
        pp = &((*pp)->next);
    }
    cout << endl;
}



int main(){
    LinkedList ll;
    ll.insert(5);
    ll.insert(2);
    ll.insert(22);
    ll.print();

    return 0;
}

非常简单的东西,它运行得很漂亮。但是,这是一个问题。因为我不知道为什么我不能这样做:

void LinkedList::insert(const int data){
    Node* pp = root;
    while (pp)
        pp = pp->next;
    pp = new Node(data);
}

它应该像我在脑海中看到指针的方式一样。当我在纸上写下地址/内容对时,它仍然有意义。

谢谢, -Connor。

3 个答案:

答案 0 :(得分:2)

void LinkedList::insert(const int data){
    Node* pp = root;
    while (pp)
        pp = pp->next;
    pp = new Node(data);
}

此代码实际上并没有做任何事情。将pp设置为特定值会遇到很多麻烦,只是忽略该值并重新分配pp一些其他值。然后它返回,pp超出范围,它分配给它的值永远丢失。

让我们逐行完成:

void LinkedList::insert(const int data){
    Node* pp = root;

此时,pp是一个等于root的局部变量。

while (pp)
    pp = pp->next;

这会更改pp的值,直到它从列表末尾开始运行。所以我们已经完成了整个列表,只是最终突破了pp设置为NULL

    pp = new Node(data);

我们不会创建新的Node并更改pp的值以指向新的Node。所以我们遇到了麻烦,让pp指向最后一个节点,然后将其更改为指向新节点。

}

现在我们返回,pp超出范围,我们也没有对新的Node做任何事情。

您还可以看到:

void LinkedList::insert(const int data){
    Node* pp = root;
    while (pp)
        pp = pp->next;
    pp = new Node(data);
}

等同于(假设它不会永远运行):

void LinkedList::insert(const int data){
    Node* pp = root;
    pp = NULL;
    pp = new Node(data);
}

相当于:

void LinkedList::insert(const int data){
    Node* pp = NULL;
    pp = new Node(data);
}

相当于:

void LinkedList::insert(const int data){
    Node* pp = new Node(data);
}

相当于:

void LinkedList::insert(const int data){
    new Node(data);
}

这显然会创建一个新的Node并立即泄漏它。

答案 1 :(得分:1)

我不喜欢这样做:

void LinkedList::insert(const int data){
    Node** pp = &root;
    while (*pp)
        pp = &((*pp)->next);
    *pp = new Node(data);
}

我将使用的是:

// returns the last node or NULL on failure
bool LinkedList::insert(const int data){
    Node* pp = root;

    if (!pp){ // if it is an empty list
        root = new Node(data); // assign it to something
        return root; // convert to bool and return - false if new failed
    }

    while (pp->next) // check if we have a next node
        pp = pp->next; // we do have a next node so go there

    // at this point pp->next will be NULL

    pp->next = new Node(data); // assign it to something
    return pp->next; // convert to bool and return - false if new failed
}

答案 2 :(得分:1)

认为指针只是一个存储内存地址的变量类型。例如,int *只是一个变量(&#34;一个盒子&#34;),它存储另一个int变量的地址。

当你进入&#34;插入&#34;功能:

Node* pp;

pp是函数的 local 变量,用于将地址存储到Node对象。从函数返回时,本地变量将被销毁。

当你这样做时:

Node ** pp;

你定义了一个存储地址的局部变量,但不是Node对象,而是指向Node对象的指针,也就是另一个&#34;中间框&#34;将地址存储到Node对象。

最后,当你这样做时:

pp = &((*pp)->next);

你的局部变量,它会在你的函数返回时被销毁,存储到&#34; next&#34;的地址。会员。不喜欢你这样做:

pp = pp->next

您指定给&#34; pp&#34; 存储在&#34; next&#34;中的相同的地址(如果next是0x1234,这是一个表示对象地址的简单值,pp将得到相同的值0x1234),在列表的最后一个对象中为NULL。

用句子:

*pp = new Node(data);

&#34; pp&#34;的内容是指向Node对象的另一个指针的地址(不是直接指向对象),在这种情况下,这是&#34; next&#34;的地址。指针(不是&#34; next&#34;指针的值),以及指定&#34;新节点(数据)&#34;对于pp的内容,您将对象地址分配给&#34; next&#34;指针,它是列表对象的成员,而不是本地变量,你得到的是将新节点链接到列表。

为了更好地理解指针,您可以在纸上绘制变量的结构,将指针绘制为存储地址的框,并将其自己的地址作为变量。