【问题标题】:Seg Fault with Binary Heap Class when running on Linux, Insert Heap problems在 Linux 上运行时二进制堆类的 Seg 错误,插入堆问题
【发布时间】:2022-01-18 03:26:47
【问题描述】:

我已经用 C++ 实现了一个用于学校的二进制堆类。我在学校 Linux 服务器上运行的程序遇到问题。我的代码在我的 Mac 上 100% 正确输出。从 main.cpp 打印第一行代码后,它出现在 SegFault 中。我曾尝试使用 GDB,但无法确定问题所在。运行 GDB 给我以下问题:程序收到信号 SIGSEGV,分段错误。 std::string::assign(std::string const&) 中的 0x00007ffff7ae8d68。任何试图纠正此问题的帮助将不胜感激。

编辑: 我发现这是导致问题的插入函数:我已将函数更新为:

更新的插入功能:

template <class typ>
void Heap<typ>::insert(typ k) {
    if (size == 0) {
        size = size + 1;
        heap[size] = k;
        return;
    }
    if (size == cap-1) {
        cap = cap * 2;
        typ *tempHeap = new typ [cap];
        for (int i = 1; i <= size; i++)
            tempHeap[i] = heap[i];
        delete [] heap;
        heap = tempHeap;
    }
    size = size + 1;
    heap[size] = k; // insert item at end of heap
    int i = size; // set i to size
    while (i != 1 && heap[parent(i)] > heap[i]) { // move up to parents until heap property is restored all the way to the root
        swapKeys(&heap[parent(i)], &heap[i]); // swap items
        i = parent(i); // set i to parent of i
    }
}    

这修复了正在发生的段错误并正确输出堆。

【问题讨论】:

  • 导致失败的最小程序是什么?
  • C++ 程序“有效”并不一定意味着它是正确的并且不受UB 影响。
  • 在 OSX 上运行 100% 正确 -- 欢迎来到 C++ 的世界,未定义的行为可能意味着程序似乎可以工作。如果您使用std::vector&lt;typ&gt; heap; 而不是typ *heap;,那么无论您使用什么编译器,如果您使用heap.at(size) = k; 而不是heap[size] = k;,您都会看到失败。再一次,使用知道其大小并能够进行边界检查的容器的另一个优势,不同于原始指针和new[]

标签: c++ segmentation-fault


【解决方案1】:

插入第一个元素时,将 cap0 更改为 cap * 2,这仍然是 0 导致后续 heap[size] = k 具有未定义的行为。大概此时您还应该将cap 更新为您的数组的新大小。

你的下一个错误是你这样做:

size = size + 1; // update size
heap[size] = k; // insert item at end of heap

在此之前size 可能等于cap - 1,在增加它之后size 然后变为cap 导致heap[size] 具有未定义的行为。

这一行的注释与提示另一个错误的代码不匹配?

int i = size; // set i to one less than size

我不确定您的程序的预期行为,但以下代码至少不会再崩溃:

template <class typ>
void Heap<typ>::insert(typ k) {
    if (size == cap) { //resize the array when full
        cap = cap == 0 ? 2 : cap * 2;
        typ* tempHeap = new typ[cap];
        for (int i = 0; i < size; i++)
            tempHeap[i] = heap[i];
        delete[] heap;
        heap = tempHeap;
    }
    heap[size] = k; // insert item at end of heap
    int i = size; // set i to one less than size
    size = size + 1; // update size
    while (i != 1 && heap[parent(i)] > heap[i]) { // move up to parents until heap property is restored all the way to the root
        swapKeys(&heap[parent(i)], &heap[i]); // swap items
        i = parent(i); // set i to parent of i
    }
}

在一个不相关的注释中,避免#includeing cpp 文件,只应包含头文件。即使您将Heap.cpp 重命名为Heap.h,您也应该删除using namespace std;,这可能导致难以追踪编译器错误,请参阅Why is "using namespace std;" considered bad practice?

【讨论】:

  • 我已尝试将插入功能更新为您发布的内容,它不再崩溃,但输出现在不正确。我认为这是插入的东西,并试图在数组已满时调整其大小,但我不确定。在我的实现中,我从索引 1 开始定义堆,它包含最大尺寸的项目,而不是从 0 到 size-1。我会继续搞砸这个功能,谢谢你提供的所有信息。
  • 我打算插入函数在堆末尾添加新项目,然后在插入后使用while循环恢复任何堆属性错误。最重要的是,将数组大小调整为满时的两倍。
【解决方案2】:

程序的问题与插入和提取值时调整堆大小有关。更新 insert 和 extractMin 函数后,程序已修复。

【讨论】:

    猜你喜欢
    • 2019-06-01
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    相关资源
    最近更新 更多