A mutatók nagy lehetőséget adnak a „C” függvényekre, amelyekre korlátozva vagyunk, hogy egy értéket adjunk vissza. A mutatóparaméterekkel a funkcióink immár a tényleges adatokat képesek feldolgozni, nem pedig az adatok másolatát.
A változók tényleges értékeinek módosítása érdekében a hívó utasítás címeket ad át egy függvény mutatóparamétereinek.
Ebben az oktatóanyagban megtanulja-
- Funkciók Mutatók Példa
- Funkciók tömbparaméterekkel
- Tömböt adó függvények
- Funkciómutatók
- Funkciómutatók tömbje
- Funkciók az érvénytelen mutatók használatával
- Funkciómutatók mint érvek
Funkciók Mutatók Példa
Például a következő program két értéket cserél kettőből:
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;}}
Kimenet:
m is 25, n is 100m is 100, n is 25
A program felcseréli a tényleges változók értékeit, mert a függvény címek segítségével, mutatók segítségével érheti el őket. Itt fogjuk megvitatni a program folyamatát:
- A két változó értékének felcseréléséért felelősnek nyilvánítjuk a függvényt, amely két egész mutatót vesz paraméterként és bármely értéket visszaad, amikor meghívják.
- A fő függvényben deklarálunk és inicializálunk két egész változót ('m' és 'n'), majd kinyomtatjuk az értéküket.
- A swap () függvényt úgy hívjuk meg, hogy a két változó címét argumentumként adjuk át az ampersand szimbólummal. Ezt követően kinyomtatjuk 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 paraméterként, és deklarálunk egy ideiglenes egész változót, amelyet harmadik tároló dobozként használunk az egyik értékváltozó elmentésére, amelyet a második változóba helyezünk.
- Mentse az ideiglenes változóba az első „a” betűvel jelölt változó tartalmát.
- Tárolja a b által mutatott második változót az a által mutatott első változóban.
- Frissítse a második (b által mutatott) változót az ideiglenes változóba mentett első változó értékével.
Funkciók tömbparaméterekkel
C-ben nem adhatunk át tömböt érték szerint egy függvénynek. Míg egy tömb neve mutató (cím), tehát csak egy tömb nevet adunk át egy függvénynek, ami azt jelenti, hogy egy mutatót továbbítunk a tömbhöz.
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);}
Kimenet:
Total summation is 471
Itt elmagyarázzuk a programkódot annak részleteivel
- Kihirdetjük és definiáljuk az add_array () függvényt, amely egy tömb címet (mutatót) veszi paramétereként az elemek számával és visszaadja ezen elemek összesített összesítését. A mutatót a tömb elemeinek iterálására használják (a p [k] jelölés segítségével), és az összegzést egy helyi változóban halmozzuk fel, amelyet a teljes elem tömb iterálása után adunk vissza.
- Deklaráljuk és inicializáljuk egy egész tömböt öt egész elemmel. A teljes összegzést úgy nyomtatjuk ki, hogy a tömb nevét (amely címként működik) és a tömb méretét átadjuk argumentumként az add_array () függvénynek.
Tömböt adó függvények
C-ben visszaadhatunk egy mutatót egy tömbbe, mint a következő programban:
#includeint * 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);}
Kimenet:
12345
És itt megvitatjuk a program részleteit
- Meghatározunk és deklarálunk egy függvényt, amely egy egész értéket tartalmazó tömbcímet ad vissza, és nem adott hozzá argumentumokat.
- Kijelölünk egy egész mutatót, amely megkapja a függvény meghívása után felépített teljes tömböt, és az egész öt tömb iterálásával kinyomtatjuk annak tartalmát.
Figyelje meg, hogy egy mutató, és nem tömb van definiálva a függvény által visszaadott tömb cím tárolására. Figyeljük meg azt is, hogy amikor egy helyi változót visszaküldünk egy függvényből, statikusnak kell nyilvánítanunk a függvényben.
Funkciómutatók
Mivel definíció szerint tudjuk, hogy a mutatók bármely memóriahelyen lévő címre mutatnak, a futtatható kód elején a memória funkcióiként is mutathatnak.
A működési mutatót a * -gal együtt deklaráljuk, a deklaráció általános állítása:
return_type (*function_name)(arguments)
Ne feledje, hogy a (* function_name) körüli zárójelek fontosak, mivel ezek nélkül a fordító úgy gondolja, hogy a function_name a return_type mutatót adja vissza.
A függvénymutató meghatározá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 funkciómutatót, hozzárendeli a függvénymutatót a közönséges függvényhez, és ezután a mutatón keresztül meghívja a függvényt:
#includevoid 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");}
Kimenet:
HiHiHi
- Meghatározunk és deklarálunk egy szabványos függvényt, amely Hi-s szöveget nyomtat k-szor, amelyet a függvény meghívásakor a paraméter-idők jelölnek
- Meghatározunk egy mutatófüggvényt (annak speciális deklarációjával), amely egész paramétert vesz fel, és nem ad vissza semmit.
- A Hi_function segítségével inicializáljuk a pointer függvényünket, ami azt jelenti, hogy a mutató a Hi_function () pontra mutat.
- Ahelyett, hogy a szokásos függvény meghívná a függvény nevének argumentumokkal történő megragadásával, csak a mutató függvényt hívjuk meg azzal, hogy argumentumként továbbadjuk a 3-as számot, és ennyi!
Ne feledje, hogy a függvény neve a futtatható kód kezdő címére mutat, mint egy tömb név, amely az első elemére mutat. Ezért az olyan utasítások, mint a function_ptr = & Hi_function és (* funptr) (3), helyesek.
MEGJEGYZÉS: A funkciókiosztás és a függvényhívás során nem fontos beilleszteni a cím és az indirekt operátor * szót.
Funkciómutatók tömbje
A függvénymutatók tömbje kapcsolót vagy if utasítás szerepet játszhat a döntés meghozatalában, mint a következő programban:
#includeint 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 48Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2624
Itt megvitatjuk a program részleteit:
- Deklarálunk és definiálunk négy függvényt, amelyek két egész argumentumot vesznek fel, és egész számot adnak vissza. Ezek a függvények összeadják, kivonják, szorozzák és elosztják a két argumentumot a felhasználó által meghívott függvények tekintetében.
- 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ó tömböt. A tömbelem minden függvénymutatója két egész paramétert vesz fel, és egy egész értéket ad vissza.
- Minden tömb elemet hozzárendelünk és inicializálunk a már deklarált funkcióval. Például a harmadik elem, amely a harmadik függvénymutató, a szorzási műveletre mutat.
- Az operandusokat és a művelet típusát a billentyűzettel beírt felhasználótól keressük.
- Argumentumokkal hívtuk meg a megfelelő tömb elemet (Function pointer), és tároljuk a megfelelő függvény által generált eredményt.
Az int (* ope [4]) (int, int) utasítás; meghatározza a függvénymutatók tömbjét. Minden tömbelemnek azonos paraméterekkel és visszatérési típussal kell rendelkeznie.
Az eredmény = ope [választás] (x, y) állítás; futtatja a megfelelő függvényt a felhasználó választása szerint A két beírt egész szám a függvénynek átadott argumentum.
Funkciók az érvénytelen mutatók használatával
Az érvénytelen mutatókat a funkció deklarációk során használják. Bármilyen típus visszaküldéséhez érvénytelen * return típusú engedélyeket használunk. Ha feltételezzük, hogy a paramétereink nem változnak, amikor átadunk egy függvénynek, akkor konst-ként deklaráljuk.
Például:
void * cube (const void *);
Fontolja meg a következő programot:
#includevoid* 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 megvitatjuk a program részleteit:
- Meghatározunk és deklarálunk egy függvényt, amely egy egész értéket ad vissza, és egy megváltoztathatatlan változó címét veszi be konkrét adattípus nélkül. Kiszámoljuk a számmutató által mutatott tartalmi változó (x) kockaértékét, és mivel ez egy érvénytelen mutató, egy megadott jelölés (* adattípus) mutató segítségével egész típusú adattípusba kell írnunk, és visszatérünk a kockaérték.
- Kijelentjük az operandus és az eredmény változót. Ezenkívül a "4" értékkel inicializáljuk operandusunkat
- Az operandus cím átadásával hívjuk meg a kocka függvényt, és az eredmény változóban kezeljük a visszatérő értéket
Funkciómutatók mint érvek
A funkciómutató kiaknázásának egy másik módja azzal, hogy argumentumként továbbítja egy másik függvénynek, amelyet néha "visszahívási függvénynek" hívnak, mert 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 * base: érvénytelen mutató a tömbre.
- size_t num: A tömb elem száma.
- size_t width Az elem mérete.
- int (* összehasonlítás (const void *, const void *): függvénymutató két argumentumból áll, és 0-t ad vissza, ha az argumentumok értéke azonos, <0, amikor az arg1 az arg2 elé kerül, és> 0, amikor 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 kis számtól a nagy számig:
#include#include 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 megvitatjuk a program részleteit:
- Két argumentumból álló összehasonlító függvényt definiálunk, és 0-t adunk vissza, ha az argumentumok értéke azonos, <0, amikor az arg1 az arg2 elé kerül, és> 0, amikor az arg1 az arg2 után következik. A paraméterek egy érvénytelen mutatótípusok, amelyek a megfelelő tömb adattípusra vannak öntve (egész szám)
- Megadunk és inicializálunk egy egész tömböt. A tömb méretét a num változóban tároljuk, és az egyes tömb elemek méretét szélesség változóban tároljuk a sizeof () előre definiált C operátor segítségével.
- Meghívjuk a qsort függvényt, és átadjuk a tömb nevét, méretét, szélességét és összehasonlító függvényét, amelyet a felhasználó korábban definiált annak érdekében, hogy a tömböt növekvő sorrendbe rendezhessük. Az összehasonlítást úgy végezzük, hogy minden iterációban két tömb elemet veszünk fel a teljes tömbig. rendezésre kerül.
- A tömb elemeit kinyomtatjuk, hogy megbizonyosodhassunk arról, hogy tömbünk rendezett-e, a teljes tömb iterálásával a ciklus segítségével.