反转计数算法的段错误

Segement fault with Inversion Counting algorithm

我正在开发一个使用合并排序算法实现倒置计数的程序。

当我用给定的测试用例测试我的程序时。我遇到了分段错误,我找不到原因。

一个测试用例如下代码所示:

    int inputArray[5] = {5,4,3,2,1};
    inversionCount Inversion(inputArray, 5);
    count = Inversion.totalinversionCount(0, 4);

程序给出的正确答案是 10。

另一个测试用例是:

    int inputArray[15] = {9, 12, 3, 1, 6, 8, 2, 5, 14, 13, 11, 7, 10, 4, 0};
    inversionCount Inversion(inputArray, 15);
    count = Inversion.totalinversionCount(0, 14);

程序给出的答案是 48,而正确答案是 56。我试图通过在 class 中打印 array[] 元素来调试程序。在构造函数中,复制的数组 [] 似乎是 {9 12 3 1 6 8 2 5 14 13 11 7 10 4 0}。但是,当程序开始计数时,class 成员数组[] 变为 {0 12 3 1 6 8 2 5 14 13 11 7 10 4 0}。第一个元素从9变成了0,不知道为什么。

最后一个测试用例是:

    int inputArray[100] = { 4, 80, 70, 23, 9, 60, 68, 27, 66, 78, 12, 40, 52, 53, 44, 8, 49, 28, 18, 46, 21, 39, 51, 7, 87, 99, 69, 62, 84, 6, 79, 67, 14, 98, 83, 0, 96, 5, 82, 10, 26, 48, 3, 2, 15, 92, 11, 55, 63, 97, 43, 45, 81, 42, 95, 20, 25, 74, 24, 72, 91, 35, 86, 19, 75, 58, 71, 47, 76, 59, 64, 93, 17, 50, 56, 94, 90, 89, 32, 37, 34, 65, 1, 73, 41, 36, 57, 77, 30, 22, 13, 29, 38, 16, 88, 61, 31, 85, 33, 54 };
    inversionCount Inversion(inputArray, 100);
    count = Inversion.totalinversionCount(0, 99);

程序在构造步骤中遇到段错误。调试显示程序在将 Array[] 复制到 array[] 时暂停。

Signal received: SIGSEGV (Segmentation fault)
For program algorithm_design_i_week_1, pid 23,328
You may discard the signal or forward it and you may continue or pause the process

我的程序如下。请帮我找出分段错误的原因。非常感谢。

inversionCount.h

#ifndef INVERSIONCOUNT_H
#define INVERSIONCOUNT_H

#include <iostream>

using namespace std;   

class inversionCount {
private:
    int length;
    int array[];

public:
    inversionCount(int Array[], int Length);
    int splitCount(int first, int mid, int last);
    int totalinversionCount(int first, int last);
};

#endif /* INVERSIONCOUNT_H */

inversionCount.cpp

#include "inversionCount.h"

inversionCount::inversionCount(int Array[], int Length) {
    length = Length;
    for (int i = 0; i < length; i++) 
        array[i] = Array[i];
}

int inversionCount::splitCount(int first, int mid, int last) {
    int first1 = first, last1 = mid;
    int first2 = mid + 1, last2 = last;
    int tempArray[length];
    int i = first;
    int totalSplitCount = 0;
    while (i < last && first1 <= last1 && first2 <= last2) {
        if (array[first1] < array[first2]) {
            tempArray[i] = array[first1];
            first1++;
            i++;
        }
        else {
            tempArray[i] = array[first2];
            totalSplitCount += last1 + 1 - first1;   
            first2++;
            i++;
        }           
    }
    while (first1 <= last1) {
        tempArray[i] = array[first1];
        first1++;
        i++;
    }   
    while (first2 <= last2) {
        tempArray[i] = array[first2];
        first2++;
        i++;
    }  
    for (int j = first; j < last + 1; j++) 
        array[j] = tempArray[j];
    return totalSplitCount;
}

int inversionCount::totalinversionCount(int first, int last) {    
    int totalCount = 0;
    if (first < last) {
        int mid = (first + last) / 2;
        totalCount = totalinversionCount(first, mid) + totalinversionCount(mid + 1, last) + splitCount(first, mid, last);
    }       

    return totalCount;
}

countDriver.cpp

#include "inversionCount.h"

int main(int argc, char** argv) {
    int inputArray[5] = {5,4,3,2,1};

    inversionCount Inversion(inputArray, 5);
    int count = 0;
    count = Inversion.totalinversionCount(0, 4);
    cout<<"The number of inversions is "<<count<<endl;
    return 0;
}

int array[];作为成员变量的定义是不合法的C++。您的编译器必须允许它作为扩展,但在那种情况下,它意味着“没有 space 分配给数组,但我们会做类似的事情:

A* pA = static_cast<A*>(malloc(sizeof(A) + Length*sizeof(int));

你没有这样做,所以当你写入数组时,你覆盖了一些随机的内存位,所以不好的事情发生了。

最好的办法是使用 std::vector

class inversionCount {
private:
    std::vector<int> array;

public:
    inversionCount(int Array[], int Length) : array(Array, Array+Length) {}
    int splitCount(int first, int mid, int last);
    int totalinversionCount(int first, int last);
};

另一条评论:使用 size_t 作为数组和容器中的长度和偏移量的类型要好得多——这是 C++ 库使用的。 size_t 是无符号类型,因此通过使用与库相同的类型,可以避免 'signed/unsigned mismatch' 的难题。 (效果往往出乎你的意料。)