简体   繁体   中英

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. 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. 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)?

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?

Can someone clarify my doubts.

When you call qsort you only pass a pointer to the function , you do not call the function itself. 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).

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.

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 . This will of course not work, as hello doesn't return anything, and would lead to a compilation error.


As for the (int (*)(void*,void*)) part, it's a simple type-cast.

As for answering your questions 1. and 2. I think you may benefit from reading about the spiral rule:

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

It can be helpful for translating seemingly complicated C statements, like function pointers, into plain English:

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

'qsort' is a function taking four parameters, returning void

parameter 0 - lineptr - an array of void pointers.

parameter 1 - left - an int.

parameter 2 - right - an int.

parameter 3 - comp - a pointer to a function that takes two arguments, each of which a void pointer, and returns an int.

Then in your call to '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'. 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'.

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'. In K&R2 it actually explains this:

"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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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