关于作为参数传递给 qsort() 函数的比较函数的问题

Question concerning the comparison function passed as a parameter to the qsort() function

我正在学习 Coursera 的专业知识,在一节课中它解释了对给定数组进行排序的 qsort() 函数:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

我们应该为 qsort() 提供四个参数——要排序的数组、数组中元素的数量、数组中每个元素的大小,以及指向函数 (compar) 的指针,该函数接受两个 const void *s 和 returns 一个整数。课程说我们需要编写 compar 函数以与 qsort 函数兼容,因此如果我们想比较两个字符串,函数应该如下所示:

int compareStrings(const void * s1vp, const void * s2vp) {
  // first const: s1vp actually points at (const char *)
  // second const: cannot change *s1vp (is a const void *)
  const char * const * s1ptr = s1vp;
  const char * const * s2ptr = s2vp;
  return strcmp(*s1ptr, *s2ptr);
}

void sortStringArray(const char ** array, size_t nelements) {
  qsort(array, nelements, sizeof(const char *), compareStrings);
}

它说:请注意,传入的指针是指向数组中元素的指针(也就是说,它们指向数组中的框),即使这些元素本身就是指针(因为它们是字符串)。 当我们从 void *s 转换它们时,我们必须注意将它们转换为正确的类型——这里是 const char * const *— 并适当地使用它们,否则我们的功能将以某种方式被破坏。例如,考虑以下损坏的代码:

// BROKEN DO NOT DO THIS!
int compareStrings(const void * s1vp, const void * s2vp) {
  const char * s1 = s1vp;
  const char * s2 = s2vp;
  return strcmp(s1, s2);
}

我不太明白的是为什么我们不把s1vp 和s2vp 当作指向指针的指针?我的意思是,由于传递给函数 compareStrings 的参数是指向字符串的指针地址(指针地址),我们不应该将 s1vp 和 s2vp 声明为 int compareStrings(const void ** s1vp, const void ** s2vp) 因为它们正在接收指针地址?

换句话说,例如,我正在将字符串数组的第一个元素的地址(实际上是一个指针)传递给 s1vp。所以现在 s1vp 正在接收指针的地址而不是变量,所以我们应该将它声明为指向指针的指针,对吗?当我尝试这样做时它会给我警告...

一个void *可以指向任何数据类型。所讨论的数据类型也是指针这一事实并没有改变任何事情。

此外,您不能更改比较函数的签名,否则它将与 qsort 的预期不兼容,并可能导致 undefined behavior.