1

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

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

这到底是什么意思?里面有一个函数作为参数。那有什么意义呢?只要声明了文件,您不应该只能调用文件中的任何函数吗?另外,就汇编而言,它是被引用的 int f() 的内存位置吗?

谢谢你。

4

2 回答 2

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);

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

函数指针还有其他用途(其中不少),例如回调,或基于将某些内容映射到函数的映射的分支。

于 2012-05-07T22:28:06.997 回答
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,它的具体实现以函数指针的形式作为参数传递。

于 2012-05-07T22:30:26.003 回答