2013-07-26 2 views
-1

Да, я хочу использовать функцию qsort() с двумя строками, скорее всего, те будут проверяться как массивы символов. Когда я бегу, я получаю необработанное исключение в qsort.c на линии (151):Visual C++ - qSort with Strings

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 должным образом?

+6

Предложение: используйте 'std :: string' и' std :: sort'. – juanchopanza

+0

Нет, вы не вызываете 'qsort' должным образом. – Yakk

ответ

2

Возможно, вы хотите, чтобы ваша функция сравнения принимала указатели SaleSlip в качестве аргумента. В функции сравнения do strcmp (a-> name, b-> name). Конечно, ваши аргументы в qsort изменится, чтобы стать структурами SaleSlip.

2

Что вы делаете неправильно это:

I. Проходите в 17 и как размер элемента и элемента сосчитать до qsort(). Это неправильно, второй аргумент - количество элементов в массиве, третий - размер одного отдельного элемента.

II. вы хотите отсортировать массив, но вы не переходите в адрес его первого элемента, а указатель на элемент 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); 
} 

II. Или, еще лучше: использовать std::sort, std::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]) полностью безопасен, независимо от того, что вы делаете с базовым типом и количеством элементов массива.

+0

'const SaleSlip * s1 = a;'? Отсутствует приведение, я думаю ... – Yakk

+0

@Yakk Да, я привык к C ... В конце концов, если код нуждается в приведении типов, он выглядит подозрительным :) –

+0

Оценка H2CO3, особенно для решения моей упрямства и объяснения. – Svanhildr

0

Лучше использовать новые функции C++, такие как std::string, std::vector и std::sort.

Однако, если вам нужно исправить ваш, вы можете сделать эти изменения в std::qsort:

qsort(sales, 17, sizeof (SaleSlip), compare); 
     ^   ^
     |    // Size of each element 
    // First element 

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

Использование std::sort: qsort труднее использовать почти в каждом случае, и менее эффективное.

Во-первых, напишите order Функция: struct SaleSlip { название символа [20]; int ProdID; двойное значение; }; 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 буферы. Если вы это сделаете, просто измените order, чтобы вернуть 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); 

, который должен работать. Тем не менее, после этого метода будет медленнее, более склонным к ошибкам, более хрупким и во всех отношениях хуже в программе на С ++, чем решение std::sort.

0

Три проблемы:

  • Первый аргумент должен просто быть sales - массив вы хотите отсортировать.
  • Аргумент размера должен быть sizeof(SaleSlip) - размер каждого элемента.
  • Сравнение делает что-то очень странное. Чтобы получить указатель на это имя, вам нужно static_cast<const SaleSlip*>(a)->name (или (const char*)a, если вы любите жить опасно).

Этих проблем можно избежать, используя функцию С ++ (std::sort и std::string для строки), который является типобезопасным и (часто) более эффективен, чем qsort. Затем вы просто делаете

std::sort(std::begin(sales), std::end(sales), 
    [](SaleSlip const & a, SaleSlip const & b) {return a.name < b.name;});