Nazwa funkcji powinna być ponter do funkcji. Większość osób uczących się C prędzej czy później obejmuje qsort, co to dokładnie robi?
mckenzm
5
@MooingDuck Nie zgadzam się z twoją sugestią, a twojej sugestii brakuje uzasadnienia na poparcie wniosku. Osobiście wolę nigdy nie używać typedef do wskaźników funkcji i myślę, że dzięki temu kod jest bardziej przejrzysty i łatwiejszy do odczytania.
Prototyp funkcji, która przyjmuje parametr funkcji, wygląda następująco:
void func (void(*f)(int));
Oznacza to, że parametr fbędzie wskaźnikiem do funkcji, która ma voidtyp zwracany i która przyjmuje pojedynczy intparametr. Następująca funkcja ( print) jest przykładem funkcji, do której można przekazać funcjako parametr, ponieważ jest to właściwy typ:
void print (int x ){
printf("%d\n", x);}
Wywołanie funkcji
Podczas wywoływania funkcji z parametrem funkcji przekazywana wartość musi być wskaźnikiem funkcji. Użyj do tego nazwy funkcji (bez nawiasów):
func(print);
zadzwoni func, przekazując mu funkcję drukowania.
Funkcja Body
Jak w przypadku każdego parametru, funcmożna teraz używać nazwy parametru w treści funkcji, aby uzyskać dostęp do wartości parametru. Powiedzmy, że funczastosuje funkcję, która zostanie przekazana do liczb 0-4. Najpierw zastanów się, jak pętla mogłaby wyglądać tak, aby wywołać print:
for(int ctr =0; ctr <5; ctr++){
print(ctr);}
Ponieważ funcdeklaracja parametru mówi, że fjest to nazwa wskaźnika do żądanej funkcji, najpierw przypominamy sobie, że jeśli fjest wskaźnikiem, *fto rzecz, która fwskazuje (tj. Funkcja printw tym przypadku). W rezultacie po prostu zamień każde wystąpienie wydruku w powyższej pętli na *f:
W pierwszym i ostatnim przykładzie kodu * nie jest obowiązkowe. Zarówno definicja parametru funkcji, jak i fwywołanie funkcji mogą trwać ftak samo, jak bez *. Dobrym pomysłem może być zrobienie tego tak, jak robisz, aby było oczywiste, że parametr f jest wskaźnikiem funkcji. Ale dość często szkodzi to czytelności.
Gauthier
5
Przykłady patrz [c99, 6.9.1§14]. Oba są oczywiście poprawne, chciałem tylko wspomnieć o alternatywie.
Gauthier
6
Naprawdę? Najwyżej oceniana odpowiedź nie odnosi się ani do używania typedefwskaźników funkcji? Przepraszam, muszę głosować w dół.
Jonathon Reinhart
3
@JonathonReinhart, jakie byłyby zalety appracha „typedef”? Ta wersja wygląda jednak na znacznie czystszą i brakuje w niej również dodatkowych instrukcji. właściwie starter tutaj.
Abhinav Gauniyal
3
@JonathonReinhart dobrze zauważony; należy wyraźnie zauważyć, że wskaźnik typedefs zaciemnia kod i dlatego nie powinien być używany.
MM
129
To pytanie ma już odpowiedź na zdefiniowanie wskaźników funkcji, jednak mogą stać się bardzo nieuporządkowane, szczególnie jeśli zamierzasz przekazywać je wokół aplikacji. Aby uniknąć tej nieprzyjemności, polecam wpisanie wskaźnika funkcji w coś bardziej czytelnego. Na przykład.
typedefvoid(*functiontype)();
Deklaruje funkcję, która zwraca void i nie przyjmuje żadnych argumentów. Aby utworzyć wskaźnik funkcji do tego typu, możesz teraz:
Dla funkcji, która zwraca wartość int i przyjmuje znak char, zrobiłbyś to
typedefint(*functiontype2)(char);
i z niego korzystać
int dosomethingwithchar(char a){return1;}
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. Funkcja Boost biblioteka jest wielki i jest warte wysiłku!
Jeśli chcesz „zmienić wskaźnik funkcji na typ”, nie potrzebujesz biblioteki doładowań. Po prostu użyj typedef; jest prostszy i nie wymaga żadnych dodatkowych bibliotek.
wizzwizz4
72
Od wersji C ++ 11 możesz użyć biblioteki funkcjonalnej, aby zrobić to w zwięzły i ogólny sposób. Składnia jest np.
std::function<bool(int)>
gdzie booljest tutaj typ zwracany funkcji jednoparametrowej, której pierwszy argument jest typu int.
Bardzo ładna odpowiedź, z całymi blokami kodu (zamiast krojenia wszystkiego w niezrozumiały bałagan). Czy mógłbyś rozwinąć różnice między obiema technikami?
Rafael Eyng
5
Funkcje można „przekazać” jako wskaźniki funkcji, zgodnie z ISO C11 6.7.6.3p8: „ Deklarację parametru jako„ typu zwracającego funkcję ”należy ustawić na„ wskaźnik do typu zwracającego funkcję ” , jak w 6.3 .2.1. ”. Na przykład:
To nie jest tak naprawdę funkcja, ale jest zlokalizowanym fragmentem kodu. Oczywiście nie przekazuje kodu tylko wyniku. Nie zadziała, jeśli zostanie przekazany do programu rozsyłającego zdarzenia, który zostanie uruchomiony w późniejszym czasie (ponieważ wynik jest obliczany teraz, a nie w momencie wystąpienia zdarzenia). Ale lokalizuje kod w jednym miejscu, jeśli to wszystko, co próbujesz zrobić.
#include<stdio.h>intIncMultInt(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;}));return0;}
typedef
.void funcA(void(*funcB)(int))
ivoid (*funcA())()
dotypedef void funcB(); void funcA(funcB)
ifuncB funcA()
? Nie widzę plusów.Odpowiedzi:
Deklaracja
Prototyp funkcji, która przyjmuje parametr funkcji, wygląda następująco:
Oznacza to, że parametr
f
będzie wskaźnikiem do funkcji, która mavoid
typ zwracany i która przyjmuje pojedynczyint
parametr. Następująca funkcja (print
) jest przykładem funkcji, do której można przekazaćfunc
jako parametr, ponieważ jest to właściwy typ:Wywołanie funkcji
Podczas wywoływania funkcji z parametrem funkcji przekazywana wartość musi być wskaźnikiem funkcji. Użyj do tego nazwy funkcji (bez nawiasów):
zadzwoni
func
, przekazując mu funkcję drukowania.Funkcja Body
Jak w przypadku każdego parametru,
func
można teraz używać nazwy parametru w treści funkcji, aby uzyskać dostęp do wartości parametru. Powiedzmy, żefunc
zastosuje funkcję, która zostanie przekazana do liczb 0-4. Najpierw zastanów się, jak pętla mogłaby wyglądać tak, aby wywołać print:Ponieważ
func
deklaracja parametru mówi, żef
jest to nazwa wskaźnika do żądanej funkcji, najpierw przypominamy sobie, że jeślif
jest wskaźnikiem,*f
to rzecz, któraf
wskazuje (tj. Funkcjaprint
w tym przypadku). W rezultacie po prostu zamień każde wystąpienie wydruku w powyższej pętli na*f
:Źródło
źródło
f
wywołanie funkcji mogą trwaćf
tak samo, jak bez *. Dobrym pomysłem może być zrobienie tego tak, jak robisz, aby było oczywiste, że parametr f jest wskaźnikiem funkcji. Ale dość często szkodzi to czytelności.typedef
wskaźników funkcji? Przepraszam, muszę głosować w dół.To pytanie ma już odpowiedź na zdefiniowanie wskaźników funkcji, jednak mogą stać się bardzo nieuporządkowane, szczególnie jeśli zamierzasz przekazywać je wokół aplikacji. Aby uniknąć tej nieprzyjemności, polecam wpisanie wskaźnika funkcji w coś bardziej czytelnego. Na przykład.
Deklaruje funkcję, która zwraca void i nie przyjmuje żadnych argumentów. Aby utworzyć wskaźnik funkcji do tego typu, możesz teraz:
Dla funkcji, która zwraca wartość int i przyjmuje znak char, zrobiłbyś to
i z niego korzystać
Istnieją biblioteki, które mogą pomóc w przekształceniu wskaźników funkcji w ładne, czytelne typy. Funkcja Boost biblioteka jest wielki i jest warte wysiłku!
jest o wiele ładniejszy niż wyżej.
źródło
typedef
; jest prostszy i nie wymaga żadnych dodatkowych bibliotek.Od wersji C ++ 11 możesz użyć biblioteki funkcjonalnej, aby zrobić to w zwięzły i ogólny sposób. Składnia jest np.
gdzie
bool
jest tutaj typ zwracany funkcji jednoparametrowej, której pierwszy argument jest typuint
.Poniżej zamieściłem przykładowy program:
Czasami jednak wygodniej jest użyć funkcji szablonu:
źródło
Przekaż adres funkcji jako parametru do innej funkcji, jak pokazano poniżej
Możemy również przekazać funkcję jako parametr za pomocą wskaźnika funkcji
źródło
Funkcje można „przekazać” jako wskaźniki funkcji, zgodnie z ISO C11 6.7.6.3p8: „ Deklarację parametru jako„ typu zwracającego funkcję ”należy ustawić na„ wskaźnik do typu zwracającego funkcję ” , jak w 6.3 .2.1. ”. Na przykład:
jest równoważne z tym:
źródło
Musisz przekazać wskaźnik funkcji . Składnia jest trochę nieporęczna, ale jest naprawdę potężna, gdy się z nią zapoznasz.
źródło
To nie jest tak naprawdę funkcja, ale jest zlokalizowanym fragmentem kodu. Oczywiście nie przekazuje kodu tylko wyniku. Nie zadziała, jeśli zostanie przekazany do programu rozsyłającego zdarzenia, który zostanie uruchomiony w późniejszym czasie (ponieważ wynik jest obliczany teraz, a nie w momencie wystąpienia zdarzenia). Ale lokalizuje kod w jednym miejscu, jeśli to wszystko, co próbujesz zrobić.
źródło
IncMultInt
?