阅读 ‧ 电子书库 提  示
声明一个指向特定函数类型的指针,首先声明一个该类型的函数,然后用(*pf)形式的表达式代替函数名称;pf就成为可指向那种类型函数的指针了。

有了函数指针之后,可以把适当类型的函数的地址赋给它。在这种场合中,函数名可以用来表示函数的地址:

阅读 ‧ 电子书库

最后一种赋值方式也是不正确的,因为不能在一个赋值的语句中使用一个void类型的函数。注意,指针pf可以指向任何接受一个char*参数并且返回类型为void的函数,而不能指向具有其他特性的函数。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

正像可以使用一个数据指针来访问数据一样,也可以使用函数指针来访问函数。奇怪的是,有两个逻辑上不一致的语法规则来实现这样的操作,请看下面的举例说明:

阅读 ‧ 电子书库

每种方法听起来都是有道理的。第一种方法:因为pf指向ToUpper函数,* pf就是ToUpper函数,因此表达式(*pf)(mis)与ToUpper(mis) 一样。从ToUpper和pf的声明中就能看出ToUpper和(*pf)是等价的。第二种方法:因为函数名是一个指针,可以互换地使用指针和函数名,因此pf(mis)与ToLower(mis)一样。从pf的赋值语句中就能看出pf和ToLower是等价的。历史上,贝尔实验室的C和UNIX的开发者采用第一种观点,而Berkeley的UNIX的扩展者采用第二种观点。K&R C不允许第二种形式。但是为了保持与现有代码的兼容性,ANSI C把这二者作为等价形式全部接受。

正如数据指针最常见的用法之一是作为函数的参数一样,函数指针最普遍的用法之一也是作为函数的参数。例如,考虑以下函数原型:

阅读 ‧ 电子书库

这看起来很杂乱,但它声明了两个参量fp和str。参量fp是一个函数指针,str是一个数据指针。更具体一点,fp指向接受一个char *参量且返回类型为void的函数,str指向一个char值。因此,给定前面的声明,可以使用像下面这样的函数调用:

阅读 ‧ 电子书库

show()如何使用传递过来的函数指针呢?它使用语法fp()或(*fp)()来调用函数:

阅读 ‧ 电子书库

阅读 ‧ 电子书库

例如,这里show ()首先把fp指向的函数作用于字符串str来转换str,然后显示转换后的字符串。

顺便提一句,带有返回值的函数能以两种不同的方式作为其他函数的参数。例如,考虑下面的情况:

阅读 ‧ 电子书库

第一个语句传递了函数sqrt()的地址,functionl()可能会在代码中使用该函数。第二个语句先调用函数sqrt(),求出它的值,然后将返回值(在本例中是2.0)传递给function2 ()。

为了说明基本概念,程序清单14.16中的程序使用一个以各种各样的转换函数作为参数的show()函数。该程序清单也说明了一些处理菜单的有用的技术。

程序清单14.16 func_ptr.c程序

阅读 ‧ 电子书库

阅读 ‧ 电子书库

下面是一个运行示例:

阅读 ‧ 电子书库

注意,函数ToUpper()、ToLower()、Transpose()和Dummy()都是相同类型的,因此4个函数都可以赋值给指针pfun。这个程序用pfun作为show()的参数,但是也可以直接将4个函数名称中的右何一个作为参数,就像show(Transpose, copy)一样。

在这种情况下您可以使用typedef。例如,示例程序还可以这样做:

阅读 ‧ 电子书库

如果您具有探险精神,您可以声明并初始化一个这类指针的数组:

阅读 ‧ 电子书库

然后,修改函数showmenu(),使它是int类型的,并且在用户键入u时返回值0,键入1时返回1,键入t时返回2,等等。您就可以用下面的语句代替包含switch语句的循环:

阅读 ‧ 电子书库

不能拥有一个“函数的数组”,但可以拥有一个“函数指针的数组”。

现在您已经了解使用函数名的所有4种方法:定义函数、声明函数、调用函数以及作为指针。图14.4总结了这些用法。

阅读 ‧ 电子书库

图14.4 函数名的用法

至于处理菜单,函数showmenu ()给出了几种技术。首先,代码:

阅读 ‧ 电子书库

和:

阅读 ‧ 电子书库

给出两种方法。这两种方法都可以将用户的输入转换为一种大小写形式,这样就不用既检测‘u’,又检测‘U’,等等。

函数eatline()剔除输入行的剩余部分,这在两个方面很有用。第一,要输入一个选择,用户会键入一个字母,然后按下回车键,这将产生一个换行符。如果不事先去掉这个换行符,它将作为下一个用户响应被读入。第二,假设用户键入整个的单词uppercase而不是u作为响应,如果没有eatline()函数,程序会把单词uppercase的每个字符当作一个单独的响应。有了eatline(),程序只处理u,并丢弃该输入行的剩余部分。

其次,showmenu()函数是设计用来只将正确的选择返回给程序。为了完成该任务,程序使用了头文件string.h中的标准库函数strchr():

阅读 ‧ 电子书库

这个函数在字符串“ulton”中找出字符ans首次出现的位置,并返回一个指向该位置的指针。如果没找到这个字符,函数返回空指针。因此,上面这个while循环判断条件和以下判断条件的作用相同,但使用起来更为方便:

阅读 ‧ 电子书库

需要检查的选择越多,使用strchr()就会越方便。