2016-11-05 69 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

相关问题