2008-08-13 17 views
452

Ich möchte eine Funktion erstellen, die eine Funktion ausführt, die von einem Parameter auf einer Datengruppe übergeben wird. Wie übergibt man eine Funktion als Parameter in C?Wie übergibt man eine Funktion als Parameter in C?

+9

passieren Wenn Sie Funktionen verwenden/Arrays als Variablen, verwenden Sie immer 'typedef'. –

+2

Wir nennen es [Funktionszeiger] (http://en.wikipedia.org/wiki/Function_pointer#Example_in_C) – AminM

+0

Der Funktionsname sollte ein Ponter für die Funktion sein. Die meisten Leute, die C lernen, decken qsort früher oder später ab, was genau das tut? – mckenzm

Antwort

583

Erklärung

Ein Prototyp für eine Funktion, die eine Funktion Parameter die folgende aussieht nimmt:

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

Diese besagt, dass der Parameter f ein Zeiger auf eine Funktion sein, die eine void hat Rückgabetyp und der einen einzigen int Parameter verwendet. Die folgende Funktion (print) ist ein Beispiel für eine Funktion, die auf func als Parameter übergeben werden konnte, weil es die richtige Art ist:

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

Function Call

Wenn eine Funktion mit einer Funktion aufrufen Parameter muss der übergebene Wert ein Zeiger auf eine Funktion sein. Verwenden Sie den Namen der Funktion (ohne Klammern) dafür:

func(print); 

würde func nennen, vorbei an der Druckfunktion zu.

Funktion Körper

Wie bei jedem Parameter func kann nun den Namen des Parameters verwenden, in den Funktionskörpern den Wert des Parameters zuzugreifen. Nehmen wir an, dass func die übergebene Funktion an die Zahlen 0-4 anwendet. Betrachten wir zuerst, was die Schleife aussehen würde Druck direkt anzurufen:

for (int ctr = 0 ; ctr < 5 ; ctr++) { 
    print(ctr); 
} 

Da func ‚s Parameter Erklärung sagt, dass f ist der Name für einen Zeiger auf die gewünschte Funktion, erinnern wir uns zunächst, dass, wenn f ein Zeiger dann *f ist die Sache, die f verweist auf (dh die Funktion print in diesem Fall). Als Ergebnis ersetzen Sie einfach jedes Vorkommen von Druck in der Schleife oben mit *f:

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

Von http://math.hws.edu/bridgeman/courses/331/f05/handouts/c-c++-notes.html

+27

In Ihrem ersten und letzten Codebeispiel ist das * nicht obligatorisch. Sowohl die Definition des Funktionsparameters als auch der Funktionsaufruf 'f' können' f' nehmen, genauso wie ohne *. Es kann jedoch sinnvoll sein, dies so zu tun, dass der Parameter f ein Funktionszeiger ist. Aber es schmerzt oft die Lesbarkeit. – Gauthier

+4

Beispiele finden Sie in [c99, 6.9.1§14]. Beides stimmt natürlich, ich wollte nur die Alternative erwähnen. – Gauthier

+3

Wirklich? Die am besten bewertete Antwort verwendet keinen einzigen Verweis auf die Verwendung eines 'typedef' für Funktionszeiger. Entschuldigung, muss abstimmen. –

2

Sie müssen eine function pointer übergeben. Die Syntax ist ein wenig mühsam, aber es ist wirklich mächtig, sobald Sie sich damit vertraut machen.

102

Diese Frage hat die Antwort bereits für die Definition Funktionszeiger, jedoch können sie sehr chaotisch, vor allem, wenn Sie werden sie bei Ihrer Bewerbung weitergeben. Um diese Unannehmlichkeit zu vermeiden, würde ich empfehlen, den Funktionszeiger in etwas besser lesbares zu schreiben. Beispielsweise.

typedef void (*functiontype)(); 

Deklariert eine Funktion, die void zurückgibt und keine Argumente annimmt.Um einen Funktionszeiger auf diese Art erstellen Sie jetzt tun können:

void dosomething() { } 

functiontype func = &dosomething; 
func(); 

Für eine Funktion, die einen int zurückgibt und eine char würden Sie

typedef int (*functiontype2)(char); 

tun und es zu benutzen

int dosomethingwithchar(char a) { return 1; } 

functiontype2 func2 = &dosomethingwithchar 
int result = func2('a'); 

Es gibt Bibliotheken, die dabei helfen können, Funktionszeiger in gut lesbare Typen zu verwandeln. Die boost function Bibliothek ist großartig und es lohnt sich die Mühe!

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

ist so viel schöner als die oben genannten.

+0

Wenn Sie einen Funktionszeiger in einen Typ verwandeln wollen, brauchen Sie die Boost-Bibliothek nicht. Verwenden Sie einfach 'typedef'; Es ist einfacher und erfordert keine zusätzlichen Bibliotheken. – wizzwizz4

40

Seit C++ 11 können Sie die functional library verwenden, um dies in einer prägnanten und generischen Art und Weise zu tun. Die Syntax ist, beispielsweise

std::function<bool (int)> 

wo bool der Rückgabetyp ist hier aus einer eintArgumentFunktion, deren erstes Argument vom Typ int.

Ich habe ein Beispielprogramm unten enthalten:

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

Manchmal, wenn es bequemer ist, eine Template-Funktion zu verwenden:

// 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); 
} 
+20

Die Frage ist über C; C++ trifft hier nicht zu. –

+8

Die Frage für C++ (http://stackoverflow.com/questions/6339970/c- using-function-as-parameter) wird hier erwähnt, also denke ich, dass diese Antwort vorhanden ist. –

7

Pass Adresse einer Funktion als Parameter zum anderen Funktion wie unten gezeigt

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

Auch können wir Funktion als Parameter verwendet Funktionszeiger

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