问题描述:
如果我们需要做一个这样的程序,当用户输入"hello"时,我调用hello函数,当用户输入"hey"时,我调用hey函数,像这样的对应关系,用户可能会有数千种输入,每种输入对应一个我需要调用的函数。
一般的方法,肯定是这样,在程序处理流程中,这样写:
if (0 == strcmp(strInput, "hello"))
{
hello();
}
else if (0 == strcmp(strInput, "hey"))
{
hey();
}
else if
{
.....
这样的程序分支,写下来就是不断地重复,等你需要添加新的函数时,不得不在一个已经写得很长的函数里面不断地加else if,而且不能支持处理函数的动态添加,比如我突然觉得“hello”的输入要交给hey()函数来处理了,那我只能在编译期修改它,不能在程序运行之后再修改。
现在有一个好办法,我们可以使用函数指针来处理这些处理函数的对应关系,下面举一个例子
#include <stdio.h>
#include <string.h>
typedef void(*VOID_FUNC_PTR)(void);
typedef struct
{
char *pszInput;
VOID_FUNC_PTR func;
} FUNC_REG;
void hello(void)
{
puts("I know you are saying hello.");
}
void hey(void)
{
puts("hey~hey.");
}
void someother(void)
{
puts("some more out put.");
}
void defaultFunc(void)
{
puts("there is no function for this anyway.");
}
FUNC_REG func_reg_list[] =
{
"hello", hello,
"hey", hey,
"someother", someother
};
VOID_FUNC_PTR LookupFunc(char *pszInput)
{
int i;
for (i = 0; i < sizeof(func_reg_list) / sizeof(func_reg_list[0]); i++)
{
if (0 == strcmp(pszInput, func_reg_list[i].pszInput))
{
return func_reg_list[i].func;
}
}
return defaultFunc;
}
int main()
{
VOID_FUNC_PTR func = NULL;
char szInput[256];
while (EOF != scanf("%s", szInput))
{
func = LookupFunc(szInput);
if (func != NULL)
{
(*func)();
}
}
return 0;
}
技术细节:
@1
typedef void(*VOID_FUNC_PTR)(void);
由于我们的处理函数都是返回void并且带void参数的函数,我们可以把自己“处理函数”的指针typedef成VOID_FUNC_PTR类型,此处VOID_FUNC_PTR只是我们给它起的一个名称而已,它也可以是别的名字。
@2.
后面我们再定义了一个结构体,这个结构体名字叫FUNC_REG,里面包含一个字符串,和一个我们“处理函数”的指针,这两个用来记录处理函数和用户输入内容的对应关系。
@3.
用我们的FUNC_REG结构体定义一个数组,并用这个数组来记录用户输入和我们处理函数的对应关系表。这个表有人称其为函数注册表,注册过的函数即为这个表中含有的函数。如果我们需要的话,完全可以去写一个“函数注册函数”去完成新的处理函数的动态添加,当然,这个注册表就不应该简单采用数组来存储了,这里仅供演示。
(注:按程序需要,可以按需要灵活使用多种数据结构去存储这个表,可以不用是数组,我们也可以使用链表之类的数据结构,以方便在程序运行时对这个对应关系表进行必要的修改)
FUNC_REG func_reg_list[] =
{
"hello", hello,
"hey", hey,
"someother", someother
};
@4.
我们再创建一个LookupFunc函数来查找上面这个对应关系表,获得相应的处理函数指针并返回。若找不到对应的处理函数,则返回我们的默认函数defaultFunc
VOID_FUNC_PTR LookupFunc(char *pszInput)
{
int i;
for (i = 0; i < sizeof(func_reg_list) / sizeof(func_reg_list[0]); i++)
{
if (0 == strcmp(pszInput, func_reg_list[i].pszInput))
{
return func_reg_list[i].func;
}
}
return defaultFunc;
}
@5
使用函数指针调用函数,注意语法格式:
则函数指针为func,调用它时这样写:
(*func)(参数1, 参数2,...);
若需要返回值,则:
返回值 = (*func)(参数1, 参数2,...);
@6.
上面的代码已经演示了最简单的将函数输入与处理函数对应上的操作,如果我们要添加一个处理函数,那只需要在我们的func_reg_list后面再加上一行。
如果我觉得现在要把“hello”函数的字符串改用hey函数来处理,这也相当简单了,在运行时就可以改了
只需要在代码里添加:
func_reg_list[0] = hey;
即可达到效果。
@7.
欣赏一下这个演示程序的输出结果
hello
I know you are saying hello.
hey
hey~hey.
someother
some more out put.
adfff
there is no function for this anyway.
ffff
there is no function for this anyway.