简体   繁体   English

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

[英]Unable to understand pointers to functions in C

I am reading "The C Programming Language" by K&R and am not able to understand the concept of pointers to functions.我正在阅读 K&R 的“C 编程语言”,但无法理解函数指针的概念。 To explain pointers to functions it gives a program as an example, the program sorts input lines numerically instead of lexicographically if an optional argument -n is given.为了解释指向函数的指针,它以一个程序为例,如果给出了可选参数 -n,则该程序按数字而不是按字典顺序对输入行进行排序。 Here is the program:这是程序:

  #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;
       }


}

My questions are:我的问题是:

1) In the call to qsort why are no arguments passed of type void*(in the bold and italicized part)? 1) 在对 qsort 的调用中,为什么没有传递 void* 类型的参数(在粗体和斜体部分)?

2)In the call to qsort (in the bold and italicized part), what is that (*) doing all alone, where is the function that it is dereferencing? 2)在对qsort的调用(在粗体和斜体部分)中,那个(*)在做什么,它正在取消引用的函数在哪里?

Can someone clarify my doubts.有人可以澄清我的疑问。

When you call qsort you only pass a pointer to the function , you do not call the function itself.当您调用qsort您只传递一个指向函数的指针,而不是调用函数本身。 The call to numeric or strcmp happens inside the qsort function (which you should not declare yourself, instead include <stdlib.h> as shown in eg this qsort reference , if it's the standard qsort you're calling).numericstrcmp的调用发生在qsort函数内部(您不应该声明自己,而是包括<stdlib.h>如在这个qsort参考中所示,如果它是您正在调用的标准qsort )。

To explain it better, lets make a small example program which shows how to use and call a function pointer:为了更好地解释它,让我们制作一个小示例程序,展示如何使用和调用函数指针:

#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
}

As you can see, passing a pointer to a function is no different than passing a pointer to an int variable.如您所见,将指针传递给函数与将指针传递给int变量没有什么不同。

If you did eg如果你做了例如

get_name_and_greet(hello("foo"));

you would call the hello function, and use what hello returns as argument to the get_name_and_greet .您将调用hello函数,并使用hello返回的内容作为get_name_and_greet参数。 This will of course not work, as hello doesn't return anything, and would lead to a compilation error.这当然不起作用,因为hello不返回任何内容,并且会导致编译错误。


As for the (int (*)(void*,void*)) part, it's a simple type-cast.至于(int (*)(void*,void*))部分,它是一个简单的类型转换。

As for answering your questions 1. and 2. I think you may benefit from reading about the spiral rule:至于回答你的问题 1. 和 2. 我认为你可能会从阅读螺旋规则中受益:

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

It can be helpful for translating seemingly complicated C statements, like function pointers, into plain English:它有助于将看似复杂的 C 语句(如函数指针)翻译成简单的英语:

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

'qsort' is a function taking four parameters, returning void 'qsort' 是一个带四个参数的函数,返回 void

parameter 0 - lineptr - an array of void pointers.参数 0 - lineptr - 一个空指针数组。

parameter 1 - left - an int.参数 1 - left - 一个整数。

parameter 2 - right - an int.参数 2 - right - 一个整数。

parameter 3 - comp - a pointer to a function that takes two arguments, each of which a void pointer, and returns an int.参数 3 - comp - 一个指向函数的指针,该函数带有两个参数,每个参数都是一个 void 指针,并返回一个 int。

Then in your call to 'qsort':然后在您对“qsort”的调用中:

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

You provide exactly these necessary arguments, more specifically, let's look at the third argument:您提供了这些必要的参数,更具体地说,让我们看看第三个参数:

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

The final bracket evaluates to 'numcmp' or 'stcmp'.最后一个括号计算为 'numcmp' 或 'stcmp'。 In either case this is a function returning an int, with the only difference being the data type of the arguments passed in. Without loss of generality, let's choose 'numcmp'.在任何一种情况下,这都是一个返回 int 的函数,唯一的区别是传入参数的数据类型。不失一般性,让我们选择 'numcmp'。

So then we have:那么我们有:

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

What we have on the left hand side of 'numcmp' is then a cast, which takes care of the difference in the data types of the arguments between the functions 'numcmp' and 'strcmp'.我们在 'numcmp' 的左侧是一个强制转换,它负责处理函数 'numcmp' 和 'strcmp' 之间参数数据类型的差异。 In K&R2 it actually explains this:在 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." “函数参数的精心转换会转换比较函数的参数。这些通常不会对实际表示产生影响,但可以向编译器保证一切正常。”

Furthermore, 'stcmp' and 'numcmp' are addresses of functions and, since they are known to be functions, the & operator is not necessary.此外,'stcmp' 和 'numcmp' 是函数的地址,因为它们是函数,所以 & 运算符不是必需的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM