Why use function pointers?
需要说明的是void*类型的指针不能解引用,否则会报错: error: 'const void*' is not a pointer-to-object type
- Efficiency
- Elegance
- Runtime binding
Determine sorting function based on type of data at run time
Eg: insertion sort for smaller data sets (n <100)
Eg: Quicksort for large data sets ( n > 100000)
Other sorting algorithms based on type of data set
函数指针是一种指向函数的指针。要点:1、本质还是指针,进行地址操作;2、其指向对象是函数。
简单例子来说明函数指针如何工作的:
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
/* The above line is equivalent of following two
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
// Invoking fun() using fun_ptr
(*fun_ptr)(10);
return 0;
}
输出
Value of a is 10
定义函数指针
函数返回类型 (* 函数指针名称) (函数形参列表);
注意:
- (* 函数指针名称) 必须要有这个括号,否则上面语句就变成了函数声明。
- 在赋值或初始化时,函数指针的函数返回类型和函数形参列表必须与函数的相应部分完全一样,否则会编译出错。
之所以能够使用指针指向一个函数并且调用该函数是基于以下几个事实:
- 函数代码是保存在程序的代码段的(.text),自然在内存中也占有一定的内存区域,通过函数名调用函数也是将该函数的首地址传给程序计数器(%rip)。
- 通过定义一个函数指针,并将要调用的函数地址赋值给该指针,就可以通过这个指针调用相应的函数。
函数指针与普通指针的不同之处在于:
- a function pointer points to code, not data. Typically a function pointer stores the start of executable code.
- we do not allocate de-allocate memory using function pointers.
由于函数名也可以用作获取函数的地址,所以在上例的赋值操作中可以去掉"&",在使用指针函数时也可以直接用指针名称调用函数,去掉"*":
void (*fun_ptr)(int) = fun; // & removed
fun_ptr(10); // * removed
象普通指针一样,我们也可以定义
函数指针数组,下面的例子展示了使用函数指针数组取代switch语句的一种用法:
#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;
}
既然普通指针可以作为参数传递给函数以及从函数中返回,那么函数指针也一样可以:
// A simple C program to show function pointers as parameter
#include <stdio.h>
// Two simple functions
void fun1() { printf("Fun1\n"); }
void fun2() { printf("Fun2\n"); }
// A function that receives a simple function
// as parameter and calls the function
void wrapper(void (*fun)())
{
fun();
}
int main()
{
wrapper(fun1);
wrapper(fun2);
return 0;
}
当一个函数指针非常复杂(比如有很多形参等)时,可以用typedef来使代码变得更简单。
typedef的功能是定义新的类型。
typedef void (*fun) ();//定义了一个新类型:fun
void wrapper(fun f){
f();//用函数指针调用函数必须加上形参列表,此处为空
}
这是非常有用的,在一些情况下它可以避免冗余。
实际应用举例
使用qsort()函数排序
// An example for qsort and comparator
#include <stdio.h>
#include <stdlib.h>
// A sample comparator function that is used
// for sorting an integer array in ascending order.
// To sort any array for any other data type and/or
// criteria, all we need to do is write more compare
// functions. And we can use the same qsort()
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int main ()
{
int arr[] = {10, 5, 15, 12, 90, 80};
int n = sizeof(arr)/sizeof(arr[0]), i;
qsort (arr, n, sizeof(int), compare);
for (i=0; i<n; i++)
printf ("%d ", arr[i]);
return 0;
}
需要说明的是void*类型的指针不能解引用,否则会报错: error: 'const void*' is not a pointer-to-object type
必须将void*类型的指针转化为其他类型的指针以后再解引用,(int *)a就是把a转化为int型的指针,*(int*)a是对转化为int型指针a的解引用。