前言
在前一章中,我们深入探讨了指针的基础知识,包括字符指针、数组指针以及指针与数组传参的细节。本章我们将继续深入,探讨函数指针这一更为复杂但同样重要的主题。希望本章内容能够帮助初学者更好地理解指针的世界。
一、 函数指针
1.1、函数指针变量的创建
什么是函数指针变量?
在前面的学习中,我们已经了解了整型指针和数组指针的概念。类比这些知识,我们可以推断出:函数指针变量是用来存储函数地址的,通过这些地址可以调用相应的函数。
那么,函数是否有地址呢?让我们通过一段代码来验证:
void test() {
printf("hehe\n");
}
int main() {
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
输出结果:
0x10403b400
0x10403b400
确实打印出了地址,这表明函数是有地址的。函数名就是函数的地址,当然也可以通过 &函数名
的方式获得函数的地址。
如果我们要将函数的地址存储起来,就需要创建函数指针变量。函数指针变量的写法与数组指针非常类似。例如:
void test() {
printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)() = test;
int Add(int x, int y) {
return x + y;
}
int (*pf3)(int, int) = Add;
int (*pf3)(int x, int y) = &Add;
函数指针类型解析:
int (*pf3)(int x, int y);
int
:函数返回类型(*pf3)
:函数指针变量名(int x, int y)
:函数参数类型和个数
总结:不同于数组名,函数名和 &函数名
是同一个意思,因此 pf3
、*pf3
、Add
、&Add
都是同一个意思。
1.2、 函数指针变量的使用
通过函数指针调用指针指向的函数:
int Add(int x, int y) {
return x + y;
}
int main() {
int (*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(3, 3));
printf("%d\n", pf3(3, 6));
return 0;
}
输出结果:
6
9
1.3、 两段有趣的代码
出自《C陷阱和缺陷》这本书:
代码1:
(*(void (*)())0)();
分析:
(void (*)())
:将0
强制类型转换为一个返回类型为void
的无参函数指针。*(void (*)())0
:解引用0
,找到该函数指针指向的函数。(*(void (*)())0)()
:调用该函数。
代码1 实际上是函数的调用。
代码2:
void (*signal(int, void(*)(int)))(int);
分析:
signal
:函数名。(int, void(*)(int))
:函数的参数。void (*)(int)
:函数的返回类型。
代码2 是 signal
函数的声明。
1.4、typedef 关键字
typedef
用于类型重命名,可以将复杂的类型简化。例如:
typedef unsigned int uint;
typedef int* ptr_t;
typedef int(*parr_t)[5];
typedef void(*pfun_t)(int);
通过 typedef
,我们可以简化代码2:
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
二、 函数指针数组
数组是存放相同类型数据的存储空间。我们已经学习了指针数组,例如:
int *arr[10];
如果要将函数的地址存放到一个数组中,这个数组就称为函数指针数组。函数指针数组的定义如下:
int (*parr1[3])();
parr1
先与 []
结合,说明 parr1
是一个数组,数组的内容是 int (*)()
类型的函数指针。
三、 函数指针的使用
函数指针数组的用途之一是实现转移表。例如,计算器的一般实现:
#include <stdio.h>
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 main() {
int x, y;
int input = 1;
int ret = 0;
int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; // 转移表
do {
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1)) {
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);
printf("ret = %d\n", ret);
} else if (input == 0) {
printf("退出计算器\n");
} else {
printf("输入有误\n");
}
} while (input);
return 0;
}
总结
函数指针是C语言中一个强大且复杂的工具,能够帮助我们更灵活地管理和调用函数。通过本章的学习,希望大家能够掌握函数指针的基本概念和使用方法,为后续更深入的学习打下坚实的基础。下一篇,我们将探讨指针的另一个重要应用,希望大家持续关注,不要走空。