无法理解C中函数的指针

Unable to understand pointers to functions in C

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  #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
"
);
        return 1;
       }


}

我的问题是:

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

2)在调用qsort(粗体和斜体部分)时,(*)单独做什么,它正在取消引用的函数在哪里?

有人能澄清我的疑虑吗?


当调用qsort时,只传递一个指向函数的指针,而不调用函数本身。对numericstrcmp的调用发生在qsort函数中(如果您所调用的是标准qsort引用,则不应声明您自己,而是包括中所示的qsort引用)。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

void hello(const char *name)
{
    printf("Hello %s
"
, 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变量传递指针没有什么不同。

如果你有,例如

1
get_name_and_greet(hello("foo"));

您可以调用hello函数,并使用hello返回的值作为get_name_and_greet的参数。这当然不起作用,因为hello不会返回任何内容,并且会导致编译错误。

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


关于回答你的问题1。和2.我认为你可以从阅读螺旋法则中获益:

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

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

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

"qsort"是一个接受四个参数的函数,返回void

参数0—lineptr—一个空指针数组。

参数1—left—一个int。

参数2-right-an int.

参数3—comp—指向一个函数的指针,该函数接受两个参数,每个参数都是一个空指针,并返回一个int。

然后在你呼叫"qsort"时:

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

您提供了这些必要的参数,更具体地说,让我们来看第三个参数:

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

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

那么我们有:

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

我们在"numcmp"的左边有一个cast,它处理函数"numcmp"和"strcmp"参数的数据类型的差异。在K&R2中,它实际上解释了这一点:

"函数参数的详细转换将转换比较函数的参数。这些通常对实际表示没有影响,但要确保编译器一切正常。"

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