我想创建一个函数,它执行一组数据上通过参数传递的函数。如何在C中传递函数作为参数?


当前回答

宣言

接受函数形参的函数原型如下所示:

void func ( void (*f)(int) );

这说明形参f将是一个指针,指向一个具有void返回类型并接受单个int形参的函数。下面的函数(print)是一个可以作为参数传递给func的函数示例,因为它是正确的类型:

void print ( int x ) {
  printf("%d\n", x);
}

函数调用

当调用带有函数形参的函数时,传递的值必须是指向函数的指针。使用函数名(不带括号):

func(print);

调用func,将print函数传递给它。

函数体

与任何形参一样,func现在可以在函数体中使用形参的名称来访问形参的值。假设func将应用它传递给数字0-4的函数。首先,考虑直接调用print的循环会是什么样子:

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}

因为func的形参声明说f是指向目标函数的指针的名称,我们首先回想一下,如果f是一个指针,那么*f就是f指向的对象(即在这种情况下的函数打印)。因此,只需将上面循环中每次出现的print替换为*f:

void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}

其他回答

你需要传递一个函数指针。语法有点麻烦,但是一旦你熟悉了它,它真的很强大。

宣言

接受函数形参的函数原型如下所示:

void func ( void (*f)(int) );

这说明形参f将是一个指针,指向一个具有void返回类型并接受单个int形参的函数。下面的函数(print)是一个可以作为参数传递给func的函数示例,因为它是正确的类型:

void print ( int x ) {
  printf("%d\n", x);
}

函数调用

当调用带有函数形参的函数时,传递的值必须是指向函数的指针。使用函数名(不带括号):

func(print);

调用func,将print函数传递给它。

函数体

与任何形参一样,func现在可以在函数体中使用形参的名称来访问形参的值。假设func将应用它传递给数字0-4的函数。首先,考虑直接调用print的循环会是什么样子:

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}

因为func的形参声明说f是指向目标函数的指针的名称,我们首先回想一下,如果f是一个指针,那么*f就是f指向的对象(即在这种情况下的函数打印)。因此,只需将上面循环中每次出现的print替换为*f:

void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}

我将用一个简单的示例代码来解释,该代码将比较函数作为另一个排序函数的参数。 假设我有一个冒泡排序函数,它接受一个自定义比较函数,并使用它来代替固定的if语句。

比较函数

bool compare(int a, int b) {
    return a > b;
}

现在,冒泡排序以另一个函数作为参数来执行比较

冒泡排序函数

void bubble_sort(int arr[], int n, bool (&cmp)(int a, int b)) {

    for (int i = 0;i < n - 1;i++) {
        for (int j = 0;j < (n - 1 - i);j++) {
            
            if (cmp(arr[j], arr[j + 1])) {
                swap(arr[j], arr[j + 1]);
            }
        }
    }
}

最后,main通过传递布尔比较函数作为参数来调用冒泡排序函数。

int main()
{
    int i, n = 10, key = 11;
    int arr[10] = { 20, 22, 18, 8, 12, 3, 6, 12, 11, 15 };

    bubble_sort(arr, n, compare);
    cout<<"Sorted Order"<<endl;
    for (int i = 0;i < n;i++) {
        cout << arr[i] << " ";
    }
}

输出:

Sorted Order
3 6 8 11 12 12 15 18 20 22

函数可以作为函数指针“传递”,根据ISO C11 6.7.6.3p8:“将形参声明为“函数返回类型”应调整为“指向函数返回类型的指针”,如6.3.2.1。”。例如,这个:

void foo(int bar(int, int));

等价于:

void foo(int (*bar)(int, int));

从c++ 11开始,你可以使用函数库以一种简洁和通用的方式来做到这一点。语法是,例如,

std::function<bool (int)>

这里的bool是一个单参数函数的返回类型,该函数的第一个参数是int类型。

下面是一个示例程序:

// g++ test.cpp --std=c++11
#include <functional>

double Combiner(double a, double b, std::function<double (double,double)> func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

不过,有时候使用模板函数会更方便:

// g++ test.cpp --std=c++11

template<class T>
double Combiner(double a, double b, T func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}