In the first part of this series, we covered the basics of pointers in C, and went on to more complex arrangements and pointer arithmetic in the second part. Both times, we focused solely on pointers representing data in memory.
But data isn’t the only thing residing in memory. All the program code is accessible through either the RAM or some other executable type of memory, giving each function a specific address inside that memory as entry point. Once again, pointers are simply memory addresses, and to fully utilize this similarity, C provides the concept of function pointers. Function pointers provide us with ways to make conditional code execution faster, implement callbacks to make code more modular, and even provide a foothold into the running machine code itself for reverse engineering or exploitation. So read on!
In general, function pointers aren’t any more mysterious than data pointers: the main difference is that one references variables and the other references functions. If you recall from last time how arrays decay into pointers to their first element, a function equally decays into a pointer to the address of its entry point, with the
() operator executing whatever is at that address. As a result, we can declare a function pointer variable
fptr and assign a function
func() to it:
fptr = func;. Calling
fptr(); will then resolve to the entry point of function
func() and execute it.
Admittedly, the idea of turning a function into a variable may seem strange at first and might require some getting used to, but it gets easier with time and it can be a very useful idiom. The same is true for the function pointer syntax, which can be intimidating and confusing in the beginning. But let’s have a look at that ourselves.