Function Pointers
===
# What are Function Pointers
Function pointers are **references** to memory addresses of functions.
* It's ++still a pointer++. So it's **4-bytes** large (on a 32-bit machine) and stores a **memory address** (some hex value).
* When compiled, the instructions for how to execute a function is stored in a certain area of memory.
* A **function pointer** stores the **value** of the memory address of the **start** of where the instructions for a function is stored.
# Declaring with Typedefs
### How to declare without typedefs
Remember when you declare a pointer, you have to specify the type of data object you are pointing to.
```C
int *pointer;
char *string;
data_type *name; // read as "name" is a pointer to "data_type"
```
So if you want to declare a function pointer, you have to specify the ++type of function++ your pointer is pointing to. So something like:
```C
type_of_function *my_func_pointer;
```
So what is the type of a function? Remember how if you want to define a function below where you use it in `main`, you have to stick a **function prototype** above `main`? This is so that the compiler knows the ++type++ of a function when it comes across its name in `main`. If you don't have this function prototype and stick the line `int num = foo(3)` in your code, your compiler is going to stare at this `foo` and complain because it doesn't know what `foo` is. So we know that to make the compiler happy, we have to include the **return type** and **argument types** in the function prototype, as well as the **name** of the function this `(return type, argument type)` pair is associated with.
```C
int foo(int num);
void foo2(int, int, char*); // don't have to specify names of arguments, just need types
// general form
return_type name_of_function(arg_1_type, arg_2_type, ...);
```
With this in mind, we are ready to declare a function pointer!
```C
int (*fp)(int); // fp is a pointer to a function that takes an int as an argument and returns an int
// general form
return_type (*name_of_func)(arg_1_type, arg_2_type);
```
### Motivation for typedefs
That's not too bad... It kind of just looks like a function prototype with a `*` in front of the function name to signal that this is a pointer. So **why do we usually typedef a function pointer**? Well, things can start to get a bit messy if we want to declare ++lots of functions pointers++ of the same type.
```C
int (*fp)(int);
int (*otherFunc)(int);
int (*funcA)(int);
int (*funcE)(int);
int (*longWindedName)(int);
```
Can you see how this is a little bit hard to read? To really drive the point home, consider this function **prototype** of a `signal()` function.
```C
void (*signal(int, void(*)(int)))(int);
```
How long does it take you to figure out what this line of code is doing?
* `signal` is a pointer to a function
* arguments = `int`, function pointer to a function that has an `int` arg and a `void` return value
* return values = a function pointer to a function that has an `int` arg and a `void` return value
If we `typedef`ed some of the confusing parts, it would be a lot more readable
```C
// SignalHandler is a function that take in an integer argument called signum and returns void
typedef void (*SignalHandler)(int signum);
// the signal prototype is now
SignalHandler signal(int signum, SignalHandler handler);
```
Benefits of introducing this typedef
* the `void(*)(int)` that we saw two of now make a lot more sense as we gave it a ++meaningful name++
* there isn't a mess of parentheses and I can decode what's going on pretty quickly
So what would its function pointer look like now?
```C
typedef SignalHandler (*signal_pointer)(int, SignalHandler);
signal_pointer my_signal = &signal;
// my_signal is a pointer to a function of type signal, and it is
// assigned the memory address of a function signal defined elsewhere in the file
```
Now everything is a lot more **readable**. Also, clarity helps to **reduce the chance of bugs**. **Code complexity** is the bane of every programmer's existence as it is exactly how bugs are introduced. The simpler your code, the better. `typedef` is the tool we use to do that here.
### This typedef syntax looks weird
Before, when we `typedef`ed something, it kind of looked like this
```C
typedef struct node Node;
```
We knew that the right-most "thing" is the name of our new alias, and everything else is the original object that we mean when we say `Node`.
Function pointer typedefs are a bit different since you have to specify a ++pair++ of types, a `return type` and `argument types`. So the **name** is actually squashed ==**between**== these two.
```C
typedef int (*somefunc_type)(int, int);
// general form
typedef return_type (*function_type_name)(arg1_type, arg2_type, ...);
```
So if we want to declare `fp` as a pointer to a function of type `return_type` and (`arg1_type`, `arg2_type`, ...), we say `fp` is of type `function_type_name`.
```C
somefunc_type fp = &foo; // fp is a pointer to the foo function
```
So just remember that the syntax is a little bit funny since we are using a `typedef` to encompass **more than one type**.
# Why do I care about function pointers?
Sometimes we have a function that is super useful and that we might want to use on a whole bunch of data types. But as we know, functions in `C` require explicit data types for its return and arguments. I don't want to write 10 diff functions for the different `structs` and data types I want to use this function with. I want to make it **generic**.
Some other languages (i.e. Java) have built-in support for generic types, but `C` does not. So we have to use **pointers** to try and introduce some of this ++generic functionality++. (Just remember, in `C`, everything is a pointer...)
# TL;DR
Function pointers are useful for plugging in functions into functions. Declare them with typedefs to make things more readable. We don't deal with anything *too* complicated in COMP2521, but we're teaching you good practices for crazy `signal()` functions you may see in the future.
```C
// typedef the pointer type
typedef int (*t_some_func)(int, int);
// declare a function pointer called afunc
t_somefunc afunc = &product;
// use your function pointer
int x2 = (*afunc)(123, 456); // older syntax
// this is the same as
int x2 = afunc(123, 456); // newer syntax
```
Yes, the `typedef` looks a bit weird because you are linking more than one data type to a name (`t_some_func`). Be careful with your typedefs.
# References
* [Ashesh's Generic ADTs in C Notes](https://webcms3.cse.unsw.edu.au/static/uploads/course/COMP2521/17s2/07093d2c4bbd2e92b94adb285fdc2368612144e074121a5adf685b7ffd26b6db/GenericADT-17s2.pdf)
* [Motivation for Typedef Function Pointer StackOverflow](https://stackoverflow.com/questions/4295432/typedef-function-pointer)
* [Signal Example of Typedef Function Pointer StackOverflow](https://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c)