带有圆形链接列表的崩溃

Crash with circular linked list

本文关键字:列表 崩溃 链接      更新时间:2023-10-16

我正在尝试实现一个链接列表(我相信这是一个圆形链接列表),但是在使用它后,它最终会崩溃。我认为这是因为我使用的遍历指针无法正确设置为0,最终删除并表现出不确定的行为。

感谢您的帮助。

这是我正在使用的功能:

struct records t_head = 0;
struct records* find_id(Rect a)
{
    struct records* tmp;
    struct records* prev;
    // Add first node
    if (t_head == NULL) {
        tmp = new records;
        tmp->b = a;
        tmp->id = trecord_count + 1;
        tmp->tally.resize(labelsInfo.size());
        tmp->frames = 0;
        t_head = tmp;
        t_head->next = NULL;
        trecord_count++;
    }
    else {
        // Check if there is any node that has delete_flag set first
        tmp = t_head;
        while (tmp) {
            if (delete_flag) {
                // Delete here
                if (tmp == t_head) {
                    t_head = tmp->next;
                    delete (tmp);
                    trecord_count--;
                }
                else {
                    prev->next = tmp->next;
                    delete (tmp);
                    trecord_count--;
                }
            }
            prev = tmp;
            tmp = tmp->next;
        }
        tmp = new records;
        tmp->b = a;
        tmp->id = trecord_count + 1;
        tmp->tally.resize(labelsInfo.size());
        tmp->frames = 0;
        tmp->next = t_head;
        t_head = tmp;
        trecord_count++;
    }
    return tmp;
}

结构定义是:

struct records {
int id;
Rect b;
vector<int> tally= {};
int frames=0;
int delete_flag=0;
struct records *next;
};

以下代码运行,但它在评论中已经提到的这些都显示了缺陷。

  1. 在您的版本中,您访问tmp中的指针,您刚刚在循环中删除了使用SET delete_flag搜索记录。这在以下版本中得到了纠正。所需的修改用//< Tobias标记。请注意,您可以在Linux下轻松发现此类错误。安登·科尔曼(Andon M. Coleman)也在他的评论中提到了这一点。
  2. 在您的find_id版本中,实际上没有搜索已实现的a。我已经在我的版本中实现了这样的搜索。
  3. 如果您在列表中间删除了一些记录,则最终记录保留其ID,但您降低trecord_count并再次分配相同的ID。因此,您最终获得了具有相同ID的多个记录。

编辑:我在程序中添加了一些日志记录。也许,这可以帮助您了解发生了什么。此外,我将frames滥用为真正的id。即,没有两个记录具有相同的 frames -value。记录在括号中,完整列表在方括号中。您没有圆形列表。也许,您会得到错误的印象,因为您在正面添加了新记录,因此,您需要将t_head的旧值用作新创建的记录的next的值。

程序的输出为:

g++ -std=c++11 -g -O0 ./test.cc -o a.exe && ./a.exe
Returning { frames=1 id=1 b=1 }
Full content:
[ { frames=1 id=1 b=1 } ]
Adding { frames=2 id=2 b=2 }
Returning { frames=2 id=2 b=2 }
Full content:
[ { frames=2 id=2 b=2 }, { frames=1 id=1 b=1 } ]
Adding { frames=3 id=3 b=3 }
Returning { frames=3 id=3 b=3 }
Full content:
[ { frames=3 id=3 b=3 }, { frames=2 id=2 b=2 }, { frames=1 id=1 b=1 } ]
Deleting head { frames=3 id=3 b=3 }
Adding { frames=4 id=3 b=4 }
Returning { frames=4 id=3 b=4 }
Full content:
[ { frames=4 id=3 b=4 }, { frames=2 id=2 b=2 }, { frames=1 id=1 b=1 } ]
Returning { frames=2 id=2 b=2 }
Full content:
[ { frames=4 id=3 b=4 }, { frames=2 id=2 b=2 }, { frames=1 id=1 b=1 } ]
Deleting { frames=2 id=2 b=2 }
Adding { frames=5 id=3 b=5 }
Returning { frames=5 id=3 b=5 }
Full content:
[ { frames=5 id=3 b=5 }, { frames=4 id=3 b=4 }, { frames=1 id=1 b=1 } ]

At exit: [ { frames=5 id=3 b=5 }, { frames=4 id=3 b=4 }, { frames=1 id=1 b=1 } ]

遵循名为 test.cc的程序:

#include <vector>
#include <iostream>
#include <cstdlib>
typedef int Rect;
struct records {
    int id;
    Rect b;
    std::vector<int> tally= {};
    int frames=0;
    int delete_flag=0;
    struct records *next;
};
struct records *t_head = 0;
int trecord_count = 0;
int trecord_frames = 0;
std::ostream& operator << (std::ostream& os, const records& r) {
    os << "{ frames=" << r.frames << " id=" << r.id << " b=" << r.b << " }";
    return os;
}
std::ostream& operator << (std::ostream& os, const records* r) {
    os << "[ ";
    if(r)
        os << *r;
    for(r=r->next; r; r=r->next)
        std::cout << ", " << *r;
    std::cout << " ]n";
}
struct records* find_id(Rect a)
{
    struct records* tmp;
    struct records* prev;
    // Add first node
    if (t_head == NULL) {
        tmp = new records;
        tmp->b = a;
        tmp->id = trecord_count + 1;
        tmp->tally.resize(0);
        tmp->frames = ++trecord_frames;
        t_head = tmp;
        t_head->next = NULL;
        trecord_count++;
    }
    else {
        // Check if there is any node that has delete_flag set first
        tmp = t_head;
        while (tmp) {
            if (tmp->delete_flag) {
                // Delete here
                if (tmp == t_head) {
                    std::cout << "Deleting head " << *tmp << std::endl;
                    t_head = tmp->next;
                    delete (tmp);
                    trecord_count--;
                    tmp = t_head; //< Tobias
                }
                else {
                    std::cout << "Deleting " << *tmp << std::endl;
                    prev->next = tmp->next;
                    delete (tmp);
                    trecord_count--;
                    tmp = prev->next; //< Tobias
                }
            } else {
                prev = tmp;
                tmp = tmp->next;
            }
        }
        // Search for the id
        tmp = t_head;
        while(tmp && (tmp->b != a))
            tmp = tmp->next;
        if(!tmp) {
            tmp = new records;
            tmp->b = a;
            tmp->id = trecord_count + 1;
            tmp->tally.resize(0);
            tmp->frames = ++trecord_frames;
            tmp->next = t_head;
            t_head = tmp;
            std::cout << "Adding " << *tmp << std::endl;
            trecord_count++;
        }
    }
    std::cout << "Returning " << *tmp << std::endl;
    std::cout << "Full content:n" << t_head << std::endl;
    return tmp;
}
int main() {
    find_id(1);
    find_id(2);
    find_id(3);
    t_head->delete_flag=1;
    find_id(4);
    records* r = find_id(2);
    r->delete_flag = 1;
    find_id(5);
    std::cout << "nAt exit: " << t_head;
    return 0;
}
/*
    Local Variables:
    compile-command: "g++ -std=c++11 -g -O0 ./test.cc -o a.exe && ./a.exe"
    End:
*/