问题编译K&R示例

我在编写本书第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版本。

我认为错误来自于旧C不知道const的事实:strcmp有两个指向非const字符( char * )我认为(这可能是它编译的原因,但不是你的编译器)。 但是,现在strcmp采用char const*const char*是一回事)。 将您的函数原型更改为:

 int numcmp(char const*, char const*); 

这是一个常见的问题:)

以下行告诉qsort期望指向具有两个void *参数的函数的指针。 不幸的是, strcmp需要两个不可修改的字符串,因此它的签名是

 int (*comp)(const char*, const char*) 

而不是你拥有的:

 int (*comp)(void *, void *) 

更改qsort1numeric的签名:

 qsort1(void *v[], int left, int right, int (*comp)(const void *, const void *)) 

和:

 int numcmp(const char*, const char*) 

qsort()bsearch()期望的标准函数指针具有原型:

 int comparator(const void *v1, const void *v2); 

代码中定义的qsort1()需要:

 int comparator(void *v1, void *v2); 

代码中定义的比较器函数没有该原型,并且不同的函数指针类型之间没有自动转换。

因此, qsort1()修复程序是:

  1. 引入一个强制转换: (int (*)(void *, void *)) ,或
  2. 重写比较器:

     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限定符,如本答案的第一个版本所示。

请注意, strcmp需要两个const参数,而numcmp则不需要。 因此,这两个函数的类型不匹配,而且? : ? :运营商会抱怨。

做其中一个:

  1. 根据numcmp更改numcmp以匹配strcmp原型
  2. 推送(int (*)(void*, void*))里面的? : ? : ,例如

     numeric ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp 

自从我完成任何纯C编程以来已经有一段时间了,我不确定新标准。

但是,转换为void **会创建一个指向指针的指针,其中函数需要指向数组的指针。 当然,它们在内部是相同的,但强大的类型检查会将其视为错误。

重写qsort接受**而不是* [],你应该没问题。