4

只是我还是Programming Pearls中的这段代码是错误的(quicksort 需要 2 个 const void,不是吗?)如果是这样,我的解决方案是否正确?抱歉,学习了...

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);
}
4

2 回答 2

7

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

如您所说, to 的最后一个参数qsort()是一个指向带有两个 type 参数的函数的指针const void*sortcmp接受不同的论点。你的编译器应该给你一个关于不兼容类型签名或其他东西的警告。在任何情况下,都会从一种类型的函数执行转换为另一种类型的函数。

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

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

然而,由于几乎在所有架构上,achar **和 aconst void*都以相同的方式表示,因此函数调用几乎总是有效的。

如果您想获得定义的行为,您必须确保您的比较器函数具有正确的类型签名,然后您可以将参数转换为正确的类型。您的解决方案是完全正确的,并且没有违反那里的 C 标准。正确性做得很好const——很多人不明白到底是什么char * const *意思。

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

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

于 2009-07-02T02:26:26.637 回答
2

你是对的,签名sortcmp不符合qsort预期。你的更正是对的。wordcmp也应该-const正确,因为您在技术上会在此过程中失去一些const-ness。

int wordncmp(const char *p, const char* q)
于 2009-07-02T02:26:56.840 回答