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)();
- We're defining a pointer to a function, named greet_ptr.
- We're using the * notation to signify that it is a pointer.
- The function pointed to, should receive no argument: ()
- The function should return nothing: void.
- 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();
greet_ptr
is a pointer, so it should receive the address of a function.greet
is a function, taking no argument, and returning void.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 *);
- We're defining a pointer to a function, named greet_ptr
- We're using the * notation to signify that it is a pointer.
- The function pointed to, should take one argument of type char pointer (char *).
- The function pointed to, should return nothing: void.
- 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");
- greet_ptr still points to greet function.
- let's execute the code living at the address stored by greet_ptr.
- This executable,
greet
is waiting for a parameter of typechar *
. - So the parameter
"foo"
will be passed to the functiongreet
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);
}
- We're defining a function, named
greet
. - The
greet
function takes 2 arguments:- a function pointer:
void (*fctPtr)(char *)
- a char pointer:
char *name
- a function pointer:
- The function pointed to, should be called with an argument of type
char *
- The function pointed to is then called:
fctPtr(name)
The next interesting line is:
greet(sayHello, "foo");
sayHello
is a function name (label)- that will be converted to a pointer to itself.
- then, that pointer will be passed to
greet
function.
- 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.