【问题标题】:How do you pass a function as a parameter in C?如何在 C 中将函数作为参数传递?
【发布时间】:2026-02-02 20:45:01
【问题描述】:

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

【问题讨论】:

  • 如果您使用函数/数组作为变量,请始终使用typedef
  • 我们称之为Function pointer
  • @MooingDuck 我不同意你的建议,你的建议缺乏支持结论的理由。我个人更喜欢从不在函数指针上使用typedef,我认为它使代码更清晰易读。
  • @andrewrk:你更喜欢void funcA(void(*funcB)(int))void (*funcA())()而不是typedef void funcB(); void funcA(funcB)funcB funcA()?我看不出有什么好处。
  • 参见标准库函数 qsortbsearch 了解如何完成此操作的示例。

标签: c function pointers syntax parameters


【解决方案1】:
typedef int function();

function *g(function *f)
{
    f();
    return f;
}

int main(void)
{
    function f;

    function *fn = g(f);

    fn();
}

int f() { return 0; }

【讨论】:

  • 这可能是一个很好的解决方案,但它发现自己在低质量答案队列中等待审核。请添加一些讨论来解释解决方案及其工作原理,以使其对本网站的未来读者更有帮助。
【解决方案2】:

我将用一个简单的示例代码进行解释,该代码将compare 函数作为另一个sorting 函数的参数。 假设我有一个冒泡排序函数,它采用自定义比较函数并使用它而不是固定的 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

【讨论】:

    【解决方案3】:

    声明

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

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

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

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

    函数调用

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

    func(print);
    

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

    函数体

    与任何参数一样,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);
      }
    }
    

    Source

    【讨论】:

    • 在您的第一个和最后一个代码示例中,* 不是强制性的。函数参数定义和f 函数调用都可以使用f,就像没有 * 一样。像你一样做这件事可能是个好主意,让参数 f 很明显是一个函数指针。但它经常损害可读性。
    • 参见 [c99, 6.9.1§14] 示例。当然,两者都是正确的,我只是想提一下替代方案。
    • 真的吗?最受好评的答案没有单独提及使用typedef 作为函数指针?抱歉,必须投反对票。
    • @JonathonReinhart ,“typedef”方法有什么优势?这个版本看起来更干净,也缺少额外的语句。这里几乎是首发。
    • @JonathonReinhart 很好发现;应该明确指出,指针 typedef 会混淆代码,因此不应使用。
    【解决方案4】:

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

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

    等价于:

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

    【讨论】:

    • 你引用的是什么文件?有链接吗?
    • 我引用的是 ISO C11 标准。
    【解决方案5】:

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

    #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
    【解决方案6】:

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

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

    【讨论】:

    • 问题是关于C的; C++ 不适用于此处。
    • 这里提到了C++(*.com/questions/6339970/…)的问题,所以我认为这个答案已经到位。
    • 也许这里不应该提到 C++ 的问题,因为这个问题是 C。
    • 当我搜索“c++ function call as parameter”时首先出现了这个问题,所以这个答案在这里很好地发挥了它的作用。
    【解决方案7】:

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

    #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();
    }
    

    【讨论】:

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

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

    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 库很棒,值得付出努力!

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

    比上面的好多了。

    【讨论】:

    • 如果你想“把一个函数指针变成一个类型”,你不需要boost库。只需使用typedef;它更简单,不需要任何额外的库。
    • boost 库不是 C++ 吗?为什么在 C 题中提到它?
    • 对于使用不同调用约定的函数,将调用约定放在第一个 * 之前。像这样:typedef void(__stdcall* funcPtr)(int arg1, int arg2);
    【解决方案9】:

    您需要传递function pointer。语法有点繁琐,但是熟悉了之后真的很强大。

    【讨论】: