-1

是的,我想将 qsort() 函数与两个字符串一起使用,这些字符串很可能会作为字符数组进行测试。当我运行它时,我在第 151 行的 qsort.c 中得到一个未处理的异常:

    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()。错了,第二个参数是数组中元素的数量,第三个是单个元素的大小。

二、你想对数组进行排序,但你没有传入它的第一个元素的地址,而是一个指向第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);
}

二、或者,更好的是:使用std::sortstd::string定义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 回答
2

您可能希望您的比较函数将 SaleSlip 指针作为参数。在比较函数中执行 strcmp(a->name,b->name)。当然,您对 qsort 的参数将更改为 SaleSlip 结构。

于 2013-07-26T14:06:01.297 回答
0

使用std::sort:qsort几乎在所有情况下都更难使用,而且效率较低。

首先,编写一个order函数:struct SaleSlip{ char name[20]; 诠释产品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用 astd::string而不是使用固定大小的缓冲区替换,但我知道有理由使用原始char缓冲区。如果这样做,只需更改order为 return 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

三个问题:

  • 第一个参数应该只是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 回答