C 在qsort函数中执行字符串指针的正确方法

C 在qsort函数中执行字符串指针的正确方法,c,C,假设我有一个要排序的字符串数组,例如: {"one", "two", "three", "four"}; 使用qsort传递这些字符串时,正确的强制转换操作是什么 int scmp(const void *p1, const void *p2) { // string1 = ??? }; 我的想法是,该项将是一个“指向字符串的指针”,由于字符串是一个“指向字符的指针”,这将给我一个“指向指针字符的指

假设我有一个要排序的字符串数组,例如:

{"one", "two", "three", "four"};
使用
qsort
传递这些字符串时,正确的强制转换操作是什么

int scmp(const void *p1, const void *p2) {
    // string1 = ???   
};
我的想法是,该项将是一个“指向字符串的指针”,由于字符串是一个“指向字符的指针”,这将给我一个“指向指针字符的指针”。以下是正确的方法吗

// 1. Pointer-to String
(String) *

// 2. String = Pointer-to-char
(char*) *

// 3. What about const-ness? Doesn't qsort require the 'value' to be const? 
//    Also, what about string = unsigned char -- is that important here?
(const char*) *
那么,
string1
的正确定义是:

int scmp(const void *p1, const void *p2) {
    const char* string1 = (const char**) p1;
};

这是正确的方法吗?您可以看到(至少对我来说)弄清楚指针声明(或本例中的强制转换)是多么乏味。有没有一种更直接的方法可以做到这一点——也就是说,如果我知道我想要一个“字符串指针”,我就可以做到(用正确的方法,使用
const
unsigned
或其他什么)在不到五分钟的时间内?

qsort
提供了带有两个常量指针的比较函数,指向数组的元素。您正在对一个“字符串”数组进行排序,也就是说一个
char*
数组。
char*
的数组是
char*[]
,指向此类数组中元素的指针是指向
char*
的指针,即
char**
,指向该数组中元素的常量指针是
char*const*

您可能会使用
strcmp
来比较这两个字符串,或者类似的东西。如果它是strcmp本身,您将得到:

int scmp(void const* va, void const* vb) {
  const char* a = *(char* const*)va;
  const char* b = *(char* const*)vb;
  return strcmp(a, b);
}

我在
a
b
中添加了不必要但无害的
const
限定符,因为
strcmp
不会改变其参数。除此之外,示例代码与查看

qsort
中的示例代码时发现的代码非常相似。qsort提供了一个比较函数,其中有两个常量指针指向数组的元素begin sorted。您正在对一个“字符串”数组进行排序,也就是说一个
char*
数组。
char*
的数组是
char*[]
,指向此类数组中元素的指针是指向
char*
的指针,即
char**
,指向该数组中元素的常量指针是
char*const*

您可能会使用
strcmp
来比较这两个字符串,或者类似的东西。如果它是strcmp本身,您将得到:

int scmp(void const* va, void const* vb) {
  const char* a = *(char* const*)va;
  const char* b = *(char* const*)vb;
  return strcmp(a, b);
}

我在
a
b
中添加了不必要但无害的
const
限定符,因为
strcmp
不会改变其参数。除此之外,示例代码与您在

中查看示例代码时会发现的代码非常相似,这有点混乱,因为
qsort()
如何使用指向元素的指针,因此,如果元素本身是指针,那么您需要以某种方式将
void*
转换为
char*
,同时还要一步一步地取消引用它

下面是如何编写此类函数的示例:

int qs\u strcmp(常数无效*a,常数无效*b){
返回strcmp(*(常量字符**)a),*((常量字符**)b));
}
以及一个测试程序,以显示其工作原理:

#包括
#包括
#包括
内部主(空){
字符*列表[]={
“波巴”,
“达达”,
“扎帕”,
“科布”,
“acdc”,
“阿巴”
};
int list_len=sizeof(list)/sizeof(char*);
qsort(&list[0]、list_len、sizeof(char*)、qs_strcmp);
对于(int i=0;i
这有点混乱,因为
qsort()
是如何使用指向元素的指针的,所以如果元素本身是指针,那么您需要以某种方式将
void*
转换为
char*
,但也需要一步取消引用它

下面是如何编写此类函数的示例:

int qs\u strcmp(常数无效*a,常数无效*b){
返回strcmp(*(常量字符**)a),*((常量字符**)b));
}
以及一个测试程序,以显示其工作原理:

#包括
#包括
#包括
内部主(空){
字符*列表[]={
“波巴”,
“达达”,
“扎帕”,
“科布”,
“acdc”,
“阿巴”
};
int list_len=sizeof(list)/sizeof(char*);
qsort(&list[0]、list_len、sizeof(char*)、qs_strcmp);
对于(int i=0;i
没有“指向字符串的指针”,它只是“指向字符的指针”,期望目标是一系列非NUL字节,后面是NUL字节。如果要对
char*
列表进行排序,则类型为
char*
。如果需要从
void*
进行强制转换,您可以将其强制转换回
char*
@tadman,对吗?第二个代码块是否阐明了这一点?我的意思是,从概念上讲,我认为
string
,我用
char*
写。我的建议是:不要认为
string
,它在C中不存在。它不应该存在于C中。任何
typedef
使它存在只会把事情搞得一团糟,因为你会认为
string
是一种你可以做的
sizeof
类型,这是错误的。重要的是要明确它是
char*
,它实际上是指向
char
的指针。该值应该从
void*
转换到
char*
,如果您愿意,您可以在这里执行
const
。@tadman:这是不正确的。比较函数的参数是指向char的常量指针,强制转换为指向const void的指针。在C中,字符串是“由第一个空字符终止并包含该空字符的连续字符序列”。字符串存在。不是作为类型,而是作为满足条件的数据描述。所以存在一个“字符串指针”,但这是对数据的描述。就像没有“指向奇数的指针”一样,我们可以有一个
int*
指向
7
,也可以有一个
unsigned*
指向
7