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

and*_*wrk 559 c parameters syntax pointers function

我想创建一个函数来执行由一组数据上的参数传递的函数.如何在C中将函数作为参数传递?

Niy*_*yaz 692

宣言

带函数参数的函数原型如下所示:

void func ( void (*f)(int) );
Run Code Online (Sandbox Code Playgroud)

这表明该参数f将是一个指向函数的指针,该函数具有void返回类型并且采用单个int参数.以下函数(print)是一个函数的示例,可以将其func作为参数传递,因为它是正确的类型:

void print ( int x ) {
  printf("%d\n", x);
}
Run Code Online (Sandbox Code Playgroud)

功能调用

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

func(print);
Run Code Online (Sandbox Code Playgroud)

会调用func,将打印功能传递给它.

功能体

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

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}
Run Code Online (Sandbox Code Playgroud)

因为func's参数声明说这f是指向所需函数的指针的名称,所以我们首先回想一下,如果f是一个指针则指向*f的东西f(即print本例中的函数).因此,只需在上面的循环中替换每次出现的print *f:

void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}
Run Code Online (Sandbox Code Playgroud)

来自http://math.hws.edu/bridgeman/courses/331/f05/handouts/c-c++-notes.html

  • 在您的第一个和最后一个代码示例中,*不是强制性的.函数参数定义和`f`函数调用都可以采用`f`,而不是*.尽管这样做可能是个好主意,但很明显参数f是一个函数指针.但它常常会伤害可读性. (34认同)
  • 有关示例,请参见[c99,6.9.1§14].两者都是正确的,我只想提一下替代方案. (5认同)
  • 真?评价最高的答案没有提到对函数指针使用`typedef`?对不起,不得不投票. (5认同)
  • @JonathonReinhart,'typedef'apprach有什么优势?这个版本看起来更干净,也没有额外的陈述.这里几乎是首发. (3认同)
  • @JonathonReinhart很好地发现了; 应该明确指出,指针typedef会混淆代码,因此不应该使用它. (3认同)

roo*_*roo 120

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

typedef void (*functiontype)();
Run Code Online (Sandbox Code Playgroud)

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

void dosomething() { }

functiontype func = &dosomething;
func();
Run Code Online (Sandbox Code Playgroud)

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

typedef int (*functiontype2)(char);
Run Code Online (Sandbox Code Playgroud)

并使用它

int dosomethingwithchar(char a) { return 1; }

functiontype2 func2 = &dosomethingwithchar
int result = func2('a');
Run Code Online (Sandbox Code Playgroud)

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

boost::function<int (char a)> functiontype2;
Run Code Online (Sandbox Code Playgroud)

比上面好多了.

  • 如果要“将函数指针转换为类型”,则不需要boost库。只需使用`typedef`; 它更简单,不需要任何额外的库。 (3认同)
  • boost库不是C++吗?为什么在C题中提到它? (3认同)

Ric*_*ard 62

从C++ 11开始,您可以使用函数库以简洁和通用的方式执行此操作.语法是,例如,

std::function<bool (int)>
Run Code Online (Sandbox Code Playgroud)

这里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);
}
Run Code Online (Sandbox Code Playgroud)

但有时候,使用模板功能会更方便:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

  • 问题是关于C; C++不适用于此处. (39认同)
  • 当我搜索“c++函数调用作为参数”时,这个问题首先出现,所以无论如何,这个答案在这里很好地达到了它的目的。 (15认同)
  • 这里提到了C++的问题(http://stackoverflow.com/questions/6339970/c-using-function-as-parameter),所以我认为这个答案已经到位. (13认同)
  • 也许这里不应该提到C++的问题,因为这个问题是C. (6认同)

Yog*_*H T 18

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

#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();
}
Run Code Online (Sandbox Code Playgroud)

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

#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();
}
Run Code Online (Sandbox Code Playgroud)

  • 非常好的答案,包含整个代码块(而不是将所有内容切成难以理解的混乱)。您能详细说明一下这两种技术的区别吗? (3认同)
  • 如果我错了,请纠正我,据我所知,函数名称是指针,就像数组名称一样,因此在第一个示例中,您传递函数对象,编译器进行隐式转换,在第二个示例中,您直接传递函数指针,这是显式转换。 (2认同)

dop*_*hen 13

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

void foo(int bar(int, int));
Run Code Online (Sandbox Code Playgroud)

相当于:

void foo(int (*bar)(int, int));
Run Code Online (Sandbox Code Playgroud)

  • 我引用的是 ISO C11 标准。 (2认同)

Hem*_*ara 6

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

比较功能

bool compare(int a, int b) {
    return a > b;
}
Run Code Online (Sandbox Code Playgroud)

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

冒泡排序功能

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]);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,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] << " ";
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Sorted Order
3 6 8 11 12 12 15 18 20 22
Run Code Online (Sandbox Code Playgroud)