我尝试使用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
时。
答案 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
如果您将指向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
的内容。如您所见,您已经遇到意外的数字比较。当你开始比较输入的其他字节位置的值时,你也使用了你不应该使用的内存,并且你正在达到未定义行为的领域。
答案 1 :(得分:3)
这里至少有两个问题。
首先,您正在尝试对静态定义的文字的内容进行排序,编译器可以将其存储在不可变的ram中。
其次,最重要的是,您将比较函数中的void *转换为int *。假设sizeof(int) == 4
和sizeof(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
字节数进行比较,而不是比较指针b
和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 *
之后,以及在对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}}