qsort 比较函数中的 const 限定符

问题描述

我使用 qsort 以两种方式对字符串数组(argv 本身)进行排序。我从 linux man 3 qsort 示例开始。 cmpstringp 只有一行:

 /* The actual arguments to this function are "pointers to
    pointers to char",but strcmp(3) arguments are "pointers
    to char",hence the following cast plus dereference */

 return strcmp(*(const char **) p1,*(const char **) p2);

我试图重新表述这个,它编译时没有警告

char *const* sp1 = vep1

const 属于中间 - 它是 argv 条目 (?)。至少这是 qsort 声明的要求。来自手册页的上述转换似乎不同且复杂。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* vep: void pointer to elements being qsorted 
   sp: string pointer (char **)            */
int 
cmpstringp(const void *vep1,const void *vep2) {

    char *const *sp1 = vep1,*const *sp2 = vep2;

    return strcmp(*sp1,*sp2);
}
/* Make char* from void*,and even char    */
int 
cmpchar(const void *p1,const void *p2) {

    const char *cp1 = p1,*cp2 = p2;

    char c1 = *cp1,c2 = *cp2;

    if (c1 == c2)
        return 0;
    else
        return c1 > c2 ? 1 : -1;
}

/* Sort cmd line args in two ways with qsort */
int main(int argc,char **argv) {

    /* sort chars of each string */
    for (int i = 1; i < argc; i++)
    qsort(argv[i],// base / first  
          strlen(argv[i]),1,// n_elems,elem_size
          cmpchar);

    /* sort argv strings 1 to argc-1 */
    qsort(argv + 1,argc - 1,sizeof *argv,cmpstringp);

    for (int j = 1; j < argc; j++)
        puts(argv[j]);

    return 0;
}

第二个 cmp 函数 cmpchar一个额外的赋值级别。如果没有,就会有一些像 if (*cp1 == *cp2) 这样无害的星星。

How do I sort the elements of argv in C?一个类似于手册页的解决方案,直接在 strcmp() 中进行转换。

但是我的无转换方法不是更正确吗?我收到警告,直到我将 const 放在它所属的位置。

解决方法

const中间中的 char *const *sp1 = vep1 表示 *sp1 指定的任何内容都是 const。这是必需的,因为 const void * 表示指针直接指向的内存应该是 const

您是对的,因为 const void * 不能在没有强制转换的情况下分配给 const char **,因为它不是 const 正确的。我个人尽量避免强制转换,因此我更喜欢您的代码而不是使用强制转换的代码。

然而,使用const char *const *sp1会更正确一些,因为没有理由cmpstringp不应该实际上也为const char **工作!

,

重新排序和对齐后,从右到左转换的内容和保守的变得更加清晰:

   int cmpstringp(void const *vep1,const void *vep2) {
    
                char * const *sp1    = vep1,...

const 被复制,“to void”被“to pointer (to char) 替换。它甚至不必是指针(例如结构体)。如果,那么我对此表示怀疑const-ness 可以扩展到所有引用,只是因为“比较”函数根本不应该修改。它可以修改所有对象,但不能修改正在排序的对象。

这一切都很有趣,但逻辑上很复杂。就像有一排盒子,里面有字母。首先,您将每个框内的字母按照它们本身进行排序(不要触摸框),然后根据字母对框进行排序(但不要触摸它们,即字母)。

感谢您的评论和回答。


6.5.16.1 简单赋值可能会处理这种情况。

指针分配的 3 个项目符号似乎需要:

  • 兼容类型,或者一种是无效的
  • 左侧具有右侧的所有限定词。
  • 右边的空指针没问题