2012-09-17 261 views
3

我試圖學習c庫stdlib的qsort函數。即使在c++中也提供了這個功能。但我不明白如何使用它們來排序c++字符串。我不確定sizeof()運營商的參數應該是什麼,以及我的compare_str代碼是否正確。我想這樣的代碼:如何比較在c中使用qsort的C++字符串?

#include<iostream> 
    #include<cstdlib> 
    using namespace std; 
    #include<string> 

    int compare_str(const void *a, const void *b){ 
     string obj = (const char*)a; 
     string obj1 = (const char*)b; 
     return obj.compare(obj1); 
    } 
    int main(){ 
     string obj[4] = {"fine", "ppoq", "tri", "get"}; 
     qsort(obj, 4, sizeof(obj[0].length()), compare_str); 
     for(int i=0; i<4; i++) 
      cout<<obj[i]<<endl; 
     return 0; 
    } 

我的產量爲:

ppoq 
tri 
get 
fine 

我不能夠做出來的錯誤。請幫忙。

+5

我很懷疑這部分 「的sizeof(OBJ [0]。長度())」 – drescherjm

回答

11

你不能,不能的std::string秒的陣列上使用qsort。元素必須是平凡類型,這些字符串不是,因此行爲未定義。從25.5/4(「qsort」):

除非base指向的數組中的對象是平凡類型,否則行爲未定義。

的原因是,將qsortmemcpy數組元素周圍,這是不可能的,一般的C++對象(除非它們是充分地微不足道)。


如果你有一個簡單的類型,你可以用這個通用qsorter比較器(當然,這是一個可怕的想法,而內聯std::sort始終是最好):

template <typename T> 
int qsort_comp(void const * pa, void const * pb) 
{ 
    static_assert<std::is_trivial<T>::value, "Can only use qsort with trivial type!"); 

    T const & a = *static_cast<T const *>(pa); 
    T const & b = *static_cast<T const *>(pb); 

    if (a < b) { return -1; } 
    if (b < a) { return +1; } 
    return 0; 
} 

用途:T arr[N]; qsort(arr, N, sizeof *arr, qsort_comp<T>);


不要使用它。改爲使用std::sort

+0

任何跡象表明,這將永遠打破一個字符串? – themel

+0

(+1)確實。我忘了在我的回答中提到這一點 - 這是這種情況下最重要的事情。 – PiotrNycz

+1

@themel任何跡象表明它永遠不會破裂(除非*「應該有效」*或*「適合你」*)? **知道**某種**不會發生**會比**假設**要好得多**,以致**不會中斷。 –

8

更好的是C++面向和使用std ::排序爲您的數組:

#include <iostream> 
#include <string> 
#include <iterator> 
#include <algorithm> 

int main() { 

    std::string obj[4] = {"fine", "ppoq", "tri", "get"}; 
    std::sort(obj, obj + 4); 
    std::copy(obj, obj + 4, std::ostream_iterator<std::string>(std::cout, "\n")); 
} 

AFAIK - std::sort使用快速排序。

[更新]查看評論,std :: sort並不總是純粹的快速排序。

[UPDATE2]

如果您想了解快速排序 - 改變std::stringconst char*和定義基於strcmp功能。請記住,qsort會傳遞指向數組中元素的指針 - 因此請解析const void*以獲得const char*。請參閱:

#include <stdlib.h> 
#include <string.h> 

int compare_cstr(const void* c1, const void* c2) 
{ 
    return strcmp(*(const char**)(c1), *(const char**)(c2)); 
} 

int main() { 

    const char* obj[4] = {"fine", "ppoq", "tri", "get"}; 
    qsort(obj, 4, sizeof(obj[0]), compare_cstr); 
    std::copy(obj, obj + 4, std::ostream_iterator<const char*>(std::cout, "\n")); 
} 
+1

在我看過的實現,'的std :: sort'竟是一個introsort(基本上*就是一個Quicksort,除了跟蹤遞歸深度,並且如果它太深,就會使用heapsort)。 –

+0

@Jerry似乎我的知識沒有達到你的要求;) – PiotrNycz

3

問題是你給qsort一個C++字符串數組。在你的比較函數中,你似乎除了C字符串,因爲你把它們轉換爲(const char *)。

另外,qsort的第三個參數,數據的大小,實際上會給出錯誤的值。的sizeof(OBJ [0]。length())將導致sizeof(size_t),這顯然是錯誤的。 sizeof(obj [0])會更正確,但請記住qsort不會調用字符串的拷貝構造函數,這可能會導致問題。

我會建議不要在C++字符串中使用qsort。

查看PiotrNycz提供的正確答案的答案。

-1

您的錯誤發生在qsort的尺寸聲明中。預計會員的大小,在你的情況下,是一個字符串。所以你想使用:

qsort(obj, 4, sizeof(string), compare_str); 

但是,你需要使用指向字符串的指針,而不是字符串本身。然後,代碼應該是這樣的:

int compare_str(const void *a, const void *b){ 
    const string* obj = (const string*)a; 
    const string* obj1 = (const string*)b; 
    return obj->compare(*obj1); 
} 

// ... 

string* obj[4] = { new string("fine"), new string("ppoq"), 
        new string("tri"), new string("get") }; 
qsort(obj, 4, sizeof(string*), compare_str); 
// And delete the objects 
for(int i = 0 ; i < 4 ; ++i) delete obj[i]; 
+0

什麼?...?好的,至少現在的代碼是正確的,至少如果你把'obj'和'obj1'改成'const std :: string **'的話。 –

-1

工作對我來說:

#include<iostream> 
#include<cstdlib> 
using namespace std; 
#include<string> 

int compare_str(const void *a, const void *b){ 
    string* obj = (string*)a; 
    string* obj1 = (string*)b; 
    return obj->compare(*obj1); 
} 
int main(){ 
    string obj[4] = {"fine", "ppoq", "tri", "get"}; 
    qsort(obj, 4, sizeof(string), compare_str); 
    for(int i=0; i<4; i++) 
     cout<<obj[i]<<endl; 
    return 0; 
} 
+4

確實:未定義的行爲通常看起來像「有效」。它會繼續工作,直到你爲你最重要的客戶做了關鍵演示,然後它就會落到面前。 –

+0

-1 - *「適合我」*從來不是C++中正確性的證明,尤其是當UB與本例中一樣明顯時(並且各方面的替代方法都遠遠優於**)。 –

0

您應使用由C++標準庫(在<algorithm>頭文件)提供的std::sort模板函數。默認情況下,std::sort使用小於比較運算符來對元素進行排序(std::string已實現operator<)。如果您需要指定排序條件(例如,不區分大小寫的字符串比較),則可以使用std::sort指定排序函數對象。

例子:

#include <string> 
#include <algorithm> 

bool caseInsensitiveOrdering(const std::string& lhs, const std::string& rhs) 
{ 
    // return true if lowercase lhs is less than lowercase rhs 
} 

int main() 
{ 
    std::string names[] = {"chuck", "amy", "bob", "donna"}; 
    size_t nameCount = sizeof(names)/sizeof(names[0]); 

    // Sort using built-in operator< 
    std::sort(names, names + nameCount); 

    // Sort using comparison function 
    std::sort(names, names + nameCount, &caseInsensitiveOrdering); 
}