我想创建一个函数,在一组数据上执行由参数传递的函数。如何在 C 中将函数作为参数传递?
9 回答
宣言
带有函数参数的函数原型如下所示:
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
是指向所需函数的指针的名称,我们首先回忆一下 iff
是指针 then*f
是指向的东西f
(即print
本例中的函数)。因此,只需将上面循环中的每次 print 替换为*f
:
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
这个问题已经有了定义函数指针的答案,但是它们可能会变得非常混乱,尤其是当您要在应用程序中传递它们时。为了避免这种不愉快,我建议您将函数指针类型定义为更具可读性的内容。例如。
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 函数库很棒,值得努力!
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 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();
}
您需要传递一个函数指针。语法有点繁琐,但是一旦你熟悉了它就真的很强大了。
我将用一个简单的示例代码进行解释,该代码将一个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
typedef int function();
function *g(function *f)
{
f();
return f;
}
int main(void)
{
function f;
function *fn = g(f);
fn();
}
int f() { return 0; }
它不是一个真正的函数,而是一段本地化的代码。当然,它不会只传递结果。如果传递给稍后运行的事件调度程序,它将不起作用(因为结果是现在计算的,而不是在事件发生时计算的)。但是,如果您只想这样做,它确实会将您的代码本地化到一个地方。
#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;
}