Function pointers are a lot like regular pointers. They differ in that they point to executable instructions instead of data. A function pointer should specify the signature of the function.
We can declare a function pointer by:
uint8_t (*min)(uint8_t, uint8_t);
We can assign a function pointer to point to an actual function by:
uint8_t minimum(uint8_t num1, uint8_t num2) { return num1 < num2 ? num1 : num2; } min = &minimum;
Now that the function pointer has been assigned, we can use it to call minimum
using either of the following ways:
uint8_t answer = min(3, 8); uint8_t answer = (*min)(3, 8);
The second line more accurately describes the operation; however, the first method is also legal (and means the same thing).
If you ever needed to pass a function pointer, and you didn't know how to do it, the following example would probably get you on the right track:
/** * Determines the smaller of the two arguments * @param num1 first number * @param num2 second number * @return The smaller of the two arguments, or either one if they are equal */ uint8_t minimum(uint8_t num1, uint8_t num2); /** * Applies the specified operation to elements in the passed array. * @param operation Operation to be performed on the data in the array * @param data Array of data to be processed * @param length Number of elements in the array * @return Result of applying the operation to all of the elements in the array */ uint16_t processArray(uint8_t (*operation)(uint8_t, uint8_t), uint8_t *data, uint8_t length); int main() { uint8_t nums[] = {4, 3, 8, 7, 13}; uint16_t result = processArray(&minimum, nums, 5); } uint16_t processArray(uint8_t *data, uint8_t length, uint8_t (*operation)(uint8_t, uint8_t)) { uint16_t answer = data[0]; uint8_t i=1; while(i<length) { answer = operation(answer, data[i]); } return answer; }
Suppose I had a few other functions that accepted two uint8_t
arguments and returned a uint8_t
value. Say,
maximum
— returns the maximum of two numbers.add
— returns the sum of two numbers.multiply
— returns the product of two numbers.
Then I could use the same processArray
function to produce completely different results. Observer causually (because it's that easy):
/** * Determines the smaller of the two arguments * @param num1 first number * @param num2 second number * @return The smaller of the two arguments, or either one if they are equal */ uint8_t minimum(uint8_t num1, uint8_t num2); /** * Determines the larger of the two arguments * @param num1 first number * @param num2 second number * @return The larger of the two arguments, or either one if they are equal */ uint8_t maximum(uint8_t num1, uint8_t num2); /** * Determines the sum of the two arguments * @param num1 first number * @param num2 second number * @return The sum of the two arguments */ uint8_t add(uint8_t num1, uint8_t num2); /** * Determines the product of the two arguments * @param num1 first number * @param num2 second number * @return The product of the two arguments */ uint8_t multiply(uint8_t num1, uint8_t num2); /** * Applies the specified operation to elements in the passed array. * @param operation Operation to be performed on the data in the array * @param data Array of data to be processed * @param length Number of elements in the array * @return Result of applying the operation to all of the elements in the array */ uint16_t processArray(uint8_t (*operation)(uint8_t, uint8_t), uint8_t *data, uint8_t length); int main() { uint8_t nums[] = {4, 3, 8, 7, 13}; uint16_t min = processArray(&minimum, nums, 5); uint16_t max = processArray(&maximum, nums, 5); uint16_t sum = processArray(&add, nums, 5); uint16_t product = processArray(&multiply, nums, 5); } uint8_t maximum(uint8_t num1, uint8_t num2) { return num1 > num2 ? num1 : num2; } uint8_t add(uint8_t num1, uint8_t num2) { return num1 + num2; } uint8_t multiply(uint8_t num1, uint8_t num2) { return num1 * num2; }