如何在C中传递函数作为参数?

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

753834 次浏览

您需要传递一个函数指针。语法有点麻烦,但一旦您熟悉它,它就非常强大。

宣言

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

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是指针,那么*ff指向的对象(即在这种情况下的函数print)。因此,只需将上面循环中出现的每一次print替换为*f

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

来源

这个问题已经有了定义函数指针的答案,但是它们可能会变得非常混乱,特别是如果你要在你的应用程序中传递它们。为了避免这种不愉快,我建议你将函数指针键入def到更可读的东西中。例如。

typedef void (*functiontype)();

声明一个返回空且不接受参数的函数。要创建指向此类型的函数指针,您现在可以执行以下操作:

void dosomething() { }
functiontype func = &dosomething;func();

对于一个返回int并接受char的函数,你会这样做

typedef int (*functiontype2)(char);

并使用它

int dosomethingwithchar(char a) { return 1; }
functiontype2 func2 = &dosomethingwithcharint result = func2('a');

有一些库可以帮助将函数指针转换为良好的可读类型。升压功能库很棒,非常值得努力!

boost::function<int (char a)> functiontype2;

比上面的要好得多。

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

通过一个函数的地址作为另一个函数的参数如下所示

#include <stdio.h>
void print();void execute(void());
int main(){execute(print); // sends address of printreturn 0;}
void print(){printf("Hello!");}
void execute(void f()) // receive address of print{f();}

我们也可以使用函数指针将函数作为参数传递

#include <stdio.h>
void print();void execute(void (*f)());
int main(){execute(&print); // sends address of printreturn 0;}
void print(){printf("Hello!");}
void execute(void (*f)()) // receive address of print{f();}

函数可以作为函数指针“传递”,按照ISO C116.7.6.3p8:“将参数声明为“函数返回类型”应调整为“指向函数返回类型的指针”,如6.3.2.1。

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

相当于这样:

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

这不是一个真正的函数,而是一段本地化的代码。当然,它不会只传递结果。如果传递给稍后运行的事件调度器,它将不起作用(因为结果是现在计算的,而不是事件发生时)。但如果这就是你试图做的一切,它确实会将你的代码本地化到一个地方。

#include <stdio.h>
int IncMultInt(int a, int b){a++;return a * b;}
int main(int argc, char *argv[])
{int a = 5;int b = 7;
printf("%d * %d = %d\n", a, b, IncMultInt(a, b));
b = 9;
// Create some local code with it's own local variableprintf("%d * %d = %d\n", a, b,  ( { int _a = a+1; _a * b; } ) );
return 0;}

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

比较函数

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

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

冒泡排序功能

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通过传递布尔比较函数作为参数来调用Bubble排序函数。

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 Order3 6 8 11 12 12 15 18 20 22
typedef int function();
function *g(function *f){f();return f;}
int main(void){function f;
function *fn = g(f);
fn();}
int f() { return 0; }