堆实现中的奇怪分段错误

Strange Segmentation Fault in Heap Implementation

本文关键字:分段 错误 实现      更新时间:2023-10-16

下面是我为使用自己的堆实现编写的驱动程序。

#include<iostream>
#include"Heap.h"
int main(){
        Heap h(30);
        h.insert(1);
        h.insert(3);
        h.insert(5);
        h.insert(6);
        h.insert(5);
        h.insert(8);
        h.display();
        std::cout<<h.extractMin();    // Statement 1
        h.display();
        }

这给出了所需的结果:

========= Heap Contents =========
1   3   5   6   5   8   
1
========= Heap Contents =========
3   6   5   8   5

但是,如果我将statement 1更改为:

   std::cout<<"Min: "<<h.extractMin();

代码开始给出分段错误。同样,如果我将statement 1更改为

int z = h.extractMin();

代码仍然给出分段错误。这让我想看看我在extractMin()中是否做错了什么。以下是我对extractMin()的定义:

int Heap::extractMin()
{
    int min = this -> arr[0];
    this -> arr[0] = this -> arr[heapSize];
    heapSize -= 1;
    heapify(0);
    return min;
}

为了完整起见,下面是我对heapify():的定义

void Heap::heapify(int index){
        if(index > this -> heapSize)
                return;
        int smallest = index;
        int l = leftChild(index);
        int r = rightChild(index);
        if(l <= heapSize && arr[l] < arr[index])
                smallest = l;
        if(r <= heapSize && arr[r] < smallest)
                smallest = r;
        if(smallest != index){
                arr[smallest] = arr[smallest] ^ arr[index];
                arr[index] = arr[smallest] ^ arr[index];
                arr[smallest] = arr[smallest] ^ arr[index];
                heapify(smallest);
                }
        }

知道发生了什么事吗?我无法理解分割错误背后的原因。有什么明显我遗漏的吗?

谢谢!

附加1:

h.getHeapSize()h.getArrSize()也会发生这种情况,这让我认为问题在于其他方面,而不是函数。

附加2:

整个代码如下:

#include<iostream>
#include<cmath>
class Heap{
    private:
        int* arr;
        int size;
        int heapSize;
    public:
        Heap(int = 8); 
        Heap(int*, int size);
        int* initArr(int size);
        void setSize(int);
        int getSize();
        int getHeapSize();
        void setHeapSize(int);
        int leftChild(int);
        int rightChild(int);
        int parent(int);
        void heapify(int);
        void buildHeap();
        void insert(int);
        int extractMin();
        void display() const;
    };
Heap::Heap(int size){
    initArr(size);
    this -> size = size;
    this -> heapSize = -1;
    }
Heap::Heap(int* arr, int size){
    this -> arr = arr;
    this -> size = size;
    this -> heapSize = size - 1;
    buildHeap();
    }
int* Heap::initArr(int size){
    int* arr = new int[size];
    return arr;
    }
void Heap::setSize(int size){
    if(size > this -> heapSize)
        this -> size = size;
    }
int Heap::getSize(){
    return this -> size;
    }
void Heap::setHeapSize(int heapSize){
    this -> heapSize = heapSize;
    }
int Heap::getHeapSize(){
    return this -> heapSize;
    }
int Heap::leftChild(int index){
    return 2*index + 1;
    }
int Heap::rightChild(int index){
    return 2*index + 2;
    }
int Heap::parent(int index){
    return ceil(index >> 1) - 1;
    }
void Heap::heapify(int index){
    if(index > this -> heapSize)
        return;
    int smallest = index;
    int l = leftChild(index);
    int r = rightChild(index);
    if(l <= heapSize && arr[l] < arr[index])
        smallest = l;
    if(r <= heapSize && arr[r] < smallest)
        smallest = r;
    if(smallest != index){
        arr[smallest] = arr[smallest] ^ arr[index];
        arr[index] = arr[smallest] ^ arr[index];
        arr[smallest] = arr[smallest] ^ arr[index];
        heapify(smallest);
        }
    }
void Heap::buildHeap(){
    for(int i = heapSize/2 - 1; i >= 0; i-- )
        heapify(i);
    }
void Heap::insert(int val){
    heapSize += 1;
    int loc = heapSize;
    arr[heapSize] = val;
    int p;
    while((p = arr[parent(heapSize)]) > val){   
        arr[loc] = arr[p] ^ arr[loc];
        arr[p] = arr[p] ^ arr[loc];
        arr[loc] = arr[p] ^ arr[loc];
        }
    }
int Heap::extractMin(){
    //int temp = arr[0];
    //arr[0] = arr[heapSize];
    //arr[heapSize] = temp;
    int min = arr[0];
    arr[0] = arr[heapSize];
    heapSize -= 1;
    heapify(0);
    //return arr[heapSize + 1];
    return min;
    }
void Heap::display() const{
    std::cout<<"n========= Heap Contents =========n";
    for(int i = 0; i <= heapSize; i++)
        std::cout<<arr[i]<<'t';
    std::cout<<'n';
    }

存在许多问题。

首先,采用int参数的构造函数不会初始化arr成员,它会分配内存并将其分配给本地指针变量,然后返回该变量,但忽略返回值
您必须将其存储在成员变量中(将局部变量命名为与成员相同通常是一个非常糟糕的主意。)

一旦修复:在第一次插入时,h.insert(1);parent(heapSize)为-1。
由于您使用它在数组中进行索引,因此程序具有未定义的行为,并且所有赌注都已取消;该程序不是有效的C++程序。

可能还有其他问题,但这些问题是最明显的。

根据您在这里发布的内容,堆大小的处理不当是罪魁祸首。所有涉及heapSize的测试似乎都没有考虑到基于零的访问。你真的应该改变这一点,因为这会导致很多不合乎逻辑的后果:heapSize初始化为-1吗?

关于调试:

  • 轻松地添加更多的null和边界检查(不仅对heapSize,而且对0)
  • 尝试减少测试集(它是否与一个项目崩溃?)并尝试手动或使用gdb跟踪控制流

编辑

错误在parent()中。试试调试技巧。