本文主要介绍C语言中函数指针的定义和使用,这是C语言入门学习中的基础知识。有需要的朋友可以参考一下。
1.函数指针的定义
函数是由执行语句组成的一系列指令或代码。这些代码的有序集合根据其大小被分配到某个内存空间,这个内存空间的起始地址就变成了函数的地址。不同的函数有不同的函数地址,编译器通过函数名索引函数的入口地址。为了方便操作相同类型和属性的函数,c/c引入了函数指针,即指向代码入口地址的指针和指向函数的指针变量。所以“函数指针”本身一开始应该是指针变量,但是指针变量指向的是函数。就像指针变量可以用来指向整形变量,字符类型和数组一样,这里有指向函数。编译C时,每个函数都有一个入口地址,就是函数指针指向的地址。有了指向函数的指针变量后,可以用指针变量调用函数,就像可以用指针变量引用其他类型的变量一样,这在这些概念中是一致的。函数指针有两个用途:调用函数和作为函数的参数。
指针的声明方法是:
类型标识符(指针变量名)(参数列表);
“函数类型”表示函数的返回类型。因为“()”比“*”优先级高,所以指针变量名外面的括号是必要的。后面的“参数表”表示指针变量所指向的函数的参数表。例如:
int函数(int x,int y);/*声明函数*/
int (*f) (int x,int y);/*声明一个函数指针*/
f=函数;/*将函数function的第一个地址赋给指针f */
赋值函数function没有括号,也没有参数。由于function代表的是函数的第一个地址,在赋值之后,指针F指向函数function(int x,int y)。代码的第一个地址。
2.使用函数指针的例子
知道如何定义函数指针,但如何使用?先看下面这个例子:
#包含stdio.h
#包含字符串. h
char * fun(char * p1,char * p2)
{
int I=0;
i=strcmp(p1,p2);
如果(0==i)
{
返回P1;
}
其他
{
返回p2;
}
}
int main()
{
char * (*pf)(char * p1,char * p2);
pf=好玩;
(*pf) ('aa ',' bb ');
返回0;
}
当我们使用指针时,我们需要使用键(" * ")来获取它所指向的内存中的值。函数指针也是如此。用(*pf)取出存在于这个地址的函数,然后调用它。
这里需要注意的是,在Visual C 6.0中,给函数指针赋值时,可以使用fun,也可以直接使用函数名fun。这是因为函数名实际上是编译后的地址,所以这里两种用法没有本质区别。这个例子很简单,我就不详细讨论了。
3.*(int*)p ----这是什么?
可能上面的例子太简单了。让我们看看下面的例子:
void函数()
{
printf('调用函数!\ n’);
}br
int main()
{
void(* p)();
*(int*)p=(int)函数;
(* p)();
返回0;
}
这是在做什么?*(int*)p=(int)函数;这是什么意思?
别急,先看这行代码:
void(* p)();
这行代码定义了一个指针变量p,指向一个参数和返回值都是void的函数。
P是求指针变量P本身的地址,它是一个32位的二进制常量(32位系统)。
(int*)p表示将地址转换成指向int类型数据的指针。
(int)Function是指函数的入口地址被强制转换成int类型的数据。
分析到这里,相信你已经明白了*(int*)p=(int)函数;将函数的入口地址赋给指针变量p。
然后(* p)();它意味着对一个函数的调用。
解释到这里,相信你已经明白了。其实函数指针和普通指针没什么区别,只是指向的内容不同。
使用函数指针的好处是可以统一标识实现同一功能的多个模块,便于后期维护,系统结构更清晰。或者可以概括为:便于分层设计,有利于系统抽象,降低耦合度,分离接口和实现。
4.(*(void(*) ())0)()------这是什么?
是不是觉得上面的例子太简单,不够刺激?好了,让我们做点刺激的事情吧。请看下面的例子:
(*(void(*)())0)();
这是经典著作《C Traps and Pitfalls》中的一个例子。你没疯吧?下面我们来分析一下:
第一步:void(*)。你可以理解为这是一个函数指针类型。这个函数没有参数,也没有返回值。
第二步:(void(*))0,这是0到函数指针类型的强制转换。0是一个地址,这意味着一个函数存在于第一个地址为0的段中。
第三步:(*(void(*))0),它是内存中一段从地址0开始的内容,它的内容是存储在第一个地址为0的段中的函数。
第四步:(*(void(*))0)(),这是一个函数调用。
看起来还是很简单吧?上面的例子将被重写:
(*(char**(*) (char **,char **))0) ( char **,char * *);
没有上面的分析,就很难理解这个表达。不过现在应该是很简单的事情了。读者怎么看?
5.函数指针数组
现在我们知道这个表达了。
char *(* pf)(char * p);
被定义为函数指针pf。因为pf是一个指针,所以它可以存储在一个数组中。修改上面的公式:
char *(* pf[3])(char * p);
这是为了定义一个函数指针数组。
它是一个名为pf的数组,数组中存储了三个指向函数的指针。这些指针指向一些函数,这些函数的返回值类型是指向字符的指针,其参数是指向字符的指针。
这听起来很拗口。不过没关系,关键是你明白这是指针的数组,不是数组。如何使用函数指针数组?这里也有一个很简单的例子。只要真正掌握了使用方法,就可以应对任何复杂的问题。
如下所示:
#包含stdio.h
#包含字符串. h
brchar * fun1(char * p)
{
printf('%s\n ',p);
返回p;
}
char * fun2(char * p)
{
printf('%s\n ',p);
返回p;
}
char * fun3
{
printf('%s\n ',p);
返回p;
}
布林特总管()
{
char *(* pf[3])(char * p);
pf[0]=fun 1;//可以直接使用函数名
pf[1]=fun 2;//可以使用函数名加地址取字符。
pf[2]=fun 3;英国铁路公司
pf[0](' fun 1 ');
pf[0](' fun 2 ');
pf[0](' fun 3 ');
返回0;
}
6.函数指针数组的指针
你不生气这个标题吗?函数指针对初学者来说就够了,函数指针数组比较麻烦。现在函数指针数组指针更难理解了。
其实没那么复杂。数组指针的问题之前已经详细讨论过了。在这里,函数指针数组指针只是一个指针。只有这个指针指向一个数组,所有指向函数的指针都存储在这个数组中。仅此而已。
让我们定义一个简单的函数指针数组指针:
char *(* * pf)[3])(char * p);
请注意,这里的pf与上一节中的pf完全不同。上一节的pf不是指针,而是数组名;这里的pf真的是一个真正的指针。该指针指向包含3个元素的数组;这个数字包含一个指向函数的指针;这些指针指向一些函数,这些函数的返回值类型是指向字符的指针,其参数是指向字符的指针。
这比上一节中的函数指针数组更加笨拙。其实你不用那么担心,只要明白这是一个指针就行了。它的用法和前面提到的数组指针没什么区别。这里有一个简单的例子:
#包含stdio.h
#包含字符串. h
char * fun1(char * p)
{
printf('%s\n ',p);
返回p;
}
char * fun2(char * p)
{
printf('%s\n ',p);
返回p;
}
char * fun3
{
printf('%s\n ',p);
返回p;
}
int main()
{
char *(* a[3])(char * p);
char *(* * pf)[3])(char * p);
pf=a;
a[0]=fun 1;
a[1]=fun 2;
a[2]=fun 3;
pf[0][0](' fun 1 ');
pf[0][1](' fun 2 ');
pf[0][2](' fun 3 ');
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。