Ich möchte eine Funktion erstellen, die eine per Parameter übergebene Funktion für einen Datensatz ausführt. Wie übergibt man eine Funktion als Parameter in C?
Wie übergibt man eine Funktion als Parameter in C?
andrewrk
Niyaz
Erklärung
Ein Prototyp für eine Funktion, die einen Funktionsparameter übernimmt, sieht wie folgt aus:
void func ( void (*f)(int) );
Diese besagt, dass der Parameter f
wird ein Zeiger auf eine Funktion sein, die a hat void
Rückgabetyp und die eine einzelne nimmt int
Parameter. Die folgende Funktion (print
) ist ein Beispiel für eine Funktion, an die übergeben werden könnte func
als Parameter, weil es der richtige Typ ist:
void print ( int x ) {
printf("%d\n", x);
}
Funktionsaufruf
Beim Aufruf einer Funktion mit einem Funktionsparameter muss der übergebene Wert ein Zeiger auf eine Funktion sein. Verwenden Sie dazu den Namen der Funktion (ohne Klammern):
func(print);
würde nennen func
und übergibt ihm die Druckfunktion.
Funktionskörper
Wie bei jedem Parameter, func
kann nun den Namen des Parameters im Funktionsrumpf verwenden, um auf den Wert des Parameters zuzugreifen. Sagen wir das func
wendet die übergebene Funktion auf die Zahlen 0-4 an. Überlegen Sie sich zunächst, wie die Schleife aussehen würde, um print direkt aufzurufen:
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
print(ctr);
}
Seit func
Das sagt die Parameterdeklaration von f
der Name für einen Zeiger auf die gewünschte Funktion ist, erinnern wir uns zunächst daran, dass if f
ist dann ein Zeiger *f
ist das Ding f
zeigt auf (dh die Funktion print
in diesem Fall). Ersetzen Sie daher einfach jedes Vorkommen von print in der obigen Schleife durch *f
:
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
-
In Ihrem ersten und letzten Codebeispiel ist das * nicht obligatorisch. Sowohl die Funktionsparameterdefinition als auch die
f
Funktionsaufruf annehmen kannf
genauso wie ohne *. Es könnte jedoch eine gute Idee sein, es so zu machen, wie Sie es tun, um deutlich zu machen, dass Parameter f ein Funktionszeiger ist. Aber es schadet oft der Lesbarkeit.– Gauthier
22. Februar 2012 um 12:52 Uhr
-
Sehen [c99, 6.9.1§14] zum Beispiel. Beides ist natürlich richtig, ich wollte nur die Alternative erwähnen.
– Gauthier
22. Februar 2012 um 12:58 Uhr
-
Wirklich? Die am besten bewertete Antwort enthält keinen einzigen Hinweis auf die Verwendung von a
typedef
für Funktionszeiger? Entschuldigung, muss abstimmen.– Jonathon Reinhart
1. Oktober 2014 um 8:03 Uhr
-
@ JonathonReinhart, was wären Vorteile mit dem ‘typedef’-Ansatz? Diese Version sieht jedoch viel sauberer aus und es fehlen auch zusätzliche Anweisungen. ziemlich viel Starter hier.
– Abhinav Gauniyal
22. Februar 2015 um 7:04 Uhr
-
@JonathonReinhart gut gesehen; Es sollte ausdrücklich darauf hingewiesen werden, dass Pointer Typedefs den Code verschleiern und daher nicht verwendet werden sollten.
– MM
24. November 2015 um 2:39 Uhr
Zimmer
Diese Frage hat bereits die Antwort für das Definieren von Funktionszeigern, aber sie können sehr chaotisch werden, besonders wenn Sie sie in Ihrer Anwendung herumreichen. Um diese Unannehmlichkeiten zu vermeiden, würde ich empfehlen, dass Sie den Funktionszeiger in etwas Lesbareres schreiben. Zum Beispiel.
typedef void (*functiontype)();
Deklariert eine Funktion, die void zurückgibt und keine Argumente akzeptiert. Um einen Funktionszeiger auf diesen Typ zu erstellen, können Sie jetzt Folgendes tun:
void dosomething() { }
functiontype func = &dosomething;
func();
Für eine Funktion, die ein int zurückgibt und ein char akzeptiert, würden Sie dies tun
typedef int (*functiontype2)(char);
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 umzuwandeln. Das Boost-Funktion Die Bibliothek ist großartig und die Mühe wert!
boost::function<int (char a)> functiontype2;
ist so viel schöner als die oben.
-
Wenn Sie einen Funktionszeiger in einen Typ umwandeln möchten, benötigen Sie die Boost-Bibliothek nicht. Benutz einfach
typedef
; es ist einfacher und erfordert keine zusätzlichen Bibliotheken.– wizzwizz4
9. April 2016 um 11:50 Uhr
-
Ist die Boost-Bibliothek nicht C++? Warum erwähnen Sie es in einer C-Frage?
– 12431234123412341234123
2. Oktober 2020 um 12:48 Uhr
-
Platzieren Sie für Funktionen, die eine andere Aufrufkonvention verwenden, die Aufrufkonvention vor dem ersten *. So was:
typedef void(__stdcall* funcPtr)(int arg1, int arg2);
– Dwedit
19. September 2021 um 18:04 Uhr
Richard
Seit C++11 können Sie die funktionale Bibliothek um dies kurz und generisch zu tun. Die Syntax ist zB
std::function<bool (int)>
wo bool
ist hier der Rückgabetyp einer Funktion mit einem Argument, deren erstes Argument vom Typ ist int
.
Ich habe unten ein Beispielprogramm eingefügt:
// 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 ist es jedoch bequemer, eine Vorlagenfunktion 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);
}
-
Die Frage betrifft C; C++ kommt hier nicht zum Einsatz.
– Superkat
29. Oktober 2015 um 23:44 Uhr
-
Auf die Frage für C ++ (stackoverflow.com/questions/6339970/…) wird hier verwiesen, daher denke ich, dass diese Antwort vorhanden ist.
– mr_T
24. März 2016 um 11:00 Uhr
-
Vielleicht sollte die Frage für C++ hier nicht erwähnt werden, weil diese Frage für C ist.
– Michael Fulton
19. April 2018 um 16:22 Uhr
-
Diese Frage tauchte zuerst auf, als ich nach “C++-Funktionsaufruf als Parameter” suchte, also erfüllt diese Antwort hier trotzdem ihren Zweck.
– ufoxDan
7. November 2019 um 21:50 Uhr
Yogeesh HT
Passieren Adresse einer Funktion als Parameter für eine andere Funktion Wie nachfolgend dargestellt
#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();
}
Wir können die Funktion auch als Parameter mit übergeben 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();
}
Doppelheide
Funktionen können als Funktionszeiger “übergeben” werden, gemäß ISO C11 6.7.6.3p8: “Eine Deklaration eines Parameters als „Funktionsrückgabetyp“ soll angepasst werden an „Zeiger auf Funktionsrückgabetyp“, wie in 6.3.2.1. “. Zum Beispiel dies:
void foo(int bar(int, int));
ist äquivalent dazu:
void foo(int (*bar)(int, int));
-
Aus welchem Dokument zitierst du? Irgendein Link dazu?
– Rafael Eyng
29. Januar 2020 um 21:41 Uhr
-
Ich zitiere aus dem ISO C11-Standard.
– Doppelheide
5. Februar 2020 um 12:57 Uhr
Ich werde es mit einem einfachen Beispielcode erklären, der a dauert compare
fungieren als Parameter für einen anderen sorting
Funktion. Nehmen wir an, ich habe eine Bubble-Sort-Funktion, die eine benutzerdefinierte Vergleichsfunktion verwendet und sie anstelle einer festen if-Anweisung verwendet.
Vergleichsfunktion
bool compare(int a, int b) {
return a > b;
}
Jetzt die Bubble-Sortierung, die eine andere Funktion als Parameter zum Durchführen des Vergleichs verwendet
Bubble-Sort-Funktion
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]);
}
}
}
}
Endlich, das main
die die Bubblesort-Funktion aufruft, indem sie die boolesche Vergleichsfunktion als Argument übergibt.
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] << " ";
}
}
Ausgabe:
Sorted Order
3 6 8 11 12 12 15 18 20 22
-
Aus welchem Dokument zitierst du? Irgendein Link dazu?
– Rafael Eyng
29. Januar 2020 um 21:41 Uhr
-
Ich zitiere aus dem ISO C11-Standard.
– Doppelheide
5. Februar 2020 um 12:57 Uhr
saint_groceon
Sie müssen a bestehen Funktionszeiger. Die Syntax ist ein wenig umständlich, aber sie ist wirklich mächtig, sobald Sie sich damit vertraut gemacht haben.
Wenn Sie Funktionen/Arrays als Variablen verwenden, verwenden Sie IMMER
typedef
.– Muhende Ente
13. Januar 2014 um 21:09 Uhr
Wir nennen es Funktionszeiger
– AminM
1. April 2014 um 11:11 Uhr
@MooingDuck Ich bin mit Ihrem Vorschlag nicht einverstanden, und Ihrem Vorschlag fehlt die Begründung, um die Schlussfolgerung zu stützen. Ich persönlich bevorzuge noch nie die Verwendung von typedef für Funktionszeiger, und ich denke, es macht den Code klarer und leichter lesbar.
– andrewrk
16. Dezember 2015 um 22:26 Uhr
@andrewrk: Du bevorzugst
void funcA(void(*funcB)(int))
undvoid (*funcA())()
zutypedef void funcB(); void funcA(funcB)
undfuncB funcA()
? Ich sehe den Vorteil nicht.– Muhende Ente
16. Dezember 2015 um 23:27 Uhr
Siehe die Standardbibliotheksfunktionen
qsort
undbsearch
für Beispiele, wie dies gemacht wird.– Bob Jarvis – Слава Україні
15. Februar 2021 um 12:45 Uhr