什么是函数指针,我将如何使用它们?

我知道我可以使用指针来实现function。

有人可以解释为什么会使用它们,以及如何使用它们? 简短的示例代码对我很有帮助。

一个简单的例子是这样的:根据您的业务逻辑,您有一系列操作(函数)。 您有一个散列函数可以将输入问题减少到其中一个业务逻辑函数。 一个干净的代码将有一个函数指针数组,您的程序将从输入推断出该数组的索引并调用它。

这是一个示例代码:

 typedef void (*fn)(void) FNTYPE; FNTYPE fn_arr[5]; fn_arr[0] = fun1; // fun1 is previously defined fn_arr[1] = fun2; ... void callMyFun(string inp) { int idx = decideWhichFun(inp); // returns an int between 0 and 4 fn_arr[idx](); } 

但当然,回调是最常见的用法。 示例代码如下:

 void doLengthyOperation(string inp, void (*callback)(string status)) { // do the lengthy task callback("finished"); } void fnAfterLengthyTask(string status) { cout << status << endl; } int main() { doLengthyOperation(someinput, fnAfterLengthyTask); } 

一个非常常见的用例是回调函数。 例如,如果从DB加载某些内容,则可以实现加载function,以便将进度报告给回调函数。 这可以通过函数指针完成。

回调。 我对一大块代码进行异步调用,并希望它在完成时让我知道,我可以向它发送一个函数指针,一旦完成就调用它。

我很惊讶没有人提到“国家机器”。 函数指针是为解析等任务实现状态机的一种非常常见的方法。 参见例如: 链接 。

您需要提供回调方法时使用函数指针。 一个典型的例子是注册信号处理程序 – 当程序获得SIGTERM(Ctrl-C)时将调用该函数

这是另一个例子:

 // The four arithmetic operations ... one of these functions is selected // at runtime with a switch or a function pointer float Plus (float a, float b) { return a+b; } float Minus (float a, float b) { return ab; } float Multiply(float a, float b) { return a*b; } float Divide (float a, float b) { return a/b; } // Solution with a switch-statement -  specifies which operation to execute void Switch(float a, float b, char opCode) { float result; // execute operation switch(opCode) { case '+' : result = Plus (a, b); break; case '-' : result = Minus (a, b); break; case '*' : result = Multiply (a, b); break; case '/' : result = Divide (a, b); break; } cout << "Switch: 2+5=" << result << endl; // display result } // Solution with a function pointer -  is a function pointer and points to // a function which takes two floats and returns a float. The function pointer // "specifies" which operation shall be executed. void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float)) { float result = pt2Func(a, b); // call using function pointer cout << "Switch replaced by function pointer: 2-5="; // display result cout << result << endl; } 

您可以在http://www.newty.de/fpt/index.html上了解有关函数指针的更多信息

如果您对面向对象语言更熟悉,可以将其视为C实现策略设计模式的方法 。

让我们为C做一个类似map的函数。

 void apply(int *arr, size_t len, int (*func)(int)) { for(size_t i = 0; i < len; i++) arr[i] = func(arr[i]); } 

这样,我们可以转换一个对整数有效的函数来处理整数数组。 我们也可以做类似的版本:

 void apply_enumerated(int *arr, size_t len, int (*func)(size_t, int)) { for(size_t i = 0; i < len; i++) arr[i] = func(i, arr[i]); } 

这也是一样的,但允许我们的函数知道它所在的元素。 我们可以使用它,例如:

 int cube(int i) { return i * i * i } void print_array(int *array, size_t len, char *sep) { if(sep == NULL) sep = ", "; printf("%d", *array); for(size_t i = 1; i < len; i++) printf("%s%d", sep, array[i]) } #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) int main(void) { int array[5] = { 1, 2, 3, 4, 5 }; print_array(array, ARRAY_SIZE(array), NULL); apply(array, ARRAY_SIZE(array), cube); print_array(array, ARRAY_SIZE(array), NULL); return 0; } 

该代码将打印:

 1, 2, 3, 4, 5 1, 8, 27, 64, 125 

对于我们的枚举示例:

 int mult(size_t i, int j) { return i * j } // print_array and ARRAY_SIZE as before int main(void) { int array[5] = { 1, 2, 3, 4, 5 }; print_array(array, ARRAY_SIZE(array), NULL); apply_enumerated(array, ARRAY_SIZE(array), mult); print_array(array, ARRAY_SIZE(array), NULL); return 0; } 

这打印:

 1, 2, 3, 4, 5 0, 2, 6, 12, 20 

作为一个更真实的例子,字符串库可以具有一个函数,该函数将对单个字符进行操作的函数应用于字符串中的所有字符。 这种函数的一个例子是ctype.h中的标准库toupper()tolower()函数 - 我们可以使用这个string_apply() string_toupper()函数轻松地创建一个string_toupper()函数。

一个非常好且易于理解的教程: http : //www.newty.de/fpt/index.html

希望这可以帮助。

指针的另一个用法是迭代列表或数组。

对于代码,请查看qrdl对状态机教程的响应。

我已经使用他的方法的变体来实现我在板上的LCD显示器的菜单。 非常有用,使编码更清晰,更易于阅读。 使用函数指针可以非常轻松地扩展菜单的数量,名称和顺序,并隐藏所有那些细节,这些函数只是看到了“嘿,我在这里写入LCD”。