Array of function pointers
The function pointer:
In C, we can have pointers to functions. The following is a simple example showing declaration and function call using the function pointer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21void fun(int a){
printf("Value of a is %d\n",a);
}
int main(){
//fun_ptr is a pointer to fun
void (*fun_ptr)(int) = &fun;
//Invoking fun() by fun_ptr
int x = 1;
(*fun_ptr)(x);
/*
**The function's name can be used to get function's address without &
**the pointer's name can also be used to invoke the function without *
*/
void (*fun_ptr2)(int) = fun ;//also works
fun_ptr2(10);
return 0;
}Output:
1
2Value of a is 1
Value of a is 10
- It is easy to understand a function pointer is a pointer that holds the start address of the specific function executable code.
A function pointer can be passed to another function as a parameter,can be returned from a function or can be stored in an array of function pointers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// A simple c program to show function pointers as a parameter and can be returned
#include<stdio.h>
void foo1(){printf("foo1\n");}
void foo2(){printf("foo2\n");}
void fun1(void (*foo)()){
foo();
}
/*
**fun2 is a function, void (*)() is the type of return value and void(*foo)() is a
**function pointer as a parameter.
*/
void (*fun2(void(*foo)()))(){ return foo;}
//In Unix, signal function is a tradition example
void (*signal (int signo, void (*func)(int))) (int);Advantage:
This pointer is very useful to avoid code redundancy. When we use a function like
qsort()
in C, what we need is a compare function and pass the pointer of it toqsort()
.1
2
3
4
5
6
7
8
9
10
11
12#include<stdio.h>
#include<stdlib.h>
int compare(const void *a, const void *b){
return (*(int*)a - *(int*)b );
}
int main(){
int array[] = {11,2,3,5,15};
int n = sizeof(array)/sizeof(array[0]);
qsort(array[],n,sizeof(int),compare);
return 0;
}Programmers want the OS execute their own handle function when the system handles a specified event. Usually, we can implement a handle function (CallBack function), giving system a pointer of the function for the specific handing.
1
2
3
4
5typedef void (*event_handler)(unsigned int para1,unsigned int para2);
struct event{
unsigned int event_id;
event_handler handler;// a function pointer
};Disadvantage:
- When the function type is more complicated, the more difficulty we may face without using
#define
ortypedef
.
- When the function type is more complicated, the more difficulty we may face without using
Array of function pointers
(*foo[])()
is an array holding function pointers, for easy access to each function which is pointed to by some function pointers.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <stdio.h>
void add(int a, int b){
printf("Addition is %d\n", a+b);
}
void subtract(int a, int b){
printf("Subtraction is %d\n", a-b);
}
void multiply(int a, int b){
printf("Multiplication is %d\n", a*b);
}
int main(){
// fun_ptr_arr is an array of function pointers
void (*fun_ptr_arr[])(int, int) = {add, subtract, multiply};
unsigned int ch, a = 15, b = 10;
printf("Enter Choice: 0 for add, 1 for subtract and 2 "
"for multiply\n");
scanf("%d", &ch);
if (ch > 2) return 0;
(*fun_ptr_arr[ch])(a, b);
return 0;
}Many C compiler will attempt to convert switch statement into a jump table, which also called branch table. Jump Table is an efficient means of handling similar events in software like event handling or delegate, which is a typical example of array of function pointers.
1
2
3
4
5
6void (*pf[])(void) = {fun1,fun2,fun3,...,funn};
void test(const int jump_index){
if(jump_index<sizeof(pf)/sizeof(*pf))
pf[jump_index]();
}Advantage:
Easy for maintenance. If we want to change specific behavior of a event, which has its own default function, we can just modify customer function used for the event
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//FUN is a pointer to the function with type void (*)()
typedef void (*FUN)();
enum EVENT_TYPE{
EVENT_TYPE_1=0,
EVENT_TYPE_2,
EVENT_TYPE_3,
EVENT_TYPE_END
};
//According different events, we just modify the eFunMap for easy maintenance
EVENT_FUN_MAP eFunMap[EVENT_TYPE_END] = {
eventFun1,
eventFun2,
eventFun3
};
void doAction(EVENT_TYPE eventType)
{
(eFunMap[eventType].pFun)();
}Dynamic override. In Unix, when we handle signals, we often use arrays of function pointers. Also, in some event handling, we often use it to replace default function dynamic.
1
2
3
4
5
6
7
8
9
10void doAction(EVENT_TYPE eventType)
{
(eFunMap[eventType].pFun)();
}
void reloadEventFun(EVENT_TYPE eventType)
{
eFunMap[eventType].pFun = &MyEventFun1;
//*(eFunMap[eventType].pFun) = MyEventFun1; also works
}
Conclusion
The array of function pointers is used so universally, like delegate in c# or java, sort()
in Python, event handling in C or C++ and nearly everywhere in Unix kernel, that it is significant to use it expertly and comprehendingly.
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!