在C语言中,就像普通的数据指针(int *,char *等)一样,我们可以具有指向函数的指针。以下是一个简单的示例,显示了使用函数指针进行的声明和函数调用。
#include
// 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
在上面的示例中,为什么在函数指针(例如fun_ptr)周围需要一个额外的括号?
如果删除括号,则表达式“ void(* fun_ptr)(int)”变为“ void * fun_ptr(int)”,这是一个返回空指针的函数的声明。有关详细信息,请参见以下帖子。
如何声明一个指向函数的指针?
以下是有关函数指针的一些有趣的事实。
1)与普通指针不同,函数指针指向代码,而不是数据。通常,函数指针存储可执行代码的开头。
2)与普通指针不同,我们不使用函数指针分配解除分配的内存。
3)函数名称也可以用来获取函数的地址。例如,在下面的程序中,我们在分配中删除了地址运算符’&’。我们还通过删除*更改了函数调用,该程序仍然有效。
#include
// 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()
{
void (*fun_ptr)(int) = fun; // & removed
fun_ptr(10); // * removed
return 0;
}
输出:
Value of a is 10
4)像普通指针一样,我们可以有一个函数指针数组。下面第5点的示例显示了指针数组的语法。
5)可以使用函数指针代替开关盒。例如,在下面的程序中,要求用户在0和2之间进行选择以执行不同的任务。
#include
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;
}
Enter Choice: 0 for add, 1 for subtract and 2 for multiply
2
Multiplication is 150
6)像普通数据指针一样,函数指针可以作为参数传递,也可以从函数返回。
例如,考虑下面的C程序,其中wrapper()接收一个void fun()作为参数并调用传递的函数。
// A simple C program to show function pointers as parameter
#include
// 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;
}
这一点在C语言中特别有用。在C语言中,我们可以使用函数指针来避免代码冗余。例如,简单的qsort()函数可用于按升序或降序对数组进行排序,或者在结构数组的情况下按任何其他顺序对数组进行排序。不仅如此,借助函数指针和void指针,还可以将qsort用于任何数据类型。
// An example for qsort and comparator
#include
#include
// 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
输出:
5 10 12 15 80 90
与qsort()类似,我们可以编写自己的函数,这些函数可用于任何数据类型,并且可以执行不同的任务而无需代码冗余。以下是可用于任何数据类型的示例搜索函数。实际上,我们可以使用此搜索函数通过编写自定义的比较函数来查找接近阈值的元素(低于阈值)。
#include
#include
// A compare function that is used for searching an integer
// array
bool compare (const void * a, const void * b)
{
return ( *(int*)a == *(int*)b );
}
// General purpose search() function that can be used
// for searching an element *x in an array arr[] of
// arr_size. Note that void pointers are used so that
// the function can be called by passing a pointer of
// any type. ele_size is size of an array element
int search(void *arr, int arr_size, int ele_size, void *x,
bool compare (const void * , const void *))
{
// Since char takes one byte, we can use char pointer
// for any type/ To get pointer arithmetic correct,
// we need to multiply index with size of an array
// element ele_size
char *ptr = (char *)arr;
int i;
for (i=0; i
输出:
Returned index is 2
通过编写单独的自定义compare(),以上搜索函数可用于任何数据类型。
7) C++中许多面向对象的功能都是使用C中的函数指针实现的。例如,虚函数。类方法是使用函数指针实现的另一个示例。有关更多详细信息,请参阅本书。
相关文章: C和C++中的指针集合1(简介,算术和数组)
参考:
http://www.cs.cmu.edu/~ab/15-123S11/AnnotatedNotes/Lecture14.pdf
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-087-practical-programming-in-c-january-iap-2010/lecture-notes/MIT6_087IAP10_lec08.pdf
http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture14.pdf