簡體   English   中英

排序功能實現中的分段錯誤

[英]Segmentation Fault in the implementation of a sorting function

我正在嘗試基於為我的編程課程提供的偽代碼實現排序算法,我和我的合作伙伴一直在收到(核心轉儲)錯誤,通常特別是分段錯誤。 我知道這通常意味着程序試圖訪問它不允許的內存,但我不確定如何解決這個問題。

#include <iostream>
#include <cmath>

using namespace std;

void FlipFlopSort(int *Array, int begin, int end){
    int length = (end-begin);
    float midh = 2*(float)length/3;
    midh = ceil(midh);
    float midl = (float)length/3;
    midl = ceil(midl);
    //cout << "size of sorted area = " << length << endl;
    if(length<=2){
        //cout << "Length = 2" << endl;
        if(Array[begin] > Array[begin+1]){
            swap(Array[begin], Array[begin+1]);
        }
    }else{
        //cout << "Recursion Begin 1" << endl;
        FlipFlopSort(Array, begin, midh);
        //cout << "Recursion End" << endl;
        FlipFlopSort(Array, midl, end);
        //cout << "Recursion Begin 2" << endl;
        FlipFlopSort(Array, begin, midh);
    }
}

int main(){
    // Declare Variables and Read Inputs
    int n;
    cin >> n;

    int Array[n];

    for(int i = 0; i < n; i++){
        cin >> Array[i];
    }

    FlipFlopSort(Array, 0, n);


    for(int i = 0; i<n; i++){
         if(i != (n-1)){
             cout << Array[i] << " ";
         }else{
             cout << Array[i] << endl;
         }
    }

    return 0;

}



讓我們開始:

    int n;
    cin >> n;

    int Array[n];
  1. 為什么是 na 有符號類型? 數組大小不能聲明為有符號類型。
  2. C++ 嚴格禁止在堆棧上聲明可變大小的數組(即您所做的方式)。 它也是 C 的一個不推薦使用的特性。你應該寫:
    int* Array = new int[n];

您可能會遇到分段錯誤的原因之一是由於以下行:

    if (length <= 2) {
        //cout << "Length = 2" << endl;
        if (Array[begin] > Array[begin + 1]) {
            swap(Array[begin], Array[begin + 1]);
        }
    }
  1. 如果長度小於或等於 2,是否意味着它至少有 2 個元素? 它可能有 0 或 1。您應該在函數的開頭添加一個檢查:
void FlipFlopSort(int *Array, int begin, int end){
    int length = (end-begin);
    if (length <= 1) {
        return;
    }
    ...
}

另一個原因是因為您計算的是中間尺寸而不是索引,這意味着您不會向它們添加開始。

考慮:開始=100,結束=103。 -> 長度 = 3,midl = 1 和 midh = 2。有意義嗎? 不! 在這種情況下,這些不是有效的索引。 你應該寫

midh += begin;
midl += begin;

經過他們的計算。

最后一件事,你應該避免使用浮點數(除非你真的需要)所以我會寫:

    const int midl = begin + length / 3;
    const int midh = begin + 2 * midl;

它與您編寫的內容不同,但它仍然有效,而您的則有風險(上限值很可疑,因為您可能會發現自己位於數組的末尾)。

void FlipFlopSort(int* Array, int begin, int end) {
    const int length = end - begin;
    if (length <= 1) {
        return;
    }

    const int midh = begin + 2 * length / 3;
    const int midl = begin + length / 3;

    //cout << "size of sorted area = " << length << endl;
    if (length <= 2) {
        //cout << "Length = 2" << endl;
        if (Array[begin] > Array[begin + 1]) {
            swap(Array[begin], Array[begin + 1]);
        }
    }
    else {
        FlipFlopSort(Array, begin, midh);
        FlipFlopSort(Array, midl, end);
        FlipFlopSort(Array, begin, midh);
    }
}

當您swap ,您必須確保length至少為 2,否則您將交換數字越界。 您的midlmidh值目前是錯誤的。 它們與begin ,因此您需要向它們添加begin 但是,您可以將midl添加到Array本身並跳過函數中的begin參數以簡化界面。

我還將用整數版本替換浮點std::ceil操作。

// A function to do integer division and return the ceil value
size_t DivCeil(size_t dividend, size_t divisor) {
    return 1U + ((dividend - 1U) / divisor);
}

void FlipFlopSort(int* Array, size_t length) {
    if(length > 2) {
        // calculate midl & midh
        size_t midl = DivCeil(length, 3U);
        size_t midh = DivCeil(2U * length, 3U);

        FlipFlopSort(Array, midh);
        // add midl to Array and sub midl from length
        FlipFlopSort(Array + midl, length - midl);
        FlipFlopSort(Array, midh);
    } else if(length == 2) {
        if(Array[1] < Array[0]) {
            // swap the values
            std::swap(Array[0], Array[1]);
        }
    } // else length < 2 ... don't do anything
}
#include <iostream>
#include <vector>

int main() {
    size_t n;
    if(std::cin >> n) { // check that the user entered a number
        // don't use VLA:s, use a std::vector instead
        std::vector<int> Array(n);

        for(size_t i = 0; i < Array.size(); ++i) {
            std::cin >> Array[i];
        }

        FlipFlopSort(Array.data(), Array.size());

        for(int value : Array) {
            std::cout << value << '\n';
        }
    }
}

如果您希望排序算法更通用且可用於標准容器,您可以用迭代器替換輸入參數。

例子:

#include <algorithm> // std::iter_swap
#include <iterator>  // std::distance, std::next

// A function to do integer division and return the ceil value
template<typename T>
T DivCeil(T dividend, T divisor) {
    return 1 + ((dividend - 1) / divisor);
}

template<typename It>
void FlipFlopSort(It begin, It end) {
    auto length = std::distance(begin, end);     // iterator version of "length = end-begin"
    static constexpr decltype(length) two = 2;   // constant of the same type as length
    static constexpr decltype(length) three = 3; // -"-

    if(length > two) {
        // calculate midl & midh iterators
        auto midl = std::next(begin, DivCeil(length, three));
        auto midh = std::next(begin, DivCeil(two * length, three));

        FlipFlopSort(begin, midh);
        FlipFlopSort(midl, end);
        FlipFlopSort(begin, midh);
    } else if(length == two) {
        if(*std::next(begin) < *begin) {
            // swap the values pointed at by the iterators
            std::iter_swap(begin, std::next(begin));
        }
    } // else length == 1 or 0 ... don't do anything
}

用法:

#include <iostream>
#include <vector>

int main() {
    size_t n;
    if(std::cin >> n) {
        std::vector<int> Array(n);

        for(size_t i = 0; i < Array.size(); ++i) {
            std::cin >> Array[i];
        }

        FlipFlopSort(std::begin(Array), std::end(Array));

        for(int value : Array) {
            std::cout << value << '\n';
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM