无法理解指向 C 中函数的指针

Unable to understand pointers to functions in C

我正在阅读 K&R 的 "The C Programming Language",我无法理解函数指针的概念。为了解释指向函数的指针,它给出了一个程序作为示例,如果给出了可选参数 -n,该程序将按数字而不是字典顺序对输入行进行排序。这是程序:

  #include <stdio.h>
    #include <string.h>
    #define MAXLINES 5000     /* max #lines to be sorted */
    char *lineptr[MAXLINES];  /* pointers to text lines */
    int readlines(char *lineptr[], int nlines);
    void writelines(char *lineptr[], int nlines);
    void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));
    int numcmp(char *, char *);
    /*sort input lines */
    main(int argc, char *argv[])
    {
      int nlines;  /*number of input lines read */
      int numeric =0;  /* 1 if numeric sort */
      if (argc>1 && strcmp(argv[1], "-n")==0)
      numeric=1;
      if ((nlines= readlines(lineptr, MAXLINES))>=0)
      {
         qsort((void **) lineptr,0,nlines-1, ***(int (*)(void*,void*))(numeric?numcmp:strcmp));***
         writelines(lineptr, nlines);
         return 0;
}
      else
      {
        printf("input too big to sort\n");
        return 1;
       }


}

我的问题是:

1) 在调用qsort时为什么没有传递类型为void*的参数(粗斜体部分)?

2)在对qsort的调用中(粗体和斜体部分),那个(*)在做什么,它解引用的函数在哪里?

谁能解开我的疑惑。

当您调用 qsort 时,您仅将指针 传递给函数 ,您不会调用函数本身。对 numericstrcmp 的调用发生在 qsort 函数内部(您不应声明自己,而是包含 <stdlib.h>,如 this qsort reference 所示,如果它是您正在调用的标准 qsort)。

为了更好地解释它,让我们制作一个小示例程序来展示如何使用和调用函数指针:

#include <stdio.h>

void hello(const char *name)
{
    printf("Hello %s\n", name);
}

void get_name_and_greet(void (*hello_function)(const char *))
{
    char name[256];
    printf("Please enter name: ");
    scanf("%255s", name);

    hello_function(name);  // Use the function pointer
}

int main(void)
{
    get_name_and_greet(&hello);  // Pass a pointer to the function
}

如您所见,将指针传递给函数与将指针传递给 int 变量没有什么不同。

如果你这样做了,例如

get_name_and_greet(hello("foo"));

你会 调用 hello 函数,并使用 hello return 作为 get_name_and_greet 的参数。这当然行不通,因为 hello 没有 return 任何东西,并且会导致编译错误。


至于 (int (*)(void*,void*)) 部分,这是一个简单的类型转换。

至于回答你的问题 1. 和 2. 我想你可能会从阅读螺旋法则中受益:

http://c-faq.com/decl/spiral.anderson.html

它有助于将看似复杂的 C 语句(如函数指针)翻译成简单的英语:

void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));

'qsort' 是一个带四个参数的函数,返回 void

参数 0 - lineptr - 空指针数组。

参数 1 - left - 一个整数。

参数 2 - right - 一个整数。

参数 3 - comp - 一个指向带有两个参数的函数的指针,每个参数都是一个 void 指针,returns 一个 int。

然后在您拨打 'qsort' 的电话中:

qsort((void **) lineptr,0,nlines-1, (int (*)(void*,void*))(numeric?numcmp:strcmp));

你提供的正是这些必要的参数,具体来说,我们来看第三个参数:

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

最后一个括号的计算结果为 'numcmp' 或 'stcmp'。在任何一种情况下,这都是一个返回 int 的函数,唯一的区别是传入参数的数据类型。不失一般性,让我们选择 'numcmp'.

那么我们有:

(int (*)(void*,void*))(numcmp)

我们在 'numcmp' 左边的是一个转换,它处理函数 'numcmp' 和 [=57= 之间参数数据类型的差异].在 K&R2 中,它实际上解释了这一点:

"The elaborate cast of the function argument casts the arguments of the comparison function. These will generally have no effect on actual representation, but assure the compiler that all is well."

此外,'stcmp'和'numcmp'是函数的地址,因为已知它们是函数,所以不需要&运算符。