-1

はい、qsort() 関数を 2 つの文字列で使用したいのですが、おそらくそれらは文字配列としてテストされます。実行すると、qsort.c の行 (151) で未処理の例外が発生します。

    if (__COMPARE(context, lo, mid) > 0) {
        swap(lo, mid, width);
    }

これは私のコードです:

#include <iostream>
#include <iomanip>
using namespace std;

struct SaleSlip{
    char name[20];
    int ProdID;
    double value;
};
int compare(void const *a, void const *b);
ostream& operator<<(ostream& out, SaleSlip& sales);

int main(){
    SaleSlip sales[17] = {
        {"Eric",   1, 200000.00},
        {"Sookie", 2,    200.00},
        {"Sookie", 4,    200.50},
        {"Bill",   3,   5000.00},
        {"Bill",   5,   7500.00},
        {"Tara",   4,    350.50},
        {"Eric",   2,    200.00},
        {"Tara",   2,    200.00},
        {"Tara",   4,    350.50},
        {"Bill",   5,   2500.00},
        {"Sookie", 1,  50000.00},
        {"Sookie", 2,    200.00},
        {"Eric",   5,  10000.00},
        {"Tara",   2,    200.00},
        {"Tara",   4,    150.50},
        {"Bill",   5,   1000.00},
        {"Sookie", 4,    400.50}        
    };
    cout << "The array before sorting is: " << endl;
    for(int i = 0; i < 17; i++)
        cout << sales[i];
    qsort(sales[0].name, 17, (sizeof(sales)/sizeof(char*)), compare);
    cout << "The array after sorting is: ";

    system("pause");
    return 0;
}

ostream& operator<<(ostream& out, SaleSlip& sales){
    out << setiosflags(ios::left | ios::fixed) << setw(7) << sales.name << setw(3) << sales.ProdID 
        << setprecision(2) << sales.value << endl;
    return out;
}

int compare(void const *a, void const *b) { 
    return strcmp(*(const char **)a, *(const char **)b);
}

私は正しく比較してテストしていますか?qsort を正しく呼び出していますか?

4

4 に答える 4

2

あなたが間違っていることは次のとおりです。

I. 要素サイズと要素数の両方として 17 を に渡しますqsort()。それは間違っています。2 番目の引数は配列内の要素の数であり、3 番目の引数は 1 つの個々の要素のサイズです。

Ⅱ.配列をソートしたいが、最初の要素のアドレスを渡すのではなく、最初の要素のnameメンバーへのポインターを渡します。これと間違った要素サイズを考えると、これからは、qsort()操作するすべてのポインターは非常に恣意的であり、それらを使用することは何の役にも立ちません。あなたができることは次のとおりです。

I. 適切なコンパレータ関数を作成し、厄介なトリックを含めようとしないでください。

qsort(sales, sizeof(sales) / sizeof(sales[0]), sizeof(sales[0]), comp);

int comp(const void *a, const void *b)
{
    // the two lines below are the aesthetic reason
    // for NOT using qsort() in C++. The ugly cast is not needed in C.

    const SaleSlip *s1 = static_cast<const SaleSlip *>(a);
    const SaleSlip *s2 = static_cast<const SaleSlip *>(b);

    return strcmp(s1->name, s2->name);
}

Ⅱ.または、さらに良い: use std::sortstd::stringおよび define SaleSlip::operator <:

class SaleSlip {
    bool operator <(const SaleSlip &that) {
        return this->name < that.name;
    }
};

std::sort(sales, sales + sizeof(sales) / sizeof(sales[0]));

おまけ: ハードコーディングされたサイズとタイプを使用しないでください。17危険でsizeof(array) / sizeof(SaleSlip)ある、より優れているが完全でsizeof(array) / sizeof(array[0])はない、配列の基本型と要素数に関係なく、完全に安全である。

于 2013-07-26T14:11:06.807 に答える
0

使用std::sort:qsortほとんどの場合、使用が難しく、効率が低くなります。

まず、order関数を書きます: struct SaleSlip{ char name[20]; int 製品 ID; 二重値; }; bool order(SaleSlip const& lhs, SaleSlip const& rhs) { return strncmp(lhs.name, rhs.name, sizeof(lhs.name))<0; 次に、これを次の場所にフィードしstd::sortます。

std::sort( &sales[0], &sales[sizeof(sales)/sizeof(sales[0])], order );

これで完了です。

C++11 では、その行の方が優れています。

std::sort( std::begin(sales), std::end(sales), order );

name固定サイズのバッファーではstd::stringなく、に置き換えることもできますが、生のcharバッファーを使用する理由があることは理解しています。その場合は、単にorderreturn に変更してlhs.name < rhs.nameください。

を使用するという選択以外に、元のコードの問題は、qsort並べ替えているメモリのブロックがSaleSlipオブジェクトではなくchar*オブジェクトであることです。まず、compare関数を修正します (そして、より適切な名前を付けます):

int compare_pvoid_SaleSlips(void const *a, void const *b) { 
  SalesSlip const* lhs = static_cast<SalesSlip const*>(a);
  SalesSlip const* rhs = static_cast<SalesSlip const*>(b);
  return strncmp(lhs->name, rhs->name, sizeof(lhs->name)/sizeof(lhs->name[0]));
}

次に、呼び出しを次のように修正しますqsort

qsort(&sales[0], 17, (sizeof(sales)/sizeof(sales[0])), compare_pvoid_SaleSlips);

これはうまくいくはずです。ただし、この方法に従うと、遅くなり、エラーが発生しやすくなり、壊れやすくなり、C++ プログラムではstd::sortソリューションよりもあらゆる点で悪化します。

于 2013-07-26T14:14:40.337 に答える
0

3 つの問題:

  • 最初の引数はsales、ソートする配列です。
  • size 引数はsizeof(SaleSlip)- 各要素のサイズです。
  • 比較は非常に奇妙なことをしています。名前へのポインターを取得するには、必要ですstatic_cast<const SaleSlip*>(a)->name(または(const char*)a、危険な生活をしたい場合)。

これらの問題は、C++std::sort関数 (およびstd::string文字列) を使用することで回避できます。これは、タイプ セーフであり、(多くの場合) よりも効率的ですqsort。次に、あなたは単に

std::sort(std::begin(sales), std::end(sales), 
    [](SaleSlip const & a, SaleSlip const & b) {return a.name < b.name;});
于 2013-07-26T14:15:10.107 に答える