簡體   English   中英

你如何在C中將函數作為參數傳遞?

[英]How do you pass a function as a parameter in C?

我想創建一個函數,該函數對一組數據執行通過參數傳遞的函數。 你如何在C中將函數作為參數傳遞?

宣言

帶有函數參數的函數原型如下所示:

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替換上面循環中出現的每次打印:

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

來源

這個問題已經有了定義函數指針的答案,但是它們可能會變得非常混亂,特別是如果你要在你的應用程序中傳遞它們。 為了避免這種不愉快,我建議您將函數指針 typedef 為更具可讀性的內容。 例如。

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

函數可以作為函數指針“傳遞”,根據 ISO C11 6.7.6.3p8:“將參數聲明為“函數返回類型”應調整為“指向函數返回類型的指針” ,如 6.3 .2.1. ". 例如,這個:

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

相當於:

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

您需要傳遞一個函數指針 語法有點麻煩,但是一旦你熟悉了它就真的很強大。

我將用一個簡單的示例代碼來解釋,該代碼將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

它不是真正的函數,而是一段本地化的代碼。 當然,它不會僅通過結果來傳遞代碼。 如果傳遞給稍后運行的事件調度程序,它將不起作用(因為現在計算結果而不是事件發生時)。 但它確實將您的代碼本地化到一個地方,如果這就是您想要做的。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM