简体   繁体   中英

Trying to understand function pointers in C

I am trying to understand function pointers and am stuggling. I have seen the sorting example in K&R and a few other similar examples. My main problem is with what the computer is actually doing. I created a very simple program to try to see the basics. Please see the following:

#include <stdio.h>

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23,(int(*)(void*,void*))(i==1?func0:func1));//34 and 23 are arbitrary inputs



}

void myfunc(int x, int y, int(*somefunc)(void *, void *)){

    int *xx =&x;
    int *yy=&y;

    printf("%i",somefunc(xx,yy));


}

int func0(int *x, int *y){

    return (*x)*(*y);

}

int func1(int *x, int *y){

    return *x+*y;
} 

The program either multiplies or adds two numbers depending on some variable (i in the main function - should probably be an argument in the main). fun0 multiplies two ints and func1 adds them.

I know that this example is simple but how is passing a function pointer preferrable to putting a conditional inside the function myfunc? ie in myfunc have the following:

if(i == 1)printf("%i",func0(xx,yy));

else printf("%i",func1(xx,yy));

If I did this the result would be the same but without the use of function pointers.

Your understanding of how function pointers work is just fine. What you're not seeing is how a software system will benefit from using function pointers. They become important when working with components that are not aware of the others.

qsort() is a good example. qsort will let you sort any array and is not actually aware of what makes up the array. So if you have an array of structs, or more likely pointers to structs, you would have to provide a function that could compare the structs.

struct foo {
  char * name;
  int magnitude;
  int something;
};

int cmp_foo(const void *_p1, const void *_p2)
{
  p1 = (struct foo*)_p1;
  p2 = (struct foo*)_p2;

  return p1->magnitude - p2->magnitude;
}

struct foo ** foos;
// init 10 foo structures...

qsort(foos, 10, sizeof(foo *), cmp_foo);

Then the foos array will be sorted based on the magnitude field.

As you can see, this allows you to use qsort for any type -- you only have to provide the comparison function.

Another common usage of function pointers are callbacks, for example in GUI programming. If you want a function to be called when a button is clicked, you would provide a function pointer to the GUI library when setting up the button.

how is passing a function pointer preferrable to putting a conditional inside the function myfunc

Sometimes it is impossible to put a condition there: for example, if you are writing a sorting algorithm, and you do not know what you are sorting ahead of time, you simply cannot put a conditional; function pointer lets you "plug in" a piece of computation into the main algorithm without jumping through hoops.

As far as how the mechanism works, the idea is simple: all your compiled code is located in the program memory, and the CPU executes it starting at a certain address. There are instructions to make CPU jump between addresses, remember the current address and jump, recall the address of a prior jump and go back to it, and so on. When you call a function, one of the things the CPU needs to know is its address in the program memory. The name of the function represents that address. You can supply that address directly, or you can assign it to a pointer for indirect access. This is similar to accessing values through a pointer, except in this case you access the code indirectly, instead of accessing the data.

First of all, you can never typecast a function pointer into a function pointer of a different type. That is undefined behavior in C (C11 6.5.2.2).

A very important advise when dealing with function pointers is to always use typedefs.

So, your code could/should be rewritten as:

typedef int (*func_t)(int*, int*);

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23, (i==1?func0:func1)); //34 and 23 are arbitrary inputs
}

void myfunc(int x, int y, func_t func){

To answer the question, you want to use function pointers as parameters when you don't know the nature of the function. This is common when writing generic algorithms.

Take the standard C function bsearch() as an example:

void *bsearch (const void *key, 
               const void *base,
               size_t nmemb, 
               size_t size,
               int (*compar)(const void *, const void *));
              );

This is a generic binary search algorithm, searching through any form of one-dimensional arrray, containing unknown types of data, such as user-defined types. Here, the "compar" function is comparing two objects of unknown nature for equality, returning a number to indicate this.

"The function shall return an integer less than, equal to, or greater than zero if the key object is considered, respectively, to be less than, to match, or to be greater than the array element."

The function is written by the caller, who knows the nature of the data. In computer science, this is called a "function object" or sometimes "functor". It is commonly encountered in object-oriented design.

An example (pseudo code):

typedef struct  // some user-defined type
{
  int* ptr;
  int  x;
  int  y;
} Something_t;

int compare_Something_t (const void* p1, const void* p2)
{
  const Something_t* s1 = (const Something_t*)p1;
  const Something_t* s2 = (const Something_t*)p2;

  return s1->y - s2->y;  // some user-defined comparison relevant to the object
}

...

Something_t  search_key = { ... };
Something_t  array[] = { ... };
Something_t* result; 

result = bsearch(&search_key,
                 array,
                 sizeof(array) / sizeof(Something_t), // number of objects
                 sizeof(Something_t), // size of one object
                 compare_Something_t // function object
                );

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