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


615

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


12
如果您将函数/数组用作变量,则始终使用typedef
Mooing Duck 2014年

3
我们称它为函数指针
AminM

函数名称应该是该函数的缩写。大多数人早晚学习C Cover qsort到底是什么?
mckenzm 2015年

5
@MooingDuck我不同意您的建议,您的建议缺乏支持该结论的理由。我个人更喜欢永远不要在函数指针上使用typedef,并且我认为它使代码更清晰,更易于阅读。
andrewrk

2
@andrewrk:你喜欢void funcA(void(*funcB)(int))void (*funcA())()typedef void funcB(); void funcA(funcB)funcB funcA()?我没有看到上行空间。
Mooing Duck 2015年

Answers:


746

宣言

具有函数参数的函数原型如下所示:

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本例中的函数)。结果,只需将上面循环中所有出现的print替换为*f

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

资源


40
在您的第一个和最后一个代码示例中,*不是强制性的。不带* 的函数参数定义和f函数调用都可以f照原样使用。最好像您一样这样做,以使参数f很明显是一个函数指针。但这经常会损害可读性。
Gauthier

5
有关示例,请参见[c99,6.9.1§14]。当然,两者都是正确的,我只想提及替代方法。
Gauthier

6
真?最受好评的答案没有单独提及使用typedeffor函数指针吗?抱歉,必须拒绝投票。
乔纳森·莱因哈特

3
@JonathonReinhart,使用'typedef'方法有什么好处?这个版本看起来更干净,并且也没有多余的声明。这里几乎是入门者。
Abhinav Gauniyal

3
@JonathonReinhart被发现;应当明确指出,指针typedef会使代码模糊,因此不应使用它。
MM

129

这个问题已经有了定义函数指针的答案,但是它们会变得非常混乱,特别是如果您要在应用程序中传递它们。为避免这种不愉快,我建议您将函数指针类型化为更易读的内容。例如。

typedef void (*functiontype)();

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

void dosomething() { }

functiontype func = &dosomething;
func();

对于返回int并接受char的函数,您可以这样做

typedef int (*functiontype2)(char);

并使用它

int dosomethingwithchar(char a) { return 1; }

functiontype2 func2 = &dosomethingwithchar
int result = func2('a');

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

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

比上面的要好得多。


4
如果要“将函数指针转换为类型”,则不需要boost库。随便用typedef; 它更简单,不需要任何额外的库。
wizzwizz4 '04

72

从C ++ 11开始,您可以使用功能库以简洁通用的方式进行此操作。语法例如是

std::function<bool (int)>

这里bool是第一个参数为type的单参数函数的返回类型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);
}

43
问题是关于C的。C ++不适用于此处。
超级猫

16
有关C ++的问题(stackoverflow.com/questions/6339970/…),请参见此处,因此我认为此答案已经存在。
mr_T

8
也许对于C ++的问题不应该被称为这里,因为这个问题的是C.
迈克尔·富尔顿

5
当我搜索“作为参数的c ++函数调用”时,首先出现了这个问题,因此无论如何,此答案都可以很好地达到目的。
ufoxDan

24

传递函数作为参数传递给另一个函数的地址如下所示

#include <stdio.h>

void print();
void execute(void());

int main()
{
    execute(print); // sends address of print
    return 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 print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void (*f)()) // receive address of print
{
    f();
}

很好的答案,带有完整的代码块(而不是将所有内容切成难以理解的混乱)。您能否详细说明两种技术的区别?
拉斐尔·埃

5

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

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

等效于此:

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

您引用什么文件?任何链接吗?
拉斐尔·伊恩

1
我引用的是ISO C11标准。
doppelheathen


-2

它不是真正的功能,但是是本地化的代码。当然,它不会仅将结果传递给代码。如果传递给事件分派器以在以后运行(因为结果是现在计算的,而不是事件发生时才计算的),它将无法正常工作。但是,如果您要这样做,它将把代码本地化到一个地方。

#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 variable
    printf("%d * %d = %d\n", a, b,  ( { int _a = a+1; _a * b; } ) );

    return 0;
}

您只是在调用一个函数。您将如何通过其他一些功能来代替IncMultInt
Tejas Pendse
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.