【问题标题】:Linked List node tail doesn't update when adding new nodes添加新节点时,链表节点尾部不更新
【发布时间】:2018-01-28 16:51:12
【问题描述】:

我正在玩一个链接列表类项目的指针,但我不知道如何创建指向新节点的链接。我有一个Linked List 类,其中包含append 之类的方法来操作数据结构。我希望节点是从 csv 文件中读取的出价。

当我从 csv 加载所有数据时,我想

  1. 创建新出价
  2. 将新出价传递给append 函数
  3. 设置Bid对象的nextBid指针并更新Linked List的尾部

我将不胜感激任何有关为每个投标对象创建新地址的指针,因为现在尾节点只“记住”第一个投标的地址。

Old Tail: 0x7ffeefbfee48
New Tail: 0x7ffeefbfee48
Old Tail: 0x7ffeefbfee48
New Tail: 0x7ffeefbfee48

我在下面复制了我的代码,省略了不相关的部分,例如从 csv 文件加载出价:

#include <algorithm>
#include <iostream>
#include <time.h>

#include "CSVparser.hpp"

using namespace std;

// forward declarations
double strToDouble(string str, char ch);

// define a structure to hold bid information
struct Bid {
    string bidId; // unique identifier
    string title;
    string fund;
    double amount;
    Bid* nextBid; //each bid has a pointer that can point to another bid
    Bid() {
        amount = 0.0;
    }
};

class LinkedList {
    
private:
    // FIXME (1): Internal structure for list entries, housekeeping variables
    Bid* head;
    Bid* tail;
    
public:
    LinkedList();
    virtual ~LinkedList();
    void Append(Bid bid);
    void Prepend(Bid bid);
    void PrintList();
    void Remove(string bidId);
    Bid Search(string bidId);
    int Size();
};

LinkedList::LinkedList() {
    // FIXME (2): Initialize housekeeping variables
    head=nullptr; //initialize head to point to nothing
    tail=nullptr;
}

void LinkedList::Append(Bid bid) { //<---I'm having trouble with this method
    // FIXME (3): Implement append logic
    if (this->head==nullptr){ //first node in a linked list
        cout << "initialize head and tail" << endl;
        this->head=&bid; //point to the bid
        this->tail=&bid;
    }
    else {
        cout << "Old Tail: " << this->tail << endl;
        this->tail->nextBid=&bid; //this refers to bid
        this->tail=&bid; //update last bid
        cout << "New Tail: " << &bid << endl;
        this->tail->nextBid=nullptr; //set pointer after last bid to null
    }
}

void displayBid(Bid bid) {
    cout << bid.bidId << ": " << bid.title << " | " << bid.amount
    << " | " << bid.fund << endl;
    return;
}

void LinkedList::PrintList() {
    // FIXME (5): Implement print logic
    //dont loop with the head, loop with bid name, because you dont want head pointer to change
    Bid* bid = this->head; //start at list's beginning
    cout << "List Head: " << this->head << endl;
    while(bid!=nullptr){
        displayBid(*(bid));
        cout << "Printing Address: " << bid << endl;
        bid = bid->nextBid; //move to the next bid
    }
}

Bid getBid() {
    Bid bid;
    //enter bid title, amount, etc.    
    return bid;
}

int main(int argc, char* argv[]) {
    
    // process command line arguments
    string csvPath = "eBid_Monthly_Sales_Dec_2016.csv";
    
    LinkedList bidList;
    
    Bid bid;
    
    int choice = 0;
    while (choice != 9) {
        cout << "Menu:" << endl;
        cout << "  1. Enter a Bid" << endl;
        cout << "  2. Load Bids" << endl;

        switch (choice) {
            case 1:{
                Bid addBid;
                cout << "new Bid Object's address is " << &addBid << endl; //address of the pointer
                bidList.Append(addBid);
//                displayBid(bid);
                bidList.PrintList();
                break;
            }
                

【问题讨论】:

  • &amp;bid 是 value 参数的地址,而不是你原来传递的那个地址。我想那不是你想要的。
  • 您需要知道对象和引用之间的区别,您传递对象并导致几乎每个函数中的复制。并且没有理由在这个类中创建析构函数virtual
  • 谢谢我让它工作了。不过,我仍然很好奇它的行为方式。如果bid在函数调用后被释放,为什么列表的头部没有重置为nullptr?现在它会记住初始化后列表中第一个出价的地址。
  • @st4rgut 关于您的后续问题:bid 现在是一个指针。因此,它的值是一个地址(如0x34ff56...)。具体来说,它是在您的main() 中创建的addBid 的地址。所以列表头的实际值是那个地址(或者:它指向addBid)。当append() 完成时,什么会被“摧毁”?只是bid 的值,它是地址,只是地址。但是该地址的副本现在保存在head 中。没有free() 操作正在进行。如果你用内存中的指针和对象绘制草图,你可能会弄明白。

标签: c++ linked-list


【解决方案1】:

问题是你试图在附加函数中分配一个指向临时变量的指针

void LinkedList::Append(Bid bid) { //<---I'm having trouble with this method
// FIXME (3): Implement append logic
if (this->head==nullptr){ //first node in a linked list
    cout << "initialize head and tail" << endl;
    this->head=&bid; //point to the bid
    this->tail=&bid;
}
else {
    cout << "Old Tail: " << this->tail << endl;
    this->tail->nextBid=&bid; //this refers to bid
    this->tail=&bid; //update last bid
    cout << "New Tail: " << &bid << endl;
    this->tail->nextBid=nullptr; //set pointer after last bid to null
}

您将Bid 对象传递给函数,而不是指针,然后您将tail 指针设置为指向该对象,但是该对象将在函数结束后被删除 因为它是在本地创建的。因此,tail 将指向已删除的对象,这将导致未定义的行为(我个人在 Linux 上得到“分段错误”)。作为一个选项,您可以将指向 Bid 对象的指针传递给函数,一切都会正常工作,因为指针将设置为在函数外部声明的有效 Bid 对象。

void LinkedList::Append(Bid* bid) { //<---I'm having trouble with this method
// FIXME (3): Implement append logic
if (this->head==nullptr){ //first node in a linked list
    cout << "initialize head and tail" << endl;
    this->head=bid; //point to the bid
    this->tail=bid;
}
else {
    cout << "Old Tail: " << this->tail << endl;
    this->tail->nextBid=bid; //this refers to bid
    this->tail=bid; //update last bid
    cout << "New Tail: " << bid << endl;
    this->tail->nextBid=nullptr; //set pointer after last bid to null
}

【讨论】:

    【解决方案2】:

    这里void LinkedList::Append(Bid bid)bid是一个局部变量,在控制从函数返回后会被释放。

    现在this-&gt;head=&amp;bid; //point to the bid 将局部变量bid 的地址分配给head,它在函数Append 的范围之外不存在。所以不会给出预期的结果。

    您可以做的是动态分配节点并将其地址传递给Append 方法。

    void LinkedList::Append(Bid* bid) // function signature
    

    添加节点:

    Bid addBid;
    bidList.Append(&addBid);
    

    【讨论】:

      【解决方案3】:

      append() 中的参数不应该是 Bid,而是 Bid *。这是因为,由于参数是在函数中按值传递的,因此您的出价对象只是原始对象的副本。
      这意味着在某处分配&amp;bid 时,该地址将是参数(复制的对象)的地址,而不是原始地址。
      因此,当函数完成并且其所有内存(在堆栈中)被“释放”时,该对象的内存也是如此,使您的节点指向垃圾。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-20
        • 1970-01-01
        • 2022-01-22
        相关资源
        最近更新 更多