【问题标题】:C++ Linked List HEAD keeps resetting to NULLC++ 链表 HEAD 不断重置为 NULL
【发布时间】:2021-10-29 03:21:07
【问题描述】:

我需要帮助来了解为什么我的链接列表方法不能按预期工作。

#include <iostream>
using namespace std;

class Node {
public:
    int Data;
    Node* Next;
    
    Node(int data) {
        Data = data;
        Next = NULL;
    }
};

void insertNodeAtEnd(Node* HEAD, int data) {
    Node* it = HEAD;
    if (HEAD == NULL) { HEAD = new Node(data); }
    else {
        while (it->Next != NULL) { it = it -> Next; }
        it -> Next = new Node(data);
    }
}

void printLinkedList(Node* HEAD) {
    Node* it = HEAD;
    while (it != NULL) {
        cout << it->Data << endl;
        it = it -> Next;
    }
}

int main() {
    Node* HEAD = NULL;
    // Node* HEAD = new Node(0);
    
    insertNodeAtEnd(HEAD, 5);
    insertNodeAtEnd(HEAD, 2);
    insertNodeAtEnd(HEAD, 10);
    
    printLinkedList(HEAD);
    return 0;
}

上面的main() 函数不起作用(即:没有输出,并且只要控件离开insertNodeAtEnd(),HEAD 就会一直重置为 NULL),我在 SO 上发现了类似的问题,解释了这一点是因为指针是按值传递的,这对我来说有部分意义。
如果指针作为值传递,当我在 main() 函数中将 Node* HEAD = NULL; 替换为 Node* HEAD = new Node(0); 时,为什么它会按预期工作?

如果我像 Node* HEAD = new Node(0); 一样初始化 HEAD,但在最初 HEAD = NULL 的情况下不会添加节点?通过使用pointer to pointer,我能够让它正常工作,但我不明白为什么这种方法不起作用。如果我没有正确解释我的问题,我很抱歉,如果需要任何澄清,请告诉我。

【问题讨论】:

  • 我没有阅读所有内容,这可能无法回答您的问题,但if (HEAD == NULL) { HEAD = new Node(data); } 是内存泄漏。
  • @Brotcrunsher 我知道你说的是对的,因为 HEAD 没有保留新节点但内存从未释放,但我不明白为什么

标签: c++ pointers linked-list


【解决方案1】:

基本问题可以简化为以下代码:

void insertNodeAtEnd(Node* HEAD, int data) {
    //...
    if (HEAD == NULL) { HEAD = new Node(data); }
    //...
}

int main() {
    Node* HEAD = NULL;
    insertNodeAtEnd(HEAD, 5);
    //...

您似乎认为在insertNodeAtEnd 内分配给HEAD 会改变main 内的HEAD 变量。这不是真的。您的指针是按值传递的,因此会为函数复制地址。更改此复制的变量不会更改 main 内的 HEAD 的值。

要解决此问题,您可以将指针传递给指针,如下所示:

void insertNodeAtEnd(Node** HEAD, int data) {
    //...
    if (*HEAD == NULL) { *HEAD = new Node(data); }
    //...
}

int main() {
    Node* HEAD = NULL;
    insertNodeAtEnd(&HEAD, 5);
    //...

这个指向指针的指针仍然是按值传递的,但是它指向的指针将与来自main 的指针相同。

【讨论】:

  • 意识到如果你为第一个参数传入NULL,你的代码将会崩溃,即insertNodeAtEnd(NULL, 5);(将*HEAD解引用为NULL)。不知道为什么 C 代码最终会出现很多 C++ 代码(指向指针的指针)。我认为该参数应该是对指针的引用,即Node *&amp; HEAD,那么您不必为Node ** HEAD 测试NULL 值。
【解决方案2】:

问题来自您的第一次插入。您更改退出该功能时重置的 head 的值。只能更改指针后面的值,不能更改指针本身。

对此的解决方案是传递指针的指针。类似的东西:(未测试)

void insertNodeAtEnd(Node** HEAD, int data) {
    
    if (*HEAD == NULL) { *HEAD = new Node(data); }
    else {
        Node* it = *HEAD;
        while (it->Next != NULL) { it = it -> Next; }
        it -> Next = new Node(data);
    }
}

int main() {
    Node* HEAD = NULL;
    // Node* HEAD = new Node(0);
    
    insertNodeAtEnd(&HEAD, 5);
    return 0;
}

由于您不更改指针的指针,而仅更改其后面的值(指向 head 的实际指针),因此一旦退出函数,更改将保持不变。

【讨论】:

    【解决方案3】:

    @Brotcrunsher 已经给出了答案。我发帖是为了帮助您实现一个更好的解决方案,它将 列表列表元素 的概念分开,封装所使用的方法并释放它的资源使用,当它超出范围时:

    #include <iostream>
    using namespace std;
    
    class Node {
    public:
        int Data;
        Node* Next;
    
        Node(int data = 0) {
            Data = data;
            Next = nullptr;
        }
    };
    
    class List {
    public:
        Node* Head = nullptr;
    
        void Insert(int data) {
            if (Head == nullptr)
                Head = new Node(data);
            else {
                Node* ptr;
                for (ptr = Head; ptr->Next != nullptr; ptr = ptr->Next)
                    ;
                ptr->Next = new Node(data);
            }
        }
    
        void Print() {
            for (Node* ptr = Head; ptr != nullptr; ptr = ptr->Next)
                cout << ptr->Data << endl;
        }
    
        ~List() {
            Node* ptr = Head;
            while (ptr != nullptr) {
                Node* tmp = ptr;
                ptr = ptr->Next;
                delete tmp;
            }
        }
    };
    
    int main() {
        List list;
        list.Insert(5);
        list.Insert(2);
        list.Insert(10);
        list.Print();
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多