函数指针就是指向函数的指针,其值就是函数体的首地址。在底层,函数名就代表函数的首地址,所以把函数名直接指派给一个同类型的函数指针而不需要&运算符,可以直接用函数名注册回调函数
调用的方式1 2 3 4 5 size_t (*pf)(const char *) = &strlen ;int len = strlen ("hehe" );len = (*pf)("hehe" ); len = pf("hehe" );
第一句简单地使用名字strlen直接调用函数,实际上执行过程是函数名strlen首先被转换成一个函数指针,该指针指向内存中函数的位置,然后函数调用操作符调用该函数,执行开始于这个地址的代码 第二句对pf执行间接访问操作,它把函数指针转换为一个函数名。这个转换并不真正需要,编译器在执行函数调用操作符之前又会把它转换回去 第三句和直接通过函数指针访问,这三句在效果上都是一样的
两段有意思的代码1 2 3 4 5 (*(void (*)())0 )(); void (*signal(int , void (*)(int )))(int );
首先代码一(*(void(*)())0)()
把(void(*)())0
单独拿出来这是将int类型的0强转成void(*)()函数指针类型,然后在解引用,最后对函数指针解引用后调用 用typedef简化:typedef void(*pFuc)();
(*(pFuc)0)(); // 代码一等价于这个形式
再来看看代码二void(*signal(int, void(*)(int)))(int);
把signal(int, void(*)(int))
单独拿出来,发现这是一个函数名为signal,形参为一个int类型和一个void(*)(int)的函数指针类型,外面的一层void(* )(int)是修饰其返回值类型的 用typedef简化:typedef int(*pFuc)(int);
pfuc signal(int, pFuc);
应用场景 回调函数函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数 这里给出一段改进版的冒泡排序,可以做到一份代码同时实现升序和降序两种功能:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 typedef int (*Comp) (int , int ) ;void Swap (int * a, int * b) { int t = *a; *a = *b; *b = t; } int Greater (int a, int b) { return a > b; } int Less (int a, int b) { return a < b; } void BubbleSort (int * arr, int size , Comp p) { for (int i = 0 ; i < size ; ++i) { for (int j = 0 ; j < size - 1 - i; ++j) { if (p(arr[j + 1 ], arr[j])) { Swap(&arr[j], &arr[j + 1 ]); } } } } int main () { int a[5 ] = { 1999 , 723 , 1007 , 2019 , 1212 }; BubbleSort(a, 5 , Greater); for (int i = 0 ; i < 5 ; ++i) { printf ("%d " , a[i]); } putchar ('\n' ); BubbleSort(a, 5 , Less); for (int i = 0 ; i < 5 ; ++i) { printf ("%d " , a[i]); } putchar ('\n' ); return 0 ; }
转移表转移表就是一个函数指针数组,可以降低函数的圈复杂度
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 26 27 28 29 30 31 32 33 34 35 36 int Add (int a, int b) { return a + b; } int Sub (int a, int b) { return a - b; } int Mul (int a, int b) { return a * b; } int Div (int a, int b) { return a / b; } int Menu () { int input; printf ("=======================\n" ); printf ("1.Add 2.Sub 3.Mul 4.Div\n" ); printf ("=======================\n" ); printf ("输入选择:" ); scanf ("%d" , &input); return input; } int main () { int x, y; typedef int (*pFuc) (int , int ) ; pFuc arr[5 ] = { 0 , Add, Sub, Mul, Div }; int choice = Menu(); printf ("输入操作数:" ); scanf ("%d %d" , &x, &y); printf ("结果为%d\n" , arr[choice](x, y)); return 0 ; }