Let’s start with a very simple function to print out a simple "hello world" using a function pointer:

#include<stdio.h>

// defining a function ptr
void (*greet_ptr)();

// a function taking no argument and returning nothing
void greet(){
  printf("Hello world!\n\n");
}

int main(){
  // make our function pointer points to greet function
  greet_ptr = &greet;

  // call greet function via the function pointer
  greet_ptr();

  return 0;
}


Slowly please?

The first interesting line is:

void (*greet_ptr)();
  1. We're defining a pointer to a function, named greet_ptr.
  2. We're using the * notation to signify that it is a pointer.
  3. The function pointed to, should receive no argument () and return nothing void.
  4. We need parenthesis, otherwise it becomes void *greet_ptr(), a void pointer.


The second interesting lines are:

greet_ptr = &greet;
greet_ptr();
  1. greet_ptr is a pointer, so it should receive the address of a function.
  2. greet is a function, taking no argument, and returning void.
  3. greet_ptr(): let's execute the code living at the address stored by greet_ptr.



What if the function pointed to, takes arguments?

Simple example:

#include<stdio.h>

// defining a function ptr
void (*greet_ptr)(char *);

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

int main(){
  // make our function pointer points to greet function
  greet_ptr = &greet;

  // call greet function via the function pointer
  greet_ptr("foo");

  return 0;
}


The first interesting line is:

void (*greet_ptr)(char *);
  1. We're defining a pointer to a function, named greet_ptr.
  2. We're using the * notation to signify that it is a pointer.
  3. The function pointed to, should take one argument of type char pointer (char *).
  4. The function pointed to, should return nothing: void.


In this case, the second interesting line is:

greet_ptr = &greet;
greet_ptr("foo");
  1. greet_ptr still points to greet function.
  2. let's execute the code living at the address stored by greet_ptr.
  3. This executable, greet is waiting for a parameter of type char *.
  4. So the parameter "foo" will be passed to the function greet before execution.



What is the address of a function?

Before going further, we have to keep one thing in mind. a function name (label) is the address of the function. Yes. A function name (label) is converted to a pointer to itself. This means that function names can be assigned to a function pointer without using & to pass an address. Example:

#include<stdio.h>

void (*greet_ptr)(char *);
void (*hello_ptr)(char *);

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

int main(){
  greet_ptr = &greet;
  hello_ptr = greet;

  if(greet_ptr == hello_ptr)
    printf("Pointers containing the same address.\n");

  greet_ptr("foo");
  hello_ptr("foo");

  return 0;
}



Function pointers as arguments?

Remember, a function name (label) is converted to a pointer to itself, so it can be passed whenever we need a function pointer. So, we can write function taking function pointers as arguments. It's simpler to understand with an example:

#include<stdio.h>

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

void sayHi(char *name){
  printf("Hey %s!\n\n", name);
}

void greet(void (*fctPtr)(char *), char *name) {
  fctPtr(name);
}

void greetBar(){
  greet(sayHello, "bar");
}

int main(){
  greet(sayHello, "foo");
  greet(sayHi, "baz");
  greetBar();

  return 0;
}


The first interesting lines are:

void greet(void (*fctPtr)(char *), char *name) {
  fctPtr(name);
}
  1. We're defining a function, named greet.
  2. The greet function takes 2 arguments:
    1. a function pointer: void (*fctPtr)(char *)
    2. a char pointer: char *name
  3. The function pointed to, should be called with an argument of type char *
  4. The function pointed to is then called: fctPtr(name)


The second interesting line is:

greet(sayHello, "foo");
  1. sayHello is a function name (label)
    1. that will be converted to a pointer to itself.
    2. then, that pointer will be passed to greet function.
  2. The function sayHello will be called with "foo" as parameter.


We can also use function pointers as return values.

We already know a pointer can be returned from a function. A function pointer, is a pointer, so there is no big deal here. Is there?


Any real life examples?

Yes. Basically, function pointers gives C programmers, a pseudo first-class functionality: being able to pass functions as argument to other functions, and being able to return functions as value from other functions. If you can share your experience using function pointers, that would be nice.



More on the topic: