由于您上一条评论中仍有一些不确定性,也许一个说明这些要点的具体示例会有所帮助。让我们从一个简单的示例开始,该示例将字符串作为用户从命令行输入(您也可以提示用户输入)。现在假设我们想让用户选择告诉我们他们想如何存储输入。就本例而言,假设选项是 (1) 以正常存储字符串,使其水平打印在一行上,(2) 存储相反的字符串也将打印在一行上的字符串,(3) 在每个字符后使用换行符存储字符串,以便垂直打印,(4) 将字符串反向存储嵌入换行符。
在解决此问题的常规方法中,您可能会编写一个switch 语句或一系列else if 语句并将字符串传递给4 个不同的例程来处理不同的情况。函数指针允许您以不同的方式解决问题。而不是 4 个不同的输入例程来处理每种情况,为什么不 1 个输入例程将函数指针作为参数,并根据作为参数传递的函数更改它处理字符串的方式。输入例程可以像复制字符串一样简单(以防止修改argv[1] 等),然后将字符串作为参数传递给指针表示的函数:
/* make copy of original string, pass to callback function */
char *input (char *d, char *s, char *(*cbf)(char *))
{
strcpy (d, s);
return (*cbf) (d);
}
上面的input 函数将目标字符串d、源字符串s 和指向函数cbf(回调函数的缩写)的指针作为参数。让我们快速看一下函数指针语法并消化它告诉我们的内容:
char *(*cbf)(char *)
| | \
return | argument
type | list
|
function pointer
name/label
上面,名为cbf 的函数指针的返回类型为char *,并采用char * 类型的单个参数。 (注意:在函数指针参数列表中只指定了类型,而不是类型和参数名称 -- 例如,没有char *str,只有char *) 现在,每次您想将这种类型的函数作为参数传递或在赋值中使用它时,输入的内容似乎很多。这是。有一个简单的解决方案可以减少所需的打字。您可以将typedef 用于函数指针,类似于将typedef 与结构等一起使用。创建cbf 类型的typedef 同样简单:
typedef char *(*cbf)(char *);
上面的函数指针 typedef 创建了一个类型 cbf,可以在需要函数指针类型的任何地方使用它来代替 char *(*cbf)(char *)。使用 typedef 时,您无需指定 返回类型 和 参数列表,也不必将函数指针放在括号内。这将原始函数声明简化为:
char *input (char *d, char *s, cbf fname)
{
strcpy (d, s);
return fname (d);
}
对函数使用typedef 不仅简化了将函数作为参数传递,而且还简化了函数指针数组的创建。根据需要,可以使用一组函数指针来简化选择和传递给定数量的函数中的任何一个。对于我们的input 函数,我们创建了一个函数指针数组,每个指针指向一个不同的函数,可用于将输入字符串以所需的格式放置。例如,假设我们上面描述的 4 个函数有这样的声明:
/* input processing callback functions */
char *hfwd (char *s);
char *hrev (char *s);
char *vfwd (char *s);
char *vrev (char *s);
注意:每个函数都匹配char * 类型的指针定义,并接受char * 类型的单个参数。使用我们的cbf typedef,我们可以轻松地创建一个名为fnames 的函数指针数组,如下所示:
cbf fnames[] = { &hfwd, &hrev, &vfwd, &vrev };
fnames 数组可以像任何其他数组一样用于通过数组索引选择我们的任何一个函数。 (例如fnames[0] 是我们的函数hfwd)这让我们能够从用户那里获取第二个输入,一个数字,来选择我们输入字符串的格式。这提供了使用我们的任何一个回调函数的能力,只需将所需函数的数组索引作为命令行的第二个参数提供。例如,任何一个功能都可以通过调用程序来指定:
./progname my_string 1 /* to process the input with the hrev */
现在承认这个例子除了重新格式化一个字符串,但从函数指针语法的角度来看,在数组中收集函数指针,并将函数指针作为参数传递以扩展代码的功能,它涵盖了很多。看看下面的例子,如果你有任何问题,请告诉我。 (回想一下,完整的函数指针语法,在没有 typedef 的情况下,也包括在内,但已注释,以便您可以比较/对比 typedef 的使用)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 128
/* typedef for function pointer */
typedef char *(*cbf)(char *);
/* simple string reverse function */
char *strrevstr (char *str);
/* input processing callback functions */
char *hfwd (char *s);
char *hrev (char *s);
char *vfwd (char *s);
char *vrev (char *s);
/* input function, pointer to function will determine behavior */
// char *input (char *d, char *s, char *(*cbf)(char *));
char *input (char *d, char *s, cbf fn);
int main (int argc, char **argv) {
if (argc < 3 ) {
fprintf (stderr, "error: insufficient input, usage: %s string int\n", argv[0]);
return 1;
}
int idx = atoi(argv[2]);
if (idx > 3 || idx < 0) {
fprintf (stderr, "error: invalid input -- out of range, (0 !< %d !< 3)\n", idx);
return 1;
}
cbf fnames[] = { &hfwd, &hrev, &vfwd, &vrev };
// char *(*fnames[])(char *) = { &hfwd, &hrev, &vfwd, &vrev };
char string[MAXS] = {0};
input (string, argv[1], fnames[idx]);
printf ("\nProcessed input ('%s' '%s'):\n\n%s\n\n", argv[1], argv[2], string);
return 0;
}
/* strrevstr - reverse string, original is not preserved. */
char *strrevstr (char *str)
{
if (!str) {
printf ("%s() error: invalid string\n", __func__);
return NULL;
}
char *begin = str;
char *end = str + strlen (str) - 1;
char tmp;
while (end > begin)
{
tmp = *end;
*end-- = *begin;
*begin++ = tmp;
}
return str;
}
/* string unchanged - print horizontal */
char *hfwd (char *s)
{ return s; }
/* string reversed - print horizontal */
char *hrev (char *s)
{ return strrevstr (s); }
/* string unchanged - print vertical */
char *vfwd (char *s)
{
char *p = s;
static char buf[MAXS] = {0};
char *b = buf;
while (*p)
{
*b++ = *p++;
*b++ = '\n';
}
*b = 0;
b = buf;
while (*b)
*s++ = *b++;
*b = 0;
return buf;
}
/* string reversed - print vertical */
char *vrev (char *s)
{
char *p = strrevstr (s);
static char buf[MAXS] = {0};
char *b = buf;
while (*p)
{
*b++ = *p++;
*b++ = '\n';
}
*b = 0;
b = buf;
while (*b)
*s++ = *b++;
*b = 0;
return buf;
}
/* make copy of original string, pass to callback function */
char *input (char *d, char *s, cbf fn)
// char *input (char *d, char *s, char *(*cbf)(char *))
{
strcpy (d, s);
return fn (d);
// return (*cbf) (d);
}
输出
$ ( for i in {0..3}; do ./bin/fnc_pointer my_string $i; done )
Processed input ('my_string' '0'):
my_string
Processed input ('my_string' '1'):
gnirts_ym
Processed input ('my_string' '2'):
m
y
_
s
t
r
i
n
g
Processed input ('my_string' '3'):
g
n
i
r
t
s
_
y
m