在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
如果将指向a
和b
的地址视为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) == 4
, sizeof(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指针a
为int *
然后解除引用它意味着它将从包含在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);