在C中使用qsort作为字符数组

我正在尝试使用qsort对字符数组进行排序。 我不明白为什么这不起作用。 我有一个指向比较函数的指针,如man页指定的那样。 有人可以告诉我有什么问题吗? 谢谢。 我的代码:

 #include  #include  #include  int cmpfunc( const void *a, const void *b) { return *(int*)a - *(int*)b; } void AlphabetSoup( char str[] ) { qsort(str, (size_t) strlen(str), (size_t) sizeof(char), cmpfunc); printf("%s\n", str); } int main() { char str1[] = "bcead"; AlphabetSoup(str1); return 0; } 

输出:当我期待abcde时的dabce

简单的错误。

cmpfunc使用char*而不是int*

 int cmpfunc( const void *a, const void *b) { return *(char*)a - *(char*)b; } 

当您使用int*而不是char*a指向的地址被解释为int的地址,而不是char

您的输入具有以下字符:

 +---+---+---+---+---+ | b | c | e | a | d | +---+---+---+---+---+ 

在hex中,那些是:

 +----+----+----+----+----+ | 62 | 63 | 65 | 61 | 64 | +----+----+----+----+----+ ^ ^ | | ab 

如果将指向ab的地址视为int* ,假设int在系统中占用4个字节, *(int*)a可以是

 0X62*2^24 + 0X63*2^16 + 0X65*2^8 + 0X61 

要么

 0X62 + 0X63*2^8 + 0X65*2^16 + 0X61*2^24 

取决于您是否具有大端系统或小端系统。

您可以类似地计算*(int*)b含义。 如您所见,您已经遇到意外的数字比较。 当您开始比较输入的其他字节位置的值时,您还使用了不应该使用的内存,并且您正在达到未定义行为的领域。

你这里至少有两个问题。

首先,您尝试对静态定义的文字的内容进行排序,编译器可以将其存储在不可变的ram中。

其次,最重要的是,您将比较函数中的void *转换为int *。 假设sizeof(int) == 4sizeof(char) == 1 ,则有效地将字符0-3“作为整数”与字符1-4“作为整数”进行比较。

sizeof(int) = 8 (即64位编译器)的情况下,那么你会做得更糟。 将void*转换为char*类型,你应该没问题。

问题在于比较函数comfunc的类型转换运算符。

 int cmpfunc(const void *a, const void *b) { // error. casting to int * instead of char * return *(int*)a - *(int*)b; } 

将void指针aint *然后解除引用它意味着它将从包含在a中的地址的开头读取sizeof(int)字节。 因此,return语句中的表达式是将a地址的sizeof(int)字节数与b地址的sizeof(int)字节数进行比较,而不是比较指针中包含的地址处的字符数和b 。 为了说明这一点,我将比较function更改为

 int cmpfunc(const void *a, const void *b) { printf("comparing %c and %c\n", *((char *)a), *((char *)b)); printf("compare as int %d - %d = %d\n", *(int *)a, *(int *)b, *(int *)a - *(int *)b); printf("compare as char %d - %d = %d\n", *(char *)a, *(char *)b, *(char *)a - *(char *)b); return *(char *)a - *(char *)b; } 

这是我得到的输出

 comparing b and c compare as int 1634034530 - 1684104547 = -50070017 compare as char 98 - 99 = -1 comparing a and d compare as int 25697 - 100 = 25597 compare as char 97 - 100 = -3 comparing e and a compare as int 6578533 - 25697 = 6552836 

在类型转换为int *之后以及在将类型转换为char *之后进行比较时,您可以看到读取值的差异。 比较function应更改为

 int cmpfunc(const void *a, const void *b) { // typecast the void pointers to correct type return *(char *)a - *(char *)b; } 

此外,您不需要转换strlen函数和sizeof运算符的结果,因为它们已经返回size_t类型的值。 此外,在数组元素上使用sizeof更具可读性和可维护性。 你应该简单地将qsort称为

 qsort(str, strlen(str), sizeof str[0], cmpfunc);