2016-11-05 145 views
0

我正在使用qsort對C++中的字符串數組進行排序。我的代碼如下:如何使用qsort在C++中對字符串數組進行排序?

#include <iostream> 
#include <cstdlib> 
using namespace std; 
int CompareString(const void * e1, const void * e2) { 
    string * s1 = (string *) e1; 
    string * s2 = (string *) e2; 
    if(*s1 < *s2)  return -1; 
    else if(*s1 == *s2) return 0; 
    else if(*s1 > *s2) return 1; 
} 
int main() { 
    string Array[4] = {"hehe","789","456","123"}; 
    qsort(Array,4,sizeof(string),CompareString); 
    for(int i = 0;i < 4;++i) 
     cout << Array[i] << endl; 
    return 0; 
} 

但它收到運行時錯誤。我確實知道這種做法,但我想知道爲什麼我不能使用qsort。謝謝:)



這個問題類似於This Question 但也有一些差異。在這個問題中,人們建議使用sort來代替,或者在平凡的類型上使用qsort。但是,我的問題是我必須使用qsort而不是排序,所以我的問題沒有解決這個問題,我不認爲我的問題是重複的。至於爲什麼我不得不使用qsort而不是排序,答案是「這是分配的要求」,鏈接是:Here。我如下翻譯原題:

實施MyString的類,它繼承了STD:字符串,該代碼被編譯並且用下面的代碼正常運行:

MyString SArray[4] = {"big","me","about","take"}; 
qsort(SArray,4,sizeof(MyString), CompareString); 
for(int i = 0;i < 4;++i) 
    cout << SArray[i] << endl; 

MyString的應該是這樣的:

class MyString:public string{ 
... 
}; 

這個原始問題需要MyString來通過其他測試,我已經通過了。但我仍然無法通過qsort,所以我調整它,並問我的第一版quesion。

從答案中,我可以得出結論:qsort不適用於非POD。由於MyString繼承了字符串,並且字符串是非POD,所以MyString是非POD,因此MyString無法通過測試。

謝謝大家回答我的問題:)

+1

'sizeof(string)'看起來對我很可疑。這意味着該算法將假定對象是POD(無C++)。將'string'轉換爲'const char *'可能會工作。 –

+2

未定義的行爲,因爲'std :: string'不能保證與'qsort'一起使用。閱讀這個問題的答案:http://stackoverflow.com/questions/6174955/what-kinds-of-types-does-qsort-not-work-for-in-c –

+1

使用'std :: sort'。 'qsort'是令人討厭的舊C。

回答

2

爲了重新排列和移動數組,類的複製/移動內部構造C++類,和/或賦值運算符必須使用。 qsort()是C庫函數,它對std::string或任何其他C++類,其構造函數或析構函數都一無所知。 qsort()不能用於排序非POD類的向量。

使用std::sort()來排序你的向量,而不是。

+0

當然,不是直接對'std :: string'數組進行排序,而是可以將指針或索引數組排序到第一個。 –

+0

我以爲qsort知道指針,我們的compareString可以正確比較兩個字符串。所以qsort不需要關心「字符串」是什麼。它可以把它看作像c中的一個未知結構一樣。由於我們使用我們自己編寫的函數compareString進行比較,因此qsort只需使用兩個指針交換兩個字符串,那在c中是不可能的? – Casualet

+0

@Casualet是的,這在C中是不可能的,因爲'std :: string'必須使用其複製或移動構造函數和賦值運算符交換,而C不能這樣做。 – j6t

1

C的qsort不能移動非POD對象。但它可以移動指針。

#include <iostream> 
#include <string>   // std::string 
#include <vector>   // std::vector 
#include <stdlib.h>   // qsort 
using namespace std; 

auto compare(void const* e1, void const* e2) 
    -> int 
{ 
    string const* const p1 = *reinterpret_cast<string* const*>(e1); 
    string const* const p2 = *reinterpret_cast<string* const*>(e2); 
    return p1->compare(*p2); 
} 

template< size_t n > 
void sort(string (&a)[n]) 
{ 
    vector<string const*> pointers; 
    pointers.reserve(n); 
    for(string& item : a){ pointers.push_back(&item); } 
    qsort(&pointers[0], n, sizeof(pointers[0]), compare); 
    vector<string> result; 
    result.reserve(n); 
    for(string const* p : pointers) { result.push_back(move(*p)); } 
    for(int i = 0; i < int(n); ++i) { a[i] = move(result[i]); } 
} 

auto main() 
    -> int 
{ 
    string strings[4] = { "hehe", "789", "456", "123" }; 
    sort(strings); 
    for(string const& s : strings) 
    { 
     cout << s << endl; 
    } 
} 
1

您的代碼

string Array[4] = {"hehe","789","456","123"}; 

產生4個字符串,而不是4個指針:所以,如果你絕對必須使用qsort排序的std::string一個數組,你可以通過排序的指針的對應陣列做對於字符串,sizeof(std :: string)應該是3 * sizeof(void *)+某些常量,如果您的實現使用SmallStringOptimization。

嘗試我的閱讀技巧我會猜想你的想法Array是指向字符串或字符串本身的指針是一個指針。

字符串最初被聲明爲這樣(如果您刪除所有模板的東西)。

class string { 
    size_t length; 
    size_t capacity 
    char *buffer; 
}; 

如果你宣佈你的陣列

std::string *Array[4] = { 
    new std::string("hehe"), 
    new std::string("789"), 
    new std::string("456"), 
    new std::string("123") 
}; 

它的工作。

您可以看到整個代碼here

相關問題