ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

N
NAND

宣言

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

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)。因此,只需用 *f 替换上述循环中出现的每个 print:

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 混淆了代码,因此不应使用。
r
roo

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

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;它更简单,不需要任何额外的库。
提升库不是 C++ 吗?为什么在 C 问题中提到它?
对于使用不同调用约定的函数,请将调用约定放在第一个 * 之前。像这样:typedef void(__stdcall* funcPtr)(int arg1, int arg2);
R
Richard

从 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++ (stackoverflow.com/questions/6339970/…) 的问题,所以我认为这个答案已经到位。
也许这里不应该提到 C++ 的问题,因为这个问题是 C。
当我搜索“c++ function call as parameter”时首先出现了这个问题,所以这个答案在这里很好地发挥了它的作用。
Y
Yogeesh H T

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

#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 函数名称是指针,就像数组名称一样,所以在第一个示例中,您传递函数对象并且编译器进行隐式转换,在第二个示例中,您直接传递函数指针,这是显式转换。
d
doppelheathen

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

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

相当于:

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

你引用的是什么文件?有任何链接吗?
我引用了 ISO C11 标准。
s
saint_groceon

您需要传递一个 function pointer。语法有点繁琐,但是一旦你熟悉了它就真的很强大了。


H
Hemanth Kollipara

我将用一个简单的示例代码进行解释,该代码将 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

m
mada
typedef int function();

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

int main(void)
{
    function f;

    function *fn = g(f);

    fn();
}

int f() { return 0; }

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

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

#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