2008-08-13 53 views
452

Chcę utworzyć funkcję, która wykonuje funkcję przekazaną przez parametr na zestawie danych. W jaki sposób przekazujesz funkcję jako parametr w C?Jak przekazać funkcję jako parametr w C?

+9

Jeśli używasz funkcji/tablice jako zmienne, zawsze używaj 'typedef'. –

+2

Nazywamy to [wskaźnikiem funkcji] (http://en.wikipedia.org/wiki/Function_pointer#Example_in_C) – AminM

+0

Nazwa funkcji powinna być ponumerowana do funkcji. Większość ludzi uczących się C obejmuje qsort wcześniej czy później, co robi dokładnie to? – mckenzm

Odpowiedz

583

Deklaracja

Prototyp dla funkcji, która przyjmuje parametr funkcji wygląda następująco:

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

ta stwierdza, że ​​parametr f będzie wskaźnik do funkcji, która ma void typ zwracany, który przyjmuje pojedynczy parametr int. Poniższa funkcja (print) jest przykładem funkcji, które mogą być przekazywane do func jako parametr, ponieważ jest to właściwy typ:

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

Funkcja połączeń

Przy wywołaniu funkcji z funkcją parametr, przekazana wartość musi być wskaźnikiem do funkcji. Użyj nazwy funkcja (bez nawiasów) dla tego:

func(print); 

nazwałbym func, przekazując funkcję drukowania do niego.

funkcjonowania organizmu

Jak w przypadku każdego parametru func mogą teraz używać nazwy parametru w ciele funkcji, aby uzyskać dostęp do wartości parametru. Powiedzmy, że func zastosuje funkcję, która jest przekazywana do liczb 0-4. Zastanów się, po pierwsze, co pętla będzie wyglądać zadzwonić do druku bezpośrednio:

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

Od func „s deklaracja parametr mówi, że f to nazwa wskaźnika do żądanej funkcji, możemy przypomnieć najpierw, że jeśli f jest wskaźnik, a następnie *f jest rzeczą, na którą wskazuje f (tj. funkcja print w tym przypadku). W rezultacie, po prostu zastąpić każde wystąpienie drukiem w pętli powyżej *f:

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

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

+27

W pierwszym i ostatnim przykładzie kodu, * nie jest obowiązkowe. Zarówno definicja parametru funkcji, jak i wywołanie funkcji 'f' mogą zająć' f' tak jak jest bez *. Dobrym pomysłem jest zrobienie tego tak jak Ty, aby było oczywiste, że parametr f jest wskaźnikiem funkcji. Ale dość często boli czytelność. – Gauthier

+4

Zobacz przykłady [c99, 6.9.1§14]. Oba są poprawne, chciałem tylko wspomnieć o alternatywie. – Gauthier

+3

Naprawdę? Najwyżej oceniona odpowiedź nie zawiera pojedynczego odniesienia do używania "typedef" do wskaźników funkcji? Przepraszam, muszę głosować w dół. –

2

Musisz podać function pointer. Składnia jest trochę uciążliwa, ale po zapoznaniu się z nią jest naprawdę potężna.

102

To pytanie ma już odpowiedź na zdefiniowanie wskaźników funkcji, jednak mogą one uzyskać bardzo brudny, szczególnie jeśli przekażesz je wokół swojej aplikacji. Aby uniknąć tego nieprzyjemności, poleciłbym wpisanie wskaźnika funkcji w coś bardziej czytelnego. Na przykład.

typedef void (*functiontype)(); 

Deklaracja funkcji, która zwraca void i nie przyjmuje żadnych argumentów.Aby utworzyć wskaźnik funkcji tego typu można teraz zrobić:

void dosomething() { } 

functiontype func = &dosomething; 
func(); 

Dla funkcji zwracającej int i trwa char byś zrobił

typedef int (*functiontype2)(char); 

i użyć go

int dosomethingwithchar(char a) { return 1; } 

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

Istnieją biblioteki, które mogą pomóc w przekształceniu wskaźników funkcji w ładne, czytelne typy. Biblioteka boost function jest świetna i jest warta wysiłku!

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

jest o wiele ładniejszy niż powyższy.

+0

Jeśli chcesz "zamienić wskaźnik funkcji w typ", nie potrzebujesz biblioteki boost. Po prostu użyj 'typedef'; jest prostszy i nie wymaga żadnych dodatkowych bibliotek. – wizzwizz4

40

Od C++ 11 można użyć functional library, aby zrobić to w sposób zwięzły i ogólny. Składnia jest, na przykład,

std::function<bool (int)> 

gdzie bool jest typ wrócimy tu o funkcję jeden argument w pierwszy argument jest typu int.

mam włączone przykładowy program poniżej:

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

Czasem jednak wygodniej jest użyć funkcji szablonu:

// 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

Pytanie dotyczy C; C++ nie ma tutaj zastosowania. –

+8

Pytanie do C++ (http://stackoverflow.com/questions/6339970/c-using-function-as-parametr) jest tutaj opisane, więc myślę, że ta odpowiedź jest na miejscu. –

7

przepustkę adresu funkcji jako parametr do innej funkcja jak pokazano poniżej

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

Również możemy przekazać funkcję jako parametr używając funkcyjny wskaźnik

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