Programming Pearls 中的 qsort 函数出错?
Posted
技术标签:
【中文标题】Programming Pearls 中的 qsort 函数出错?【英文标题】:Error in qsort function in Programming Pearls? 【发布时间】:2010-11-07 12:13:51 【问题描述】:只是我还是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);
【问题讨论】:
【参考方案1】:第一个代码示例可能适用于几乎任何编译器和 CPU;但是,如果您严格遵守 C 标准,这在技术上是未定义的行为。
正如你所说,qsort()
的最后一个参数是一个指向函数的指针,该函数采用两个 const void*
类型的参数。 sortcmp
采用不同的参数。你的编译器应该给你一个关于不兼容类型签名或其他东西的警告。在任何情况下,都是从一种类型的函数到另一种类型的函数执行转换。
C 标准规定您可以将函数指针转换为具有不同类型的其他函数指针,但您不能取消引用和调用转换后的函数指针。但是,如果您将函数指针重新转换回其原始类型,则调用具有已定义行为的函数 - 它会调用原始函数。
由于您从int (*)(char**, char**)
转换为int (*)(const void*, const void*)
,然后最终qsort()
调用了您的比较器函数而不将其转换回int (*)(char**, char**)
,这是未定义的行为。
但是,由于几乎在所有架构上,char **
和 const void*
的表示方式都相同,因此函数调用几乎总是有效。
如果您想获得已定义的行为,您必须确保您的比较器函数具有正确的类型签名,然后您可以将参数转换为正确的类型。您的解决方案是完全正确的,并且没有违反那里的 C 标准。 const
-correctness 做得很好——很多人不明白 char * const *
的确切含义。
您还应该让wordncmp()
接受const char*
的参数,因为您没有修改参数。
旁注:从技术上讲,您也不能将函数指针转换为数据指针(例如void*
),反之亦然。该标准允许函数指针和数据指针具有不同的大小。即使它在您的计算机上运行,也不能保证始终运行。
【讨论】:
该标准实际上不能保证char *
和void *
具有相同的表示吗?我同意使用错误的函数指针类型进行调用仍然是 UB,但我不认为参数的表示是问题所在。相反,问题在于病态实现可以使用不同的调用约定来传递void *
与char *
,例如每种类型都有一组单独的参数寄存器。
@R.:是的,标准保证 char*
和 void*
具有相同的表示和对齐要求(C99 §6.2.5/27),但 char**
和 void*
不一定兼容。【参考方案2】:
你是对的,sortcmp
的签名与qsort
的预期不匹配。你的更正是对的。 wordcmp
也应该设为 const
-正确,因为从技术上讲,您在此过程中会失去一些 const
-ness。
int wordncmp(const char *p, const char* q)
【讨论】:
以上是关于Programming Pearls 中的 qsort 函数出错?的主要内容,如果未能解决你的问题,请参考以下文章
为 Python 查找最长重复字符串的有效方法(来自 Programming Pearls)
用 1 MB 空间对 1000 万个整数进行排序解决方案解释 - Programming Pearls
markdown [批量提取SDSS目录的SQL查询] #sdss #sherlock #catalogue #star #galaxy #qso