我想明白的地方,在实际场景中使用函数指针。 任何人都可以请给我一个实际的例子,我们必须传递函数本身作为另一个函数的参数。
回答
当您想创建callback mechanism并且需要将函数的地址传递给另一个函数时,函数指针可能很有用。
当你想存储一组函数,例如动态调用时,它们也可能很有用。
一个常见用途是实现callback function。
尝试使用qsort
库函数对某些东西进行排序。它的最后一个参数是指向您写的比较函数的指针。
我觉得作为一个非常有用的应用程序的第一件事是一个按钮。看看下面的代码:
int buttonID = CreateButton ("Click Me!", 100, 100, 200, 100, onClick);
这将创建一个宽度200,高度100。每当你点击它在(100,100)的按钮,onClick函数调用。
我在个人Windows API包装中使用了类似的东西。它使得创建按钮等变得更容易。
那么,#1股票的答案是:qsort
。 qsort
将使用的比较器例程作为函数指针传递。许多其他“通用算法”功能将以类似的方式采用比较器;例如也许散列表实现可能会接受你的散列函数。 C语言GUI工具包和应用程序框架(例如Gnome/Gtk +/Glib)经常接受函数指针作为定时器或用户界面事件的“回调函数”。 (EG:“单击此按钮时调用此函数”或“...只要此计时器过期”)
实际上,C中的大多数“OOP-like”或“事件驱动”代码将接受函数指针类似的原因。
有函数指针两个主要用途:
- 回调 - 用于事件处理程序,解析器专业化,比较器功能的传球...
- 插件和扩展 - 通过插件或提供的函数指针库扩展由标准函数
GetProcAddress
,dlsym
或类似的函数收集,它们将函数标识符作为名称并返回一个函数指针。对于像OpenGL这样的API来说绝对至关重要。
您可以使用它将回调传递给函数。例如,您可能想要使用qsort()
对数组进行排序。此功能需要一个比较函数作为它的一个参数,这意味着你可以使用自己的排序顺序:
// All odd numbers are before even numbers
int cmpoddeven(const void *xp, const void *yp) {
int x = *((int*) xp);
int y = *((int*) yp);
if(x == y)
return 0;
if(x % 2 == y % 2) {
return (x < y ? -1 : 1);
if(x % 2 == 1)
return -1;
return 1;
}
int main() {
int array[] = {1, 2, 3, 4, 5};
// calling qsort with cmpoddeven as the comparison function
qsort(array, 5, sizeof(int), &cmpoddeven);
// array == {1, 3, 5, 2, 4};
}
在大多数情况下,它本质上是做dependency inversion的C-方式。该wiki文章指出:
答:高级模块不应该依赖低级模块。两者都应该依赖于抽象。 B.抽象不应该取决于细节。细节应该取决于抽象。
qsort
的经典示例是这样做的,即更高级别的排序函数不依赖于要排序的数据的类型,大小或比较方法。因此,如果您使用的是整数的qsort()
,则详细信息为sizeof(int)
和您的比较实现。抽象是一个任意大小的元素数组和一个比较该类型元素的函数。另外:Inversion of Control。
我很惊讶没有人提到过pthread_create()
作为例子。
我能想到的惟一常见用法不能一概而论,因为依赖倒置在非可切换数据类型上实现类似开关的流量控制。例如,如果您曾经想要打开字符串,请创建将排序后的字符串键映射到函数指针并进行二分搜索的数组。它不像开关那样是O(1),而是比在一个大的if-else中盲目地执行strcmp(),直到你找到一个匹配更好。但也许并不比标记字符串和使用实际开关更好。
回调例程似乎是迄今为止提出的最常见的场景。然而,还有许多其他的...
有限状态机其中(多维)数组元素指示处理/处理下一个状态的例程。这将FSM的定义保留在一个地方(数组)。
启用功能和禁用功能可以使用函数指针来完成。您可能具有希望启用或禁用的功能,可以执行类似但不同的操作。您可以使用if-else构造测试变量来代替填充和混淆代码,以便使用函数指针进行编码,然后通过更改/分配函数指针来启用/禁用功能。如果添加新的变体,则不必追踪所有if-else或switch案例(并且可能会丢失一个)。相反,您只需更新函数指针以启用新功能,或者禁用旧功能。
减少代码混乱我在前面的例子中谈到了这一点。例如,如...
switch (a) {
case 0:
func0();
break;
case 1:
func1();
break;
case 2:
func2();
break;
case 3:
func3();
break;
default:
funcX();
break;
}
可以简化为...
/* This declaration may be off a little, but I am after the essence of the idea */
void (*funcArray)(void)[] = {func0, func1, func2, func3, funcX};
... appropriate bounds checking on 'a' ...
funcArray[a]();
还有更多。希望这可以帮助。
FWIW,声明应该是'void(* funcArray [])(void)= {func0,func1,func2 ...};'('funcArray'是一个指向函数的指针数组...)。记住声明模仿使用;如果代码中的表达式是'funcArray [a]()',那么声明将以相同的方式构造。 –
@JohnBode - 非常感谢。尽管我已经和C一起工作了20多年,但我仍然混淆了函数指针语法。通常我选择更简单的(对我来说)typedef函数指针的路由,然后声明typedef变量的数组。 – Sparky
@Sparky就typedef达成一致意见。它使诸如函数指针数组或指向函数指针的指针变得更容易阅读。 –
- 1. 什么是函数指针?
- 2. vbscript中的函数指针是什么?
- 3. 在函数中使用指针指针的正确方法是什么?
- 4. 什么是指向指针的指针?
- 5. 使用指针的目的是什么?
- 6. 什么是打印内建函数的函数指针
- 7. 什么时候在C++中使用函数引用而不是函数指针?
- 8. 指针指针的意义是什么?
- 9. 指针指针的语法是什么?
- 10. 为什么cudaMalloc()使用指针指针?
- 11. 什么是指向一个函数的指针?
- 12. 函数指针的指针值代表什么?
- 13. 函数指针的使用
- 14. 为什么Java不是使用指针
- 15. 什么是强指针和弱指针
- 16. 指针指针是什么意思?
- 17. 传递指针作为函数参数的语义是什么?
- 18. 函数指针数组的类型是什么?
- 19. 这有什么函数指针
- 20. 函数指针声明 - __P做什么?
- 21. OpenGL gl *指针函数做什么
- 22. 无效的左值,指向函数的指针,这是什么使用?它更简单地调用函数
- 23. 为什么使用指针
- 24. 为什么在Objective-C的结构中使用函数指针?
- 25. 为什么和什么时候值得使用指针指针?
- 26. 我们在哪里可以使用C中的函数指针,函数指针有什么用处
- 27. 如果它不是函数指针,它是什么?
- 28. 函数指针与函数调用有什么区别?
- 29. 使用函数指针?
- 30. 使用函数指针
这是C#,但它也涉及到C/C++和函数指针的实用性:http://stackoverflow.com/questions/667410/the-benefits-of-using-function-pointers – Algorhythm