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

时间:2014-04-18 04:52:10

标签: c function pointers qsort

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

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

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;
}

输出:dabce当我期待abcde时。

3 个答案:

答案 0 :(得分:8)

简单错误。

char*中使用int*代替cmpfunc

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

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

您的输入具有以下字符:

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

在十六进制中,那些是:

+----+----+----+----+----+
| 62 | 63 | 65 | 61 | 64 |
+----+----+----+----+----+
^    ^
|    |
a    b

如果您将指向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的内容。如您所见,您已经遇到意外的数字比较。当你开始比较输入的其他字节位置的值时,你也使用了你不应该使用的内存,并且你正在达到未定义行为的领域。

答案 1 :(得分:3)

这里至少有两个问题。

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

其次,最重要的是,您将比较函数中的void *转换为int *。假设sizeof(int) == 4sizeof(char) == 1,您实际上将字符0-3和#34;作为整数进行比较&#34;字符1-4和#34;作为整数&#34;。

sizeof(int) = 8(即64位编译器)的情况下,你会做得更糟。将void*投射到char*类型,您应该没问题。

答案 2 :(得分:0)

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

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

将空指针a强制转换为int *,然后取消引用它意味着它将从sizeof(int)中包含的地址开头读取a个字节。因此,return语句中的表达式是将sizeof(int)a地址的sizeof(int)字节数与b中地址的a字节数进行比较,而不是比较指针bint 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 *之后,以及在对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); 称为

即可
{{1}}