oba*_*nby 2 c sorting comparison casting qsort
我正在尝试学习 C,并遇到了一个用于qsort对字符串数组进行排序的示例。
我正在努力理解以下内容:
int CompareWords(const void *a, const void *b) {
char **str1 = (char **)(a);
char **str2 = (char **)(b);
char *c1 = (char *)a;
char *c2 = (char *)b;
return strcmp(c1, c2);
// return strcmp(*str1, *str2);
}
Run Code Online (Sandbox Code Playgroud)
例程qsort不知道你在排序什么。它接受要排序的内容作为数组,您可以为其提供每个元素的字节数和元素数量。
由于qsort知道每个元素的字节数,因此可以计算每个元素的地址。但它不知道每个元素是什么类型。因此,当它希望您的例程比较两个元素时,它会使用 type 向该例程传递两个元素的地址const void *。它void是实际类型的替代品,意味着const这些地址处的数据不打算更改,只是进行比较。
您的例程确实知道元素的类型。您的数组包含指向字符的指针。具体来说,字符的类型为char,指向它们的指针为char *。所以你传递的地址qsort实际上是 a 的地址char *,即:char * *。除了向qsort您传递了一个指向const数据的指针,因此数据是char * const,而指向它的指针是char * const *。请注意,这char * const *是一个指向常量的指针char,而不是指向常量的指针char。
回顾:
\nchar *.qsort向您传递数组中元素的地址,因此它向您传递一个char * *.qsort添加了 a const,所以它传递给你 a char * const *。qsort不知道您的元素类型,因此它将部分更改char *为void并传递给您一个void const *,这与 相同const void *。char * const *.您可以通过以下方式将地址qsort传递转换为实际类型:
char * const *str1 = a;\nchar * const *str2 = b;\nRun Code Online (Sandbox Code Playgroud)\n如果您以const这种方式正确使用,则不需要石膏。编译器将允许在初始化中隐式转换,因为void *允许隐式转换为其他指向对象类型的指针,但const不允许隐式删除。移除const需要石膏。但是使用强制转换意味着const可能会被意外删除,所以应该避免\xe2\x80\x94最好在初始化时使用隐式转换而不是使用强制转换。
除了不更改指向 的指针之外char,此比较例程也不会更改char,因此我们可以const为它们添加,作为有助于避免错误的安全功能:
const char * const *str1 = a;\nconst char * const *str2 = b;\nRun Code Online (Sandbox Code Playgroud)\n接下来,我们得到了指向指针的指针,但我们需要使用的是后者。我们可以使用*str1和来获取和指向的*str2指针:str1str2
const char *c1 = *str1;\nconst char *c2 = *str2;\nRun Code Online (Sandbox Code Playgroud)\n现在c1并c2指向要进行比较的实际字符。
然后我们可以与 进行比较return strcmp(c1, c2);,这使得整个例程:
#include <string.h>\n\nint CompareWords(const void *a, const void *b)\n{\n const char * const *str1 = a;\n const char * const *str2 = b;\n const char *c1 = *str1;\n const char *c2 = *str2;\n return strcmp(c1, c2);\n}\nRun Code Online (Sandbox Code Playgroud)\n写出c1and的用法c2主要是为了说明。我们还可以将例程写为:
int CompareWords(const void *a, const void *b)\n{\n const char * const *str1 = a;\n const char * const *str2 = b;\n return strcmp(*str1, *str2);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n为什么这两个返回语句不同?
\n
return strcmp(c1, c2);问题中出现的问题是错误的,因为这些c1和c2只是从传递的地址转换而来的值。它们是我们需要的指针的地址,而不是我们需要的指针。
\n\n为什么我们需要将 void 指针转换为 (char **) 而不是 (char *)。
\n
提供给qsortsort 的数组是一个指向 的指针数组char,并将qsort比较例程指针传递给这些指针。它本身不传递指针。
(它无法传递指针本身,因为它不知道数组中的元素是什么类型。它不知道它们是指针,并且在 C 中没有办法传递您不知道类型的对象的值传递对象的值需要从内存中获取对象的字节并解释它们,并且在不知道它们的类型的情况下无法解释它们。)
\n