在C中传递函数作为参数

时间:2012-05-07 22:25:27

标签: c

我正在查看我的一本教科书,我看到了C函数的以下代码行:

node_t* func(node_t* n, int f(node_t *))

这究竟是什么意思?那里有一个函数作为参数。那是什么意思?你是否应该只要声明它就可以调用文件中的任何函数? 另外,就汇编而言,是否正在引用int f()的内存位置?

谢谢。

2 个答案:

答案 0 :(得分:4)

node_t* func(node_t* n, int f(node_t *))

是一个函数,称为func,它接受两个参数:n,指向node_t的指针,f,指向一个带有node_t指针并返回int的函数的指针。函数func返回指向node_t的指针。

无论如何,我想到的最常见的用途是通用算法。

“只要声明了它,你不应该只能调用文件中的任何函数吗?”

只要该函数已在编译单元中声明,并且链接器可以在链接时找到它,这是真的。但是,当您希望能够在运行时决定使用哪个函数时(或者如果您只想要一个通用函数则编译时),可以使用函数指针。

作为一个切实的例子,请考虑qsort

void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );

现在考虑一下:

typedef struct Student { int id; char* name; }

Student students[10];

//populate students

int sortByName(void* a, void* b)
{
    Student* sa = a;
    Student* sb = b;
    return strcmp(a->name, b->name);
}

int sortById(void* a, void* b)
{
    Student* sa = a;
    Student* sb = b;
    return a->id - b->id;
}

//sort by name:
qsort(students, 10, sizeof(Student), sortByName);

//sort by id:
qsort(students, 10, sizeof(Student), sortById);

重要的是,不必更改排序代码。排序实现实际上是通用的。它是一种对不同数据类型进行操作的算法,在这种情况下,函数指针可以促进这种通用性。

还有其他功能指针的使用(其中相当一部分),例如回调,或基于将某些东西映射到函数的地图的分支。

答案 1 :(得分:1)

第二个参数是指向具有签名int(node_t *)的函数的函数指针。通过这种方式,您可以将回调传递给func,如下所示:

int foo(node_t * p) { /* ... */ }

node_t n;
func(&n, foo);   //  note: the second argument is the function pointer

这是一个非常愚蠢的例子,用它来移动一个虚构的数组:

T * array_next(T * arr, int n) { return arr + n; }
T * array_prev(T * arr, int n) { return arr - n; }

T * move_in_array(T * arr, T * (*f)(T *, int))
{
    return f(arr, 1);
}

现在,您可以使用回调编写以运行时确定的方式在数组中移动的代码:

T * p = move_in_array(some_array, flag ? array_next : array_prev);

这里的关键设计思想是我们有一个通用的动作函数move_in_array,它的具体实现作为参数以函数指针的形式传递。