void ToUpper (char *): //把字符串转换为大写函数ToUpper ()的类型是“具有char*类型的参量,返回类型是void的函数”。要声明指向这种类 型的函数的指针pf,可以这样做:
void (*pf) (char *); // pf是一个指向函数的指针从这个声明中可以看出,第一对圆括号将运算符*和Pf结合在一起,这意味着Pf是一个指向函数的指 针。这就使得(*pf)是一个函数,并使(char*)作为该函数的参量列表,void作为其返回类型。可能创 建这个声明最简单的方法是注意到它用表达式(*pf)来代替函数名ToUpper。因此,如果想要声明一个指 向某一特定类型函数的指针,可以声明一个这种特定类型的函数,然后用一个(* pf)形式的表达式来替 代函数名,以创建一个函数指针声明。就像先前提到过的那样,由于有运算符优先级的规则,所以第一个圆括号是必需的。省略掉圆括号会导致完全不同的情况:
void *pf (char *); // pf是返回一个指针的函数
有了函数指针之后,可以把适当类型的函数的地址陚给它。在这种场合中,函数名可以用来表示函数 的地址:
void ToUpper (char *);
void ToLower (char *);
int round (double);
void (*pf) (char *);
pf = ToUpper;//合法,ToUpper是函数ToUpper ()的地址
pf = ToLower: //合法,ToLower是函数ToLower O的地址
pf = round; //无效,round是错误类型的函数
pf = ToLower (): //无效,ToLower ()不是地址
最后一种赋值方式也是不正确的,因为不能在一个陚值的语句中使用一个void类型的函数。注意,指 针pf可以指向任何接受一个char*参数并且返回类型为void的函数,而不能指向具有其他特性的函数。
正像可以使用一个数据指针来访问数据一样,也可以使用函数指针来访问函数。奇怪的是,有两个逻 辑上不一致的语法规则来实现这样的操作,请看下面的举例说明:
void ToUpper (char *):
void ToLower (char *);
void (*pf) (char *);
char mis[] = "Nina Metier":
pf = ToUpper:
(*pf) (mis): // 把ToUpper作用于mis (语法 1)
pf = ToLower:
pf (mis); // 把 ToLower 作用于 mis (语法 2)
每种方法听起来都是有道理的。第一种方法:因为pf指向ToUpper函数,*pf就是ToUppei函数,因 此表达式(*pf) (mis)与ToUpper (mis) —样。从ToUpper和pf的声明中就能看出ToUpper和(* pf)是等价的。第二种方法:因为函数名是一个指针,可以互换地使用指针和函数名,因此pf (mis)与ToLower (mis)—样。从pf的賦值语句中就能看出pf和ToLower是等价的。历史上,贝尔实验室的C和UNIX的 开发者采用第一种观点,而Berkeley的UNIX的扩展者采用第二种观点。K&RC不允许第二种形式。但是 为了保持与现有代码的兼容性,ANSI C把这二者作为等价形式全部接受。
正如数据指针最常见的用法之一是作为函数的参数一样,函数指针最普遍的用法之一也是作为函数的 参数。例如,考虑以下函数原型:
void show (void (* fp) (char *), char * str);
这看起来很杂乱,但它声明了两个参量pf和str。参量fp是一个函数指针,str是一个数据指针。更具 体一点,fp指向接受一个char*参量且返回类型为void的函数,str指向一个char值。因此,给定前面的 声明,可以使用像下面这样的函数调用:
show (ToLower, mis): /* show ()使用 ToLower ()函数:fp=ToLower */
show (pf,mis): /* show ()使用由 pf 指向的函数:fp=pf */
show ()如何使用传递过来的函数指针呢?它使用语法尔()或()来调用函数:
void show (void (* fp) (char *),char * str)
{ 1
(*fp) (str): /*把所选函数作用于str */
puts (str); /* S不结果 */
}
例如,这里show ()首先把fp指向的函数作用于字符串str来转换str,然后显示转换后的字符串。 顺便提一句,带有返回值的函数能以两种不同的方式作为其他函数的参数。例如,考虑下面的情况:
functionl (sqrt): /* 传递 sqrt 函数的地址 */
function2 (sqrt (4.0)); /* 传递 sqrt 函数的返回值 */
第一个语句传递了函数sqrt ()的地址,functionl ()可能会在代码中使用该函数。第二个语句先调 用函数sqrt (),求出它的值,然后将返回值(在本例中是2.0)传递给fiinction2 ()。
// func_ptr.c --使用函数指针\
#include
#include
#include
#define MAX 81
char showmenu(void);
void eatline(void); // 读至行未
void show(void(*fp)(char *),char *str);
void ToUpper(char *); //把字符串转换为大写
void ToLower(char *); //把字符串转换为小写
void Transpose(char *); //大小写转置
void Dummy(char *); //不改变字符串
int main(void)
{
char line[MAX];
char copy[MAX];
char choice;
void (*pfun)(char *);//指向一个函数,该函数接受
// 一个char *参数,并且没有返M值
puts("Enter a string (enpty line to quit):");
while(gets(line)!=NULL&&line[0]!='\0')
{
while((choice=showmenu())!='n')
{
switch(choice)// switch语句用来设置指针
{
case 'u':pfun=ToUpper;break;
case 'l':pfun=ToLower;break;
case 't':pfun=Transpose;break;
case 'o':pfun=Dummy;break;
}
strcpy(copy,line); 为 show ()制作一份拷贝
show(pfun,copy);使用用户选择的函数
}
puts("Enter a string (empty line to quit):");
}
puts("Bye!");
return 0;
}
char showmenu(void)
{
char ans;
puts("Enter menu choice:");
puts("u)uppercase l)lowercase");
puts("t)transposed case o)origianl case");
puts("n)next string");
ans=getchar();//获取用户的响应
ans=tolower(ans);// 转换为小写
eatline();// 剔除行中剩余部分
while(strchr("ulton",ans)==NULL)
{
puts("Please enter a u,l,t,o,or n:");
ans=tolower(getchar());
eatline();
}
return ans;
}
// 剔除行中剩余部分
void eatline(void)
{
while(getchar()!='\n')
continue;
}
void ToUpper(char *str)
{
while(*str)
{
*str=toupper(*str);
str++;
}
}
void ToLower(char *str)
{
while(*str)
{
*str=tolower(*str);
str++;
}
}
void Transpose(char *str)
{
while(*str)
{
if(islower(*str))
*str=toupper(*str);
else if(isupper(*str))
*str=tolower(*str);
str++;
}
}
void Dummy(char *str)
{
// leaves string unchanged
}
void show(void (* fp)(char *), char * str)
{
(*fp)(str); // apply chosen function to str
puts(str); // display result
}
下面是一个运行示例:
Enter a string (empty line to quit): Does C make you feel loopy?
Enter menu choice: u) uppercase 1) lowercase
t) transposed case o) original case n) next string
t
dOES C MAKE YOU FEEL LOOPY?
Enter menu choice:
u) uppercase 1) lowercase
t) transposed case o) original case n) next string
1
does c make you feel loopy?
Enter menu choice:
u) uppercase 1) lowercase
t) transposed case o) original case n) next string n
Enter a string (empty line to quit):
Bye!
注意,函数ToUpper ()、ToLower ()、Transpose ()和Dummy ()都是相同类型的,因此4个函数 都可以赋值给指针pfun。这个程序用pfim作为show ()的参数,但是也可以直接将4个函数名称中的任 何一个作为参数,就像show (Transpose,copy) —样。
在这种情况下您可以使用typedef。例如,示例程序还可以这样做:
typedef void (*V_FP_CHARP) (char *):
void show (V_FP_CHARP fpt char *):
V_FP_CHARP pfun;