我在编写本书第5.11节中介绍的示例程序时遇到了问题。我删除了大部分代码,只留下相关内容。
#define MAXLINES 5000
char *lineptr[MAXLINES];
void qsort1(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
main(int argc, char *argv[]) {
int numeric = 1;
/* ... */
qsort1((void**) lineptr, 0, 100, (int (*)(void*, void*))(numeric ? numcmp : strcmp));
}
void qsort1(void *v[], int left, int right, int (*comp)(void *, void *)) {
/* ... */
}
int numcmp(char *s1, char *s2) {
/* ... */
}
问题是代码无法编译(我正在使用Digital Mars编译器)。我得到的错误是:
qsort1((void**) lineptr, 0, nlines - 1, (int (*)(void*, void*))(numeric
? numcmp : strcmp));
^
go.c(19) : Error: need explicit cast to convert
from: int (*C func)(char const *,char const *)
to : int (*C func)(char *,char *)
--- errorlevel 1
虽然我正确地粘贴了书中的代码,但声明一定有问题。我不知道做出正确的更改(关于函数指针的部分当然可以更广泛地编写)。
编辑:我应该提到我正在阅读本书的ANSI版本。答案 0 :(得分:9)
我认为错误来自于旧的C还不知道const的事实:strcmp有两个指针指向非const字符(char *
)我想(这可能是它编译回来的原因,但不是你的编译器)。但是,现在strcmp需要char const*
(const char*
是一回事)。将您的函数原型更改为:
int numcmp(char const*, char const*);
答案 1 :(得分:2)
qsort()
或bsearch()
所期望的标准函数指针具有原型:
int comparator(const void *v1, const void *v2);
代码中定义的qsort1()
期望:
int comparator(void *v1, void *v2);
代码中定义的比较器函数没有该原型,并且不同的函数指针类型之间没有自动转换。
因此,qsort1()
的修正是:
(int (*)(void *, void *))
或重写比较器:
int numcmp(void *v1, void *v2)
{
char *s1 = v1;
char *s2 = v2;
...
}
int str_cmp(void *v1, void *v2) // Note new function name!
{
return(strcmp(v1, v2));
}
显然,对qsort1()
的调用会引用str_cmp
而不是strcmp
。作者试图避免使用中间函数,但与现在使用的(合法的)繁琐的编译器相违背。
qsort()
的标准版本需要一堆const
限定符,与此答案的第一个版本一样。
答案 2 :(得分:2)
这是一个常见问题:)
以下行告诉qsort
期望指向具有两个void *参数的函数的指针。不幸的是,strcmp
需要两个不可修改的字符串,因此它的签名是
int (*comp)(const char*, const char*)
而不是你拥有的:
int (*comp)(void *, void *)
更改qsort1
和numeric
的签名:
qsort1(void *v[], int left, int right, int (*comp)(const void *, const void *))
和
int numcmp(const char*, const char*)
答案 3 :(得分:1)
请注意,strcmp
需要两个 const 参数,而numcmp
不会。因此,这两个函数的类型不匹配,? :
运算符会抱怨。
做其中一个:
numcmp
以匹配strcmp
原型
在(int (*)(void*, void*))
内推送? :
强制转换,例如
numeric ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp
答案 4 :(得分:0)
自从我完成任何纯C编程以来已经有一段时间了,我不确定新标准。
然而,转换为void **会创建一个指向指针的指针,其中函数需要指向数组的指针。当然,它们在内部是相同的,但强大的类型检查会将其视为错误。
重写qsort以接受**而不是* [],你应该没问题。