Function pointers

In Python, we say, functions are first class citizen. This means, functions can be used like any other objects. They can be stored inside variables, they can be passed as argument to a function, they can be returned from a function. The following is a very basic example:

square = lambda x: x * x
cube = lambda x: x * x * x

operations = {1: square, 2: cube}
choice = int(input("Square (1) or Cube (2) ?: "))
value = int(input("Value ?: "))

print(operations[choice](value))

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: ()
  4. The function should return nothing: void.
  5. We need parenthesis, otherwise it becomes void *greet_ptr(), a function returning a void pointer.

The next 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.
  5. We need parenthesis, otherwise it becomes void *greet_ptr(char *), a function taking a string and returning a void pointer.

The next interesting lines are:

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; // notice, there is no &

  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. Example:

#include<stdio.h>

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

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

// a function that takes a function and a string as parameters
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 next 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.


The original Python example in C?

#include<stdio.h>

int square (int x) {
  return x * x;
}

int cube (int x) {
  return x * x * x;
}


int main () {
  int choice, value;
  // an array of pointers to functions
  // those functions should take an int and return an int
  int (*fp[2])(int) = {square, cube};
  printf("Square (1) or Cube (2) ?: ");
  scanf("%d", &choice);

  printf("Value ?: ");
  scanf("%d", &value);

  printf("%d\n", (*fp[choice-1])(value));

  return 0;
}

Any real life examples?

Function pointers gives C programmers, first-class citizen functionality: being able to pass functions as argument to other functions, and being able to return functions as value from other functions.


More on the topic: