Funkciók Mutatók a C programozásban példákkal
A mutatók nagy lehetőségeket adnak a 'C' függvényeknek, melyeket egy érték visszaadására korlátozunk. A mutatóparaméterekkel funkcióink mostantól tényleges adatokat dolgozhatnak fel adatok másolata helyett.
A változók aktuális értékének módosítása érdekében a hívó utasítás címeket ad át egy függvény mutató paramétereinek.
Funkciók Mutatók Példa
Például a következő program felcseréli a kettő két értékét:
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
A program felcseréli a tényleges változók értékeit, mert a függvény cím használatával éri el őket mutató. Itt megbeszéljük a program menetét:
- Deklaráljuk a két változó érték felcseréléséért felelős függvényt, amely két egész mutatót vesz paraméterként, és meghívásakor tetszőleges értéket ad vissza.
- A fő függvényben deklarálunk és inicializálunk két egész változót ('m' és 'n'), majd kiírjuk az értékeket.
- A swap() függvényt úgy hívjuk meg, hogy a két változó címét argumentumként adjuk át az és jellel. Ezt követően kiírjuk a változók új felcserélt értékeit.
- Itt definiáljuk a swap() függvény tartalmát, amely két egész változó címet vesz fel paraméterként, és deklarál egy ideiglenes egész változót, amelyet harmadik tárolódobozként használunk, hogy elmentsük az egyik értékváltozót, amely a második változóba kerül.
- Mentse el az 'a'-val jelölt első változó tartalmát az ideiglenes változóban.
- Tárolja a b-vel mutatott második változót az a-val jelölt első változóban.
- Frissítse a második (b-vel jelölt) változót az ideiglenes változóba mentett első változó értékével.
Függvények tömbparaméterekkel
C-ben nem adhatunk át tömböt érték szerint egy függvénynek. Míg a tömbnév egy mutató (cím), ezért csak egy tömbnevet adunk át egy függvénynek, ami azt jelenti, hogy egy mutatót adunk át a tömbnek.
Például a következő programot vesszük figyelembe:
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
Itt elmagyarázzuk a programkódot annak részleteivel együtt
- Deklaráljuk és definiáljuk az add_array() függvényt, amely paraméterként egy tömbcímet(mutatót) vesz az elemszámmal, és visszaadja ezen elemek összesített összegét. A mutató a tömbelemek iterálására szolgál (a p[k] jelölést használva), és az összegzést egy helyi változóban halmozzuk fel, amelyet a teljes elemtömb iterációja után adunk vissza.
- Egy öt egész elemből álló egész tömböt deklarálunk és inicializálunk. A teljes összegzést úgy nyomtatjuk ki, hogy átadjuk a tömb nevét (ami címként működik) és a tömb méretét add_array()függvénynek nevezzük argumentumként.
Függvények, amelyek tömböt adnak vissza
C-ben visszaadhatunk egy mutatót egy tömbbe, mint a következő programban:
#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
És itt megbeszéljük a program részleteit
- Definiálunk és deklarálunk egy függvényt, amely egy egész számot tartalmazó tömbcímet ad vissza, és nem vett fel argumentumot.
- Deklarálunk egy egész mutatót, amely megkapja a függvény meghívása után felépített teljes tömböt, és a teljes ötelemes tömb iterálásával kiírjuk a tartalmát.
Figyeljük meg, hogy a függvény által visszaadott tömbcím tárolására nem tömb, hanem mutató van megadva. Figyeljük meg azt is, hogy amikor egy függvényből lokális változót adunk vissza, statikusként kell deklarálnunk a függvényben.
Funkciómutatók
Amint azt definícióból tudjuk, hogy a mutatók egy címre mutatnak bármely memóriahelyen, a memória függvényeiként a futtatható kód elejére is mutathatnak.
A függvényre mutató mutatót a * jellel deklarálják, a deklaráció általános utasítása:
return_type (*function_name)(arguments)
Ne feledje, hogy a körülötte lévő zárójelek (*függvény_neve) fontosak, mert ezek nélkül a fordító azt gondolja, hogy a függvény_neve a return_type mutatót adja vissza.
A függvénymutató definiálása után hozzá kell rendelnünk egy függvényhez. Például a következő program deklarál egy közönséges függvényt, meghatároz egy függvénymutatót, hozzárendeli a függvénymutatót a normál függvényhez, majd a mutatón keresztül meghívja a függvényt:
#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
- Definiálunk és deklarálunk egy szabványos függvényt, amely a függvény meghívásakor k-szer kiír egy Hi szöveget, amelyet a paraméter-idő jelzi
- Definiálunk egy pointer függvényt (speciális deklarációjával), amely egy egész paramétert vesz fel, és nem ad vissza semmit.
- A mutató függvényünket a Hi_függvénnyel inicializáljuk, ami azt jelenti, hogy a mutató a Hi_function()-ra mutat.
- Ahelyett, hogy a szabványos függvény a függvény nevének argumentumokkal történő rögzítésével hívná meg, csak a mutató függvényt hívjuk meg a 3-as szám argumentumként való átadásával, és kész!
Ne feledje, hogy a függvény neve a végrehajtható kód kezdőcímére mutat, mint egy tömbnév, amely az első elemére mutat. Ezért az olyan utasítások, mint a function_ptr = &Hi_function és a (*funptr)(3) helyesek.
MEGJEGYZÉS: A funkció hozzárendelése és a funkcióhívás során nem fontos a & cím operátor és az indirekt operátor * beszúrása.
Funkciómutatók tömbje
A függvénymutatók tömbje kapcsolót vagy if utasítást játszhat a döntés meghozatalában, mint a következő programban:
#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
Itt megbeszéljük a program részleteit:
- Kijelentjük és négyet határozunk meg funkciók amelyek két egész argumentumot vesznek fel és egy egész értéket adnak vissza. Ezek a függvények összeadják, kivonják, szorozzák és elosztják a két argumentumot arra vonatkozóan, hogy melyik függvényt hívja meg a felhasználó.
- 4 egész számot deklarálunk az operandusok, a művelettípus és az eredmény kezelésére. Ezenkívül deklarálunk egy négy függvénymutatóból álló tömböt. A tömbelem minden függvénymutatója két egész szám paramétert vesz fel, és egy egész értéket ad vissza.
- Minden tömbelemet hozzárendelünk és inicializálunk a már deklarált függvénnyel. Például a harmadik elem, amely a harmadik függvénymutató, a szorzási műveleti függvényre mutat.
- Operandusokat és művelettípusokat keresünk a billentyűzettel begépelt felhasználótól.
- A megfelelő tömbelemet (Function pointer) meghívtuk argumentumokkal, és a megfelelő függvény által generált eredményt tároljuk.
Az utasítás int (*ope[4])(int, int); a függvénymutatók tömbjét határozza meg. Minden tömbelemnek azonos paraméterekkel és visszatérési típussal kell rendelkeznie.
Az állítás eredménye = ope[választás](x, y); futtatja a megfelelő függvényt a felhasználó választása szerint. A két megadott egész szám a függvénynek átadott argumentum.
Funkciók üres mutatók használata
A funkciódeklaráció során üres mutatókat használunk. A void * visszatérési típust használjuk, amely lehetővé teszi bármilyen típusú visszaküldést. Ha feltételezzük, hogy a paramétereink nem változnak, amikor egy függvénynek átadunk, akkor azt const-ként deklaráljuk.
Például:
void * cube (const void *);
Fontolja meg a következő programot:
#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;}
Eredmény:
4 cubed is 64
Itt megbeszéljük a program részleteit:
- Egy olyan függvényt definiálunk és deklarálunk, amely egész értéket ad vissza, és egy változtathatatlan változó címét veszi fel meghatározott adattípus nélkül. Kiszámoljuk a tartalomváltozó (x) kockaértékét, amelyet a num pointer mutat, és mivel ez egy void pointer, ezért egy adott jelölésű (* adattípus) mutató segítségével be kell gépelnünk egy egész adattípusba, és visszaadjuk. a kocka értékét.
- Deklaráljuk az operandust és az eredményváltozót. Ezenkívül az operandusunkat „4” értékkel inicializáljuk.
- A kocka függvényt az operandus címének átadásával hívjuk meg, és az eredmény változóban kezeljük a visszatérő értéket
Funkciómutatók, mint argumentumok
Egy másik módja a függvénymutató kihasználásának, ha argumentumként adjuk át egy másik függvénynek, amelyet néha „visszahívási függvénynek” neveznek, mivel a fogadó függvény „visszahívja”.
Az stdlib.h fejlécfájlban a Quicksort „qsort()” függvény ezt a technikát használja, amely egy tömb rendezésére szolgáló algoritmus.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *alap: érvénytelen mutató a tömbre.
- size_t num : A tömb elemszáma.
- size_t width Az elem mérete.
- int (*összehasonlítás (const void *, const void *) : a függvénymutató két argumentumból áll, és 0-t ad vissza, ha az argumentumok értéke azonos, <0-t, ha az arg1 az arg2 elé kerül, és >0-t, ha az arg1 az arg2 után következik.
A következő program a qsort() függvény segítségével rendezi az egész tömböt kicsitől a nagyig:
#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;}
Eredmény:
13 14 48 50 52
Itt megbeszéljük a program részleteit:
- Összehasonlító függvényt definiálunk, amely két argumentumból áll, és 0-t ad vissza, ha az argumentumok azonos értékűek, <0-t, ha az arg1 az arg2 elé kerül, és >0-t, ha az arg1 az arg2 után következik. A paraméterek üres mutató típusúak, amelyek a megfelelő tömb adattípusba vannak öntve (egész szám)
- Egész tömböt definiálunk és inicializálunk A tömb mérete a num változó, és az egyes tömbelemek mérete a szélességi változóban tárolódik a sizeof() előre meghatározott használatával C operátor.
- Hívjuk a qsort függvényt, és adja át a felhasználó által korábban meghatározott tömb nevét, méretét, szélességét és összehasonlító függvényét, hogy a tömbünket növekvő sorrendbe rendezze. Az összehasonlítás úgy történik, hogy minden iterációban két tömbelemet veszünk, amíg a teljes tömb meg nem lesz rendezve.
- Kinyomtatjuk a tömb elemeit, hogy megbizonyosodjunk arról, hogy a tömb jól van rendezve a teljes tömb iterációjával hurokhoz.