编程珍珠中的qsort函数出错?

时间:2009-07-02 02:04:49

标签: c std qsort programming-pearls

只是我或Programming Pearls中的这段代码是错误的(quicksort想要2个const空洞,不是吗?)如果是这样,我的解决方案是对的吗?道歉,只是学习......

int wordncmp(char *p, char* q)
{   int n = k;
    for ( ; *p == *q; p++, q++)
        if (*p == 0 && --n == 0)
            return 0;
    return *p - *q;
}

int sortcmp(char **p, char **q)
{   return wordncmp(*p, *q);
}
...

qsort(word, nword, sizeof(word[0]), sortcmp);

这是一个解决方案吗?

int sortcmp(const void *p, const void *q)
{   return wordncmp(* (char * const *) p, * (char * const *) q);
}

2 个答案:

答案 0 :(得分:7)

第一个代码示例可能几乎适用于任何编译器和CPU;但是,如果你遵循C标准,这是技术上未定义的行为。

正如你所说,qsort()的最后一个参数是一个指向函数的指针,该函数采用类型为const void*的两个参数。 sortcmp采用不同的论点。您的编译器向您发出有关不兼容类型签名或其他内容的警告。在任何情况下,都会从一种类型的函数到另一种类型的函数执行强制转换。

C标准指定您可以将函数指针强制转换为具有不同类型的其他函数指针,但是您不能取消引用并调用已转换的函数指针。但是,如果将函数指针重新转换回其原始类型,则调用已定义的行为 - 它将调用原始函数。

由于您从int (*)(char**, char**)转换为int (*)(const void*, const void*),然后最终qsort()正在调用您的比较器函数而不将其强制转换回int (*)(char**, char**),这是未定义的行为

但是,由于几乎在所有体系结构上,char **const void*的表示方式相同,因此函数调用几乎总是有效。

如果要获得已定义的行为,则必须确保比较器函数具有正确的类型签名,然后可以将参数转换为正确的类型。您的解决方案完全正确,并且不违反C标准。在const做得好 - 正确 - 很多人都不明白char * const *的含义。

您还应该wordncmp()const char*参数,因为您没有修改参数。

旁注:您在技术上也无法将函数指针强制转换为数据指针(例如void*),反之亦然。该标准允许函数指针和数据指针具有不同的大小。即使它在您的计算机上运行,​​也不能保证始终有效。

答案 1 :(得分:2)

你是对的,sortcmp的签名与qsort期望的签名不符。你的纠正是正确的。 wordcmp也应该const - 正确,因为您在技术上会失去一些const - 沿途。

int wordncmp(const char *p, const char* q)