Funktionszeiger in der C-Programmierung mit Beispielen
Zeiger bieten C-Funktionen viele Möglichkeiten, bei denen wir auf die Rückgabe eines Werts beschränkt sind. Mit Zeigerparametern können unsere Funktionen jetzt tatsächliche Daten statt einer Kopie von Daten verarbeiten.
Um die tatsächlichen Werte von Variablen zu ändern, übergibt die aufrufende Anweisung Adressen an Zeigerparameter in einer Funktion.
Beispiel für Funktionszeiger
Das nächste Programm vertauscht beispielsweise zwei Werte von zwei:
void swap (int *a, int *b); int main() { int m = 25; int n = 100; printf("m is %d, n is %d\n", m, n); swap(&m, &n); printf("m is %d, n is %d\n", m, n); return 0;} void swap (int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp;} }
Ausgang:
m is 25, n is 100 m is 100, n is 25
Das Programm tauscht die tatsächlichen Variablenwerte aus, da die Funktion über die Adresse auf sie zugreift Zeiger. Hier besprechen wir den Programmablauf:
- Wir deklarieren die Funktion, die für den Austausch der beiden Variablenwerte verantwortlich ist, die zwei ganzzahlige Zeiger als Parameter akzeptiert und beim Aufruf einen beliebigen Wert zurückgibt.
- In der Hauptfunktion deklarieren und initialisieren wir zwei ganzzahlige Variablen ('m' und 'n') und geben dann jeweils ihre Werte aus.
- Wir rufen die Funktion swap() auf, indem wir die Adressen der beiden Variablen als Argumente mit dem kaufmännischen Und-Symbol übergeben. Danach drucken wir die neuen ausgetauschten Werte der Variablen aus.
- Hier definieren wir den Inhalt der Funktion swap(), die zwei Adressen von Integer-Variablen als Parameter verwendet, und deklarieren eine temporäre Integer-Variable, die als drittes Speicherfeld zum Speichern einer der Wertvariablen verwendet wird, die in die zweite Variable eingefügt wird.
- Speichern Sie den Inhalt der ersten Variablen, auf die „a“ zeigt, in der temporären Variablen.
- Speichern Sie die zweite Variable, auf die b zeigt, in der ersten Variablen, auf die a zeigt.
- Aktualisieren Sie die zweite Variable (auf die b zeigt) mit dem Wert der ersten Variablen, der in der temporären Variablen gespeichert ist.
Funktionen mit Array-Parametern
In C können wir ein Array nicht als Wert an eine Funktion übergeben. Während ein Array-Name ein Zeiger (Adresse) ist, übergeben wir einfach einen Array-Namen an eine Funktion, was bedeutet, dass ein Zeiger auf das Array übergeben wird.
Wir betrachten beispielsweise das folgende Programm:
int add_array (int *a, int num_elements); int main() { int Tab[5] = {100, 220, 37, 16, 98}; printf("Total summation is %d\n", add_array(Tab, 5)); return 0;} int add_array (int *p, int size) { int total = 0; int k; for (k = 0; k < size; k++) { total += p[k]; /* it is equivalent to total +=*p ;p++; */} return (total);}
Ausgang:
Total summation is 471
Hier erklären wir den Programmcode mit seinen Details
- Wir deklarieren und definieren die Funktion add_array(), die eine Array-Adresse (Zeiger) mit der Nummer ihrer Elemente als Parameter verwendet und die akkumulierte Gesamtsumme dieser Elemente zurückgibt. Der Zeiger wird verwendet, um die Array-Elemente zu iterieren (unter Verwendung der p[k]-Notation), und wir sammeln die Summe in einer lokalen Variablen, die nach der Iteration des gesamten Elementarrays zurückgegeben wird.
- Wir deklarieren und initialisieren ein Integer-Array mit fünf Integer-Elementen. Wir drucken die Gesamtsumme aus, indem wir den Array-Namen (der als Adresse fungiert) und die Array-Größe an übergeben add_array()aufgerufene Funktion als Argumente.
Funktionen, die ein Array zurückgeben
In C können wir einen Zeiger auf ein Array zurückgeben, wie im folgenden Programm:
#include <stdio.h> int * build_array(); int main() { int *a; a = build_array(); /* get first 5 even numbers */ for (k = 0; k < 5; k++) printf("%d\n", a[k]); return 0;} int * build_array() { static int Tab[5]={1,2,3,4,5}; return (Tab);}
Ausgang:
1 2 3 4 5
Und hier besprechen wir die Programmdetails
- Wir definieren und deklarieren eine Funktion, die eine Array-Adresse zurückgibt, die einen ganzzahligen Wert enthält und keine Argumente akzeptiert.
- Wir deklarieren einen ganzzahligen Zeiger, der das vollständige Array empfängt, das nach dem Aufruf der Funktion erstellt wurde, und geben seinen Inhalt aus, indem wir das gesamte Array mit fünf Elementen iterieren.
Beachten Sie, dass zum Speichern der von der Funktion zurückgegebenen Array-Adresse ein Zeiger und kein Array definiert ist. Beachten Sie auch, dass wir eine lokale Variable, die von einer Funktion zurückgegeben wird, in der Funktion als statisch deklarieren müssen.
Funktionszeiger
Da wir per Definition wissen, dass Zeiger auf eine Adresse an einem beliebigen Speicherort verweisen, können sie auch auf den Anfang von ausführbarem Code als Funktionen im Speicher verweisen.
Ein Zeiger auf eine Funktion wird mit * deklariert. Die allgemeine Aussage seiner Deklaration lautet:
return_type (*function_name)(arguments)
Sie müssen bedenken, dass die Klammern um (*Funktionsname) wichtig sind, denn ohne sie geht der Compiler davon aus, dass der Funktionsname einen Zeiger vom Rückgabetyp zurückgibt.
Nachdem wir den Funktionszeiger definiert haben, müssen wir ihn einer Funktion zuweisen. Das nächste Programm deklariert beispielsweise eine normale Funktion, definiert einen Funktionszeiger, weist den Funktionszeiger der normalen Funktion zu und ruft danach die Funktion über den Zeiger auf:
#include <stdio.h> void Hi_function (int times); /* function */ int main() { void (*function_ptr)(int); /* function pointer Declaration */ function_ptr = Hi_function; /* pointer assignment */ function_ptr (3); /* function call */ return 0;} void Hi_function (int times) { int k; for (k = 0; k < times; k++) printf("Hi\n");}
Ausgang:
Hi Hi Hi
- Wir definieren und deklarieren eine Standardfunktion, die beim Aufruf der Funktion k-mal einen durch den Parameter angegebenen Hi-Text ausgibt
- Wir definieren eine Zeigerfunktion (mit ihrer speziellen Deklaration), die einen ganzzahligen Parameter akzeptiert und nichts zurückgibt.
- Wir initialisieren unsere Zeigerfunktion mit der Hi_function, was bedeutet, dass der Zeiger auf die Hi_function() zeigt.
- Anstatt die Standardfunktion aufzurufen, indem wir den Funktionsnamen mit Argumenten versehen, rufen wir nur die Zeigerfunktion auf, indem wir die Zahl 3 als Argumente übergeben, und das war's!
Beachten Sie, dass der Funktionsname auf die Anfangsadresse des ausführbaren Codes verweist, wie ein Array-Name, der auf sein erstes Element verweist. Daher sind Anweisungen wie function_ptr = &Hi_function und (*funptr)(3) korrekt.
HINWEIS: Es ist nicht wichtig, den Adressoperator & und den Indirektionsoperator * während der Funktionszuweisung und des Funktionsaufrufs einzufügen.
Array von Funktionszeigern
Ein Array von Funktionszeigern kann bei der Entscheidungsfindung eine Schalter- oder if-Anweisungsrolle spielen, wie im nächsten Programm:
#include <stdio.h> int sum(int num1, int num2); int sub(int num1, int num2); int mult(int num1, int num2); int div(int num1, int num2); int main() { int x, y, choice, result; int (*ope[4])(int, int); ope[0] = sum; ope[1] = sub; ope[2] = mult; ope[3] = div; printf("Enter two integer numbers: "); scanf("%d%d", &x, &y); printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: "); scanf("%d", &choice); result = ope[choice](x, y); printf("%d", result); return 0;} int sum(int x, int y) {return(x + y);} int sub(int x, int y) {return(x - y);} int mult(int x, int y) {return(x * y);} int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48 Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2 624
Hier besprechen wir die Programmdetails:
- Wir deklarieren und definieren vier Funktionen die zwei ganzzahlige Argumente annehmen und einen ganzzahligen Wert zurückgeben. Diese Funktionen addieren, subtrahieren, multiplizieren und dividieren die beiden Argumente, die angeben, welche Funktion vom Benutzer aufgerufen wird.
- Wir deklarieren 4 Ganzzahlen, um Operanden, Operationstyp und Ergebnis zu verarbeiten. Außerdem deklarieren wir ein Array mit vier Funktionszeigern. Jeder Funktionszeiger eines Array-Elements nimmt zwei Ganzzahlparameter an und gibt einen Ganzzahlwert zurück.
- Wir weisen jedem Array-Element die bereits deklarierte Funktion zu und initialisieren es. Beispielsweise zeigt das dritte Element, das der dritte Funktionszeiger ist, auf die Multiplikationsoperationsfunktion.
- Wir suchen nach Operanden und Operationstypen, die der Benutzer über die Tastatur eingegeben hat.
- Wir haben das entsprechende Array-Element (Funktionszeiger) mit Argumenten aufgerufen und das von der entsprechenden Funktion generierte Ergebnis gespeichert.
Die Anweisung int (*ope[4])(int, int); definiert das Array von Funktionszeigern. Jedes Array-Element muss die gleichen Parameter und den gleichen Rückgabetyp haben.
Die Anweisung result = ope[choice](x, y); führt die entsprechende Funktion entsprechend der vom Benutzer getroffenen Auswahl aus. Die beiden eingegebenen Ganzzahlen sind die an die Funktion übergebenen Argumente.
Funktionen, die leere Zeiger verwenden
Leere Zeiger werden bei Funktionsdeklarationen verwendet. Wir verwenden einen void *-Rückgabetyp, der die Rückgabe eines beliebigen Typs ermöglicht. Wenn wir davon ausgehen, dass sich unsere Parameter bei der Übergabe an eine Funktion nicht ändern, deklarieren wir sie als const.
Beispielsweise:
void * cube (const void *);
Betrachten Sie das folgende Programm:
#include <stdio.h> void* cube (const void* num); int main() { int x, cube_int; x = 4; cube_int = cube (&x); printf("%d cubed is %d\n", x, cube_int); return 0;} void* cube (const void *num) { int result; result = (*(int *)num) * (*(int *)num) * (*(int *)num); return result;}
Ergebnis:
4 cubed is 64
Hier besprechen wir die Programmdetails:
- Wir definieren und deklarieren eine Funktion, die einen ganzzahligen Wert zurückgibt und eine Adresse einer unveränderlichen Variablen ohne einen bestimmten Datentyp annimmt. Wir berechnen den Würfelwert der Inhaltsvariablen (x), auf die der Num-Zeiger zeigt, und da es sich um einen void-Zeiger handelt, müssen wir ihn unter Verwendung einer bestimmten Notation (*-Datentyp)-Zeiger in einen ganzzahligen Datentyp umwandeln, und wir kehren zurück der Würfelwert.
- Wir deklarieren den Operanden und die Ergebnisvariable. Außerdem initialisieren wir unseren Operanden mit dem Wert „4“.
- Wir rufen die Cube-Funktion auf, indem wir die Operandenadresse übergeben, und verarbeiten den Rückgabewert in der Ergebnisvariablen
Funktionszeiger als Argumente
Eine andere Möglichkeit, einen Funktionszeiger auszunutzen, besteht darin, ihn als Argument an eine andere Funktion zu übergeben, die manchmal „Rückruffunktion“ genannt wird, weil die empfangende Funktion ihn „zurückruft“.
In der Header-Datei stdlib.h verwendet die Quicksort-Funktion „qsort()“ diese Technik, bei der es sich um einen Algorithmus zum Sortieren eines Arrays handelt.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base: void-Zeiger auf das Array.
- size_t num: Die Array-Elementnummer.
- size_t width Die Elementgröße.
- int (*compare (const void *, const void *) : Funktionszeiger bestehend aus zwei Argumenten und gibt 0 zurück, wenn die Argumente denselben Wert haben, <0, wenn arg1 vor arg2 kommt, und >0, wenn arg1 nach arg2 kommt.
Das folgende Programm sortiert ein Array von Ganzzahlen von klein nach groß mithilfe der Funktion qsort():
#include <stdio.h> #include <stdlib.h> int compare (const void *, const void *); int main() { int arr[5] = {52, 14, 50, 48, 13}; int num, width, i; num = sizeof(arr)/sizeof(arr[0]); width = sizeof(arr[0]); qsort((void *)arr, num, width, compare); for (i = 0; i < 5; i++) printf("%d ", arr[ i ]); return 0;} int compare (const void *elem1, const void *elem2) { if ((*(int *)elem1) == (*(int *)elem2)) return 0; else if ((*(int *)elem1) < (*(int *)elem2)) return -1; else return 1;}
Ergebnis:
13 14 48 50 52
Hier besprechen wir die Programmdetails:
- Wir definieren eine Vergleichsfunktion, die aus zwei Argumenten besteht und 0 zurückgibt, wenn die Argumente denselben Wert haben, <0, wenn arg1 vor arg2 kommt, und >0, wenn arg1 nach arg2 kommt. Die Parameter sind ein leerer Zeigertyp, der in den entsprechenden Array-Datentyp umgewandelt wird (ganze Zahl)
- Wir definieren und initialisieren ein Integer-Array. Die Array-Größe wird im gespeichert num Variable und die Größe jedes Array-Elements wird in der Breitenvariablen gespeichert, wobei sizeof() vordefiniert ist C-Operator.
- Wir nennen das qsort Funktion und übergeben Sie den zuvor vom Benutzer definierten Array-Namen, die Größe, die Breite und die Vergleichsfunktion, um unser Array in aufsteigender Reihenfolge zu sortieren. Der Vergleich wird durchgeführt, indem in jeder Iteration zwei Array-Elemente aufgenommen werden, bis das gesamte Array sortiert ist.
- Wir drucken die Array-Elemente aus, um sicherzustellen, dass unser Array gut sortiert ist, indem wir das gesamte Array mit iterieren for-Schleife.