目录
函数指针:
就像之前(函数×指针(C语言))讲到的那样,一个指针能够指向一个数组、一个整型变量、一个结构体变量……在于其能够存储它们在内存中的首地址。同理,如果我们能够用指针存储一个函数在内存中的首地址,即让这个指针指向这个函数,那么我们就可以通过这个指针变量来调用这个函数,而这个指针变量就被称作函数指针变量,简称函数指针。
那么,一个函数指针该怎样定义呢?我们首先定义一个指向整型函数的函数指针:
int (*p)();
类似的,我们已经学过如何定义一个指向整型变量的整型指针:
int *p;//int (*p);
定义整型指针时,* 和 p 在一起表明 p 是一个指针,而前面的数据类型为 int ,表明 p 是一个整形指针。可以看到, 定义一个指向整型函数的函数指针,我们在指针变量后面添加了一个圆括号,它代表的是函数的形参。
我们再来定义一个简单的求和函数 Sum :
int Sum(int a,int b){int sum=a+b;return sum;}
尽管函数不是变量,但它在内存中仍有其物理地址,该地址能够赋给指针变量。获取函数地址的方法是:用不带有括号和参数的函数名得到。
那么,我们可以这样为 p 赋值:
p=Sum;//p=∑
这样,p 便存储着函数 Sum 的入口地址了,而要引用这个函数,我们不仅可以用 Sum ,还可以用 p 。
#include<stdio.h>
int Sum(int a, int b)
{
int sum = a + b;
printf("通过函数指针成功调用Sum函数,");
return sum;
}
int main()
{
int a = 9, b = 4;
int(*p)(int c, int d);//int (*p)(int, int);/int (*p)();
p = ∑//p=Sum;
printf("结果为 %d", (*p)(a, b));//printf("结果为 %d", p(a, b));
}
通过这个完整的示例,我们发现定义和使用一个函数指针的方法与我们之前学过的整形指针等简单指针的使用并无多大出入。接下来我们以另一种方式定义一个函数指针,需要用到关键字 typedef 。
typedef 关键字的基本功能就是重命名,可以将 int 、char 等数据类型以及数组等复合类型替换别名,举一个小例子:
#include<stdio.h>
int main()
{
typedef int integer;//将 int 重命名为 integer
integer iNum = 10;
printf("iNum: %d\n", iNum);
typedef char character[3];//character 代表了有3个元素的字符数组类型
character str1, str2; //上面两行不能合并为typedef char character[3] str1, str2;
str1[0] = '1';
str1[1] = '2';
str1[2] = '\0';
str2[0] = '3';
str2[1] = '4';
str2[2] = '\0';
printf("str1 + str2: %s%s", str1, str2);
return 0;
}
我们将 int 重命名为 integer ,integer 行使着和 int 一样的功能,两者都能正常定义变量。我们定义了一个 integer 类型的变量 iNum ,并将其值打印出来。然后我们利用一种特殊的方式定义了一中具有3个字符元素的字符数组类型 character ,通过 character 类型定义的每个变量都等同于一个含有3个元素的字符数组。
另外一种定义一个函数指针的方式为:
#include<stdio.h>
int Sum(int a, int b)
{
int sum = a + b;
return sum;
}
int main()
{
typedef int(*Sum_tem1)();
Sum_tem1 Sum_tem2;
Sum_tem2 = Sum;
printf("%d", Sum_tem2(1, 2));
return 0;
}
不难看出,利用 typedef 关键字,我们将 Sum_tem1 定义为一个指向整型函数的指针类型(而不是指向整型函数的指针),但没有指定是指向什么确定的整型函数(这句话暗示可以用这个类型定义一个数组,该数组的元素为各个函数的首地址),然后再定义了一个 Sum_tem1 类型的变量 Sum_tem2 ,并将 Sum 函数的首地址赋给了它,之后我们便可以通过 Sum_tem2 来调用 Sum 函数了。
接下来讲一下 typedef 的一个小功能:
#include<stdio.h>
#define int_tem2 int*
int main()
{
typedef int* int_tem1;
int_tem1 iNum1, iNum2;
int* iNum3, iNum4;
int_tem2 iNum5, iNum6;
return 0;
}
iNum1、iNum2、iNum3、iNum5均为整型指针,而iNum4、iNum6均为整型变量。typedef 将 int* 看作一种数据类型,并将它重命名为 int_tem1,但 #define 起到的作用只是简单的字符替换,故以下两条语句是等效的:
int* iNum3,iNum4;
int_tem2 iNum5, iNum6;
函数的形参为函数指针:
举一个求3个整数的平均值的例子:
#include<stdio.h>
int Sum(int a, int b)
{
int sum = a + b;
return sum;
}
float Average_three_num(int a, int b, int c, int(*p)())
{
float sum = a + p(b, c);
return sum / 3;
}
int main()
{
int(*p)() = Sum; //int (*p) = Sum;也没问题
float ave = 0;
int a = 10, b = 7, c = 6;
ave = Average_three_num(a, b, c, p); //ave = Average_three_num(a, b, c, Sum);也可以
printf("The average of three numbers is %.2f", ave);
return 0;
}
可以看到,函数 Average_three_num 的前三个参数均为整型变量,最后一个参数为函数指针变量。在 main 函数中调用函数 Average_three_num 时,我们可以将它的最后一个实参设置为 p 或是 Sum 。就像我们使用整型指针或是其它类型的指针那样,我们只是将地址传送过去以便能够使用特定地址区间上的东西。
欢迎指正我的上一篇博客:循环链表×双向链表(C语言)
我的下一篇博客:typedef与结构体