Functies Pointers in C-programmering met voorbeelden
Pointers bieden enorme mogelijkheden voor 'C'-functies, waarbij we beperkt zijn tot het retourneren van één waarde. Met pointerparameters kunnen onze functies nu daadwerkelijke gegevens verwerken in plaats van een kopie van gegevens.
Om de werkelijke waarden van variabelen te wijzigen, geeft de aanroepende instructie adressen door aan pointerparameters in een functie.
Functies Aanwijzers Voorbeeld
Het volgende programma wisselt bijvoorbeeld twee waarden van twee om:
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;} }
Output:
m is 25, n is 100 m is 100, n is 25
Het programma wisselt de werkelijke waarden van de variabelen om, omdat de functie deze benadert via adres met behulp van wijzer. Hier bespreken we het programmaproces:
- We verklaren de functie die verantwoordelijk is voor het verwisselen van de twee variabelewaarden, die twee integer-pointers als parameters neemt en elke waarde retourneert wanneer deze wordt aangeroepen.
- In de hoofdfunctie declareren en initialiseren we twee gehele variabelen ('m' en 'n'), waarna we respectievelijk hun waarden afdrukken.
- We roepen de functie swap() aan door het adres van de twee variabelen door te geven als argumenten met behulp van het ampersand-symbool. Daarna drukken we de nieuwe verwisselde waarden van variabelen af.
- Hier definiëren we de inhoud van de swap()-functie die twee gehele variabele-adressen als parameters neemt en een tijdelijke gehele variabele declareert die wordt gebruikt als derde opslagbox om een van de waardevariabelen op te slaan die in de tweede variabele wordt geplaatst.
- Sla de inhoud op van de eerste variabele waarnaar wordt verwezen met 'a' in de tijdelijke variabele.
- Sla de tweede variabele op die wordt aangegeven door b in de eerste variabele die wordt aangegeven door a.
- Werk de tweede variabele bij (aangeduid door b) met de waarde van de eerste variabele die is opgeslagen in de tijdelijke variabele.
Functies met arrayparameters
In C kunnen we een array niet op waarde doorgeven aan een functie. Terwijl een arraynaam een pointer (adres) is, geven we dus gewoon een arraynaam door aan een functie, wat betekent dat we een pointer naar de array moeten doorgeven.
We beschouwen bijvoorbeeld het volgende programma:
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);}
Output:
Total summation is 471
Hier zullen we de programmacode met zijn details uitleggen
- We declareren en definiëren de functie add_array() die een arrayadres (pointer) met zijn elementennummer als parameters gebruikt en de totale geaccumuleerde som van deze elementen retourneert. De pointer wordt gebruikt om de array-elementen te itereren (met behulp van de p[k]-notatie), en we accumuleren de sommatie in een lokale variabele die zal worden geretourneerd na het itereren van de gehele elementarray.
- We declareren en initialiseren een integer-array met vijf integer-elementen. We drukken de totale optelling af door de arraynaam (die als adres fungeert) en de arraygrootte door te geven aan de add_array()functie genoemd als argumenten.
Functies die een array retourneren
In C kunnen we een aanwijzer naar een array retourneren, zoals in het volgende programma:
#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);}
Output:
1 2 3 4 5
En hier zullen we de programmadetails bespreken
- We definiëren en declareren een functie die een arrayadres retourneert dat een geheel getal bevat en geen argumenten heeft aangenomen.
- We declareren een integer-pointer die de volledige array ontvangt die is gebouwd nadat de functie is aangeroepen en we drukken de inhoud ervan af door de volledige array met vijf elementen te herhalen.
Merk op dat een pointer, en geen array, is gedefinieerd om het array-adres op te slaan dat door de functie wordt geretourneerd. Merk ook op dat wanneer een lokale variabele wordt geretourneerd door een functie, we deze als statisch moeten declareren in de functie.
Functiewijzers
Omdat we per definitie weten dat pointers naar een adres op elke geheugenlocatie verwijzen, kunnen ze ook naar het begin van uitvoerbare code verwijzen als functies in het geheugen.
Een verwijzing naar een functie wordt gedeclareerd met de *, de algemene verklaring van de declaratie is:
return_type (*function_name)(arguments)
Je moet niet vergeten dat de haakjes rond (*functie_naam) belangrijk zijn, omdat de compiler zonder deze haakjes zal denken dat de functie_naam een pointer van return_type retourneert.
Nadat we de functiepointer hebben gedefinieerd, moeten we deze toewijzen aan een functie. Bijvoorbeeld, het volgende programma declareert een gewone functie, definieert een functiepointer, wijst de functiepointer toe aan de gewone functie en roept daarna de functie aan via de pointer:
#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");}
Output:
Hi Hi Hi
- We definiëren en declareren een standaardfunctie die een Hi-tekst k keer afdrukt, aangegeven door de parameter times, wanneer de functie wordt aangeroepen
- We definiëren een pointerfunctie (met zijn speciale declaratie) die een geheel getalparameter nodig heeft en niets retourneert.
- We initialiseren onze pointerfunctie met de Hi_function, wat betekent dat de pointer naar de Hi_function() wijst.
- In plaats van dat de standaardfunctie wordt aangeroepen door de functienaam met argumenten te koppelen, roepen we alleen de pointerfunctie aan door het getal 3 als argumenten door te geven, en dat is alles!
Houd er rekening mee dat de functienaam verwijst naar het beginadres van de uitvoerbare code, net als een arraynaam die naar het eerste element verwijst. Daarom zijn instructies zoals function_ptr = &Hi_function en (*funptr)(3) correct.
OPMERKING: Het is niet belangrijk om de adresoperator & en de indirecte operator * in te voegen tijdens de functietoewijzing en functieaanroep.
Reeks functieaanwijzers
Een array van functieaanwijzers kan een schakelaar- of if-instructierol spelen bij het nemen van een beslissing, zoals in het volgende programma:
#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 bespreken we de programmadetails:
- We verklaren en definiëren er vier functies waarvoor twee integer-argumenten nodig zijn en een geheel getal-waarde retourneren. Deze functies tellen op, trekken af, vermenigvuldigen en delen de twee argumenten met betrekking tot welke functie door de gebruiker wordt aangeroepen.
- We declareren 4 integers om respectievelijk operanden, operatietype en resultaat te verwerken. Ook declareren we een array van vier functiepointers. Elke functiepointer van een array-element neemt twee integers-parameters en retourneert een integerwaarde.
- We wijzen elk array-element toe en initialiseren het met de functie die al is gedeclareerd. Bijvoorbeeld, het derde element, dat de derde functiepointer is, zal verwijzen naar de vermenigvuldigingsbewerkingsfunctie.
- We vragen de gebruiker om operanden en het type bewerking dat hij met het toetsenbord typt.
- We hebben het juiste array-element (Functieaanwijzer) met argumenten aangeroepen en het resultaat opgeslagen dat door de juiste functie is gegenereerd.
De instructie int (*ope[4])(int, int); definieert de array van functieaanwijzers. Elk arrayelement moet dezelfde parameters en hetzelfde retourtype hebben.
Het resultaat van de instructie = ope[choice](x, y); voert de juiste functie uit volgens de keuze gemaakt door de gebruiker. De twee ingevoerde gehele getallen zijn de argumenten die aan de functie worden doorgegeven.
Functies Void-aanwijzers gebruiken
Ongeldige verwijzingen worden gebruikt tijdens functiedeclaraties. We gebruiken een ongeldige * retourtypevergunning om elk type te retourneren. Als we aannemen dat onze parameters niet veranderen bij het doorgeven aan een functie, declareren we deze als const.
Bijvoorbeeld:
void * cube (const void *);
Denk aan het volgende programma:
#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;}
Resultaat:
4 cubed is 64
Hier bespreken we de details van het programma:
- We definiëren en declareren een functie die een geheel getal retourneert en een adres aanneemt van een onveranderlijke variabele zonder een specifiek gegevenstype. We berekenen de kubuswaarde van de inhoudsvariabele (x), aangegeven door de num-aanwijzer, en omdat het een lege aanwijzer is, moeten we deze naar een geheel getal-gegevenstype typen met behulp van een specifieke notatie (* datatype)-aanwijzer, en we retourneren de kubuswaarde.
- We declareren de operand en de result variabele. Ook initialiseren we onze operand met waarde “4.”
- We roepen de kubusfunctie aan door het operandadres door te geven en we verwerken de geretourneerde waarde in de resultaatvariabele
Functieaanwijzers als argumenten
Een andere manier om een functieaanwijzer te exploiteren door deze als argument door te geven aan een andere functie, wordt ook wel de 'callback-functie' genoemd, omdat de ontvangende functie deze 'terugroept'.
In het headerbestand stdlib.h gebruikt de functie Quicksort “qsort()” deze techniek, een algoritme dat speciaal is bedoeld om een array te sorteren.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base : ongeldige verwijzing naar de array.
- size_t num : Het array-elementnummer.
- size_t breedte De elementgrootte.
- int (*compare (const void *, const void *) : functieaanwijzer bestaande uit twee argumenten en retourneert 0 als de argumenten dezelfde waarde hebben, <0 als arg1 vóór arg2 komt, en >0 als arg1 na arg2 komt.
Het volgende programma sorteert een integer-array van klein naar groot getal met behulp van de functie 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;}
Resultaat:
13 14 48 50 52
Hier bespreken we de details van het programma:
- We definiëren een vergelijkingsfunctie die bestaat uit twee argumenten en retourneert 0 als de argumenten dezelfde waarde hebben, <0 als arg1 vóór arg2 komt, en >0 als arg1 na arg2 komt. De parameters zijn van het type void pointers, gegoten naar het juiste array-gegevenstype (geheel getal)
- We definiëren en initialiseren een integer-array. De array-grootte wordt opgeslagen in de num variabele en de grootte van elk array-element wordt opgeslagen in de breedtevariabele met behulp van vooraf gedefinieerde sizeof(). C-operator.
- We noemen de sorteer function en geef de arraynaam, grootte, breedte en vergelijkingsfunctie door die eerder door de gebruiker is gedefinieerd om onze array in oplopende volgorde te sorteren. De vergelijking wordt uitgevoerd door in elke iteratie twee array-elementen te nemen totdat de gehele array is gesorteerd.
- We drukken de array-elementen af om er zeker van te zijn dat onze array goed gesorteerd is door de hele array te herhalen met behulp van for loop.