前言:前面有一篇文章是专门针对函数指针与指针函数的,本文再进一步说明指针,涉及到两个较为复杂烦琐的概念,即
函数指针数组、函数指针数组的指针。前一篇文章参考为:
C语言指针进阶(一)——深入详解“函数指针”与“指针函数”
前面的文章已经详细介绍了函数指针,它是如何定义的也已经很清楚了,那究竟什么是函数指针数组呢?
1.1 案例一
先从一个案例来说明,比如我有四个函数,分别实现两个数的加法、减法、乘法、除法运算,两个参数都是浮点型float,返回的值也是浮点型float,当然我们可以创建四个不同的函数指针分别指向这四个函数,但是想一下,既然没一个函数的参数和返回值都是一样的,所以函数指针的形式也应该一样,那就没有必要定义四个重复的指针了,二用一个数组的形式即可完成。
先看一下四个函数的定义:
float add(float a,float b)
{
printf("%f\n", a+b);
return a+b;
}
float sub(float a, float b)
{
printf("%f\n", a - b);
return a - b;
}
float mul(float a, float b)
{
printf("%f\n", a * b);
return a * b;
}
float div(float a, float b)
{
printf("%f\n", a / b);
return a / b;
}
定义函数指针数组:
float (*pf[4])(float,float);
为什么是这个样子呢?
根据前面的函数指针的定义,这里如果只定义一个函数指针匹配四个函数中的其中一个,我们可以这样定义
float (*pf)(float,float);
这没什么可说的,在函数指针数组的定义中,
float (*pf[4])(float,float); //由于在(*pf[4])这个括号里面[]的优先级比*更高,所以它实际上等价于
float (*pf0)(float,float); //定义的四个函数指针,只不过写成了数组的形式
float (*pf1)(float,float);
float (*pf2)(float,float);
float (*pf3)(float,float);
//等价于
typedef float (*FUNC)(float,float); //定义一个函数指针
FUNC *pf[4];
最终的完整的代码为:
int main() {
float (*pf[4])(float,float);
pf[0] = add; // 可以直接用函数名
pf[1] = ⊂ // 可以用函数名加上取地址符
pf[2] = &mul;
pf[3] = div;
pf[0](10.0,20.0);
pf[1](10.0, 20.0);
pf[2](10.0, 20.0);
pf[3](10.0, 20.0);
getchar();
return 0;
}
/*最终结果为:
30.000000
-10.000000
200.000000
0.500000
*/
1.2 案例二
这里返回的是一个基本的浮点类型,如果我返回的是一个指针类型呢?四个函数如下:
#include
float *add(float a,float b)
{
float c = a + b;
printf("%f %p\n", a + b, &c);
return &c;
}
float *sub(float a, float b)
{
float c = a - b;
printf("%f %p\n", a - b, &c);
return &c;
}
float *mul(float a, float b)
{
float c = a + b;
printf("%f %p\n", a + b, &c);
return &c;
}
float *div(float a, float b)
{
float c = a + b;
printf("%f %p\n", a / b,&c);
return &c;
}
完整代码为:
int main() {
float *(*pf[4])(float,float);
//等价于
//typedef float *(*FUNC)(float, float);
//FUNC pf[4];
pf[0] = add; // 可以直接用函数名
pf[1] = ⊂ // 可以用函数名加上取地址符
pf[2] = &mul;
pf[3] = div;
pf[0](10.0,20.0);
pf[1](10.0, 20.0);
pf[2](10.0, 20.0);
pf[3](10.0, 20.0);
getchar();
return 0;
}
/*
30.000000 0073F97C
-10.000000 0073F97C
30.000000 0073F97C
0.500000 0073F97C
*/
总结:函数指针数组 其实就是 函数指针组成的数组。作用就是用一个数组的形式,每一个数组元素就是一个函数指针,指向具有相同参数和返回值的函数,常见的行使如下:
float (*pf[4])(float,float); //每一个函数返回基本类型,这里是float
//等价于:
typedef float (*FUNC)(float,float);
FUNC pf[4];
float *(*pf[4])(float,float); //每一个函数返回一个指向基本类型的指针,这里是指向float的指针
//等价于
typedef float *(*FUNC)(float,float);
FUNC pf[4];
typedef int(*FUNC)(int, int); //定义一个函数指针类型
FUNC(*pf[4])(float, float); //每一个函数返回的都是一个函数指针类型,与FUNC匹配
注意:在使用函数指针的时候,当出现比较复杂的指针的时候,最好是通过typedef来定义,这样就比较明确了,看起来一目了然。
函数指针数组就是定义一个数组,每一个数组元素都是一个指向函数的指针。
前面详细讨论过数组指针的问题,这里的函数指针数组的指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面的每一个元素又都是都是指向函数的函数指针。仅此而已。
这其实就是在前面的“函数指针数组”的基础上更进一步,前面的是一个数组,上一节的pf就是数组名,这儿再用一个指针指向前面的那个数组,仅此而以。
2.1 案例一:参见上面的案例一
下面就定义一个简单的函数指针数组指针:
float (*(*pf)[3])(float,floart);
注意:
(1)这里的pf 和上面的pf 就完全是两码事了。上一节的pf 并非指针,而是一个数组名;这里的pf 确实是实实在在的指针。
(2)这个指针pf指向一个包含了3 个元素的数组;即下方的红色部分,这就是数组指针的定义嘛。
float (*(*pf)[3])(float a,float b);
这个数字里面存的是指向函数的指针;
(3)这些指针指向一些返回值类型为float、参数为两个float的指针的函数。这比面的函数指针数组更拗口。其实你不用管这么多,明白这是一个指针就ok 了。其用法与前面讲的数组指针没有差别。下面列一个简单的例子:
int main() {
float (*a[4])(float,float); //“函数指针数组”
a[0] = add;
a[1] = sub;
a[2] = mul;
a[3] = div;
float(*(*pf)[4])(float,float); //“函数指针数组的指针”。这里的pf不再是数组名成了,而是一个指向数组的数组指针
pf = &a;
pf[0][0](10.0,20.0);
pf[0][1](10.0, 20.0);
pf[0][2](10.0, 20.0);
pf[0][3](10.0, 20.0);
getchar();
return 0;
}
/*
30.000000
-10.000000
200.000000
0.500000
*/
2、案例二:参见上面的案例二
实现代码如下:
int main() {
float *(*a[4])(float,float); //“函数指针数组”
a[0] = add;
a[1] = sub;
a[2] = mul;
a[3] = div;
float *(*(*pf)[4])(float,float); //“函数指针数组的指针”。这里的pf不再是数组名成了,而是一个指向数组的数组指针
pf = &a;
pf[0][0](10.0,20.0);
pf[0][1](10.0, 20.0);
pf[0][2](10.0, 20.0);
pf[0][3](10.0, 20.0);
getchar();
return 0;
}
/*
30.000000 00DFFD90
-10.000000 00DFFD90
30.000000 00DFFD90
0.500000 00DFFD90
*/
总结:由上面的几个例子,可以看到C语言的指针的确很强大,与此同时,的的确确很复杂,很容易让人犯错,所说像上面这样的代码尽量还是少出现,否则别人看的人真的是头疼,另外,如果一定要用各种复杂的指针,建议使用typedef,定义得更加清楚易懂一些,这样比较好理解,也比较好维护。