![](/img/trans.png)
[英]How do you properly write a function that takes a parameter by reference in 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.