Funkciók Mutatók a C programozásban példákkal

⚡ Okos összefoglaló

A C függvénymutatók a végrehajtható kód címét tárolják, lehetővé téve a programok számára, hogy a függvényeket közvetve hívják meg, argumentumként adják át, tömbökből diszpécsertáblákat építsenek, és visszahívásokat valósítsanak meg, például a qsort összehasonlító rutint a rugalmas, újrafelhasználható tervekhez.

  • 🔗 Nyilatkozat: Egy függvénymutató a return_type(*name)(arguments) formátumot használja; a név körüli zárójelek kitöltése kötelező.
  • 🔄 Csere cím szerint: A változócímek pointer paramétereknek való átadása lehetővé teszi a függvények számára, hogy megváltoztassák a hívó eredeti értékeit, ahogy a swap példában is látható.
  • 📦 Tömbök: Egy tömbnév már egy mutató, így a függvények fogadhatnak egy tömböt, vagy visszaadhatnak egy statikus tömbre mutató mutatót.
  • 🎛️ Feladási táblázatok: Egy függvénypointerek tömbje helyettesíti a hosszú kapcsoló- vagy if-láncokat azáltal, hogy közvetlenül a kiválasztott műveletre indexel.
  • 🧊 érvénytelen mutatók: Egy void * paraméter vagy visszatérési típus bármilyen típust elfogad, amelyet a függvény használat előtt visszaalakít.
  • 📞 Visszahívások: Egy függvénymutató argumentumként való átadása olyan visszahívásokat tesz lehetővé, mint például a qsort összehasonlító függvény.
  • 🤖 AI segítség: A GitHub Copilot és a mesterséges intelligencia asszisztensek scaffollow-olják a függvénymutató szintaxist, a typedef-eket és a visszahívási aláírásokat, majd megjelölik az egyező paramétereket.

Függvénymutatók C-ben

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

Funkciók Mutatók Példa

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:

  1. A swapért felelős függvényt deklaráljuk.ping a két változó értéke, amely két egész mutatót kap paraméterként, és meghívásakor tetszőleges értéket ad vissza.
  2. 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.
  3. 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.
  4. 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.
  5. Mentse el az 'a'-val jelölt első változó tartalmát az ideiglenes változóban.
  6. Tárolja a b-vel mutatott második változót az a-val jelölt első változóban.
  7. 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

Függvények tömbparaméterekkel

  1. 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.
  2. 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

Függvények, amelyek tömböt adnak vissza

  1. 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.
  2. 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

Funkciók Mutatók C-ben

  1. 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
  2. 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.
  3. A mutató függvényünket a Hi_függvénnyel inicializáljuk, ami azt jelenti, hogy a mutató a Hi_function()-ra mutat.
  4. A ta általi standard függvényhívás helyettping a függvény nevét argumentumokkal, akkor csak a mutatófüggvényt hívjuk meg a 3-as szám argumentumként történő átadásával, és ennyi!

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:

Funkciómutatók tömbje

  1. Kijelentjük és négyet határozunk meg funkciók amelyek két egész argumentumot fogadnak el, és egy egész értéket adnak vissza. Ezek a függvények összeadják, subtract, szorozd meg és oszd el a két argumentumot, amelyek arra vonatkoznak, hogy a felhasználó melyik függvényt hívja meg.
  2. 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.
  3. 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.
  4. Operandusokat és művelettípusokat keresünk a billentyűzettel begépelt felhasználótól.
  5. 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:

Funkciók üres mutatók használata

  1. 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.
  2. Deklaráljuk az operandust és az eredményváltozót. Ezenkívül az operandusunkat „4” értékkel inicializáljuk.
  3. 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:

Funkciómutatók, mint argumentumok

  1. Ö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)
  2. 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.
  3. Meghívjuk a qsort függvényt, és átadjuk a felhasználó által korábban definiált tömbnevet, méretet, szélességet és az összehasonlító függvényt, hogy a tömböt növekvő sorrendbe rendezzük. Az összehasonlítást úgy végezzük, hogy minden iterációban két tömbelemet veszünk figyelembe, amíg a teljes tömb rendezett nem lesz.
  4. 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.

GYIK

Igen. Egy függvénymutatónak pontosan meg kell egyeznie a célfüggvény visszatérési típusával és paraméterlistájával. Egy eltérő szignatúrával rendelkező függvény hozzárendelése nem definiált viselkedés, még akkor is, ha lefordul, mert a hívás futásidejű argumentumokat helytelenül olvasna be és küldene be.

A typedef egy összetett függvénymutató típusnak egy rövid nevet ad. A typedef int (* írásaOperation)(int, int); lehetővé teszi a deklarálást Operation add; a teljes mutató szintaxis ismétlése helyett a tömbök, paraméterek és struktúratagok sokkal könnyebben olvashatók.

A függvénymutatók visszahívásokat, ugró- vagy diszpécsertáblákat, bővítmény- és eseményvezérelt rendszereket, állapotgépeket és olyan könyvtári rutinokat vezérelnek, mint a qsort és a bsearch. OperaA futtatórendszerek és a beágyazott firmware-ek ezekre támaszkodnak a futásidejű viselkedés kiválasztásához hosszú feltételes láncok nélkül.

Az adatmutató a memóriában lévő változó címét tárolja, míg a függvénymutató a végrehajtható kód belépési címét. A függvény futtatásához függvénymutatón keresztül hívjuk meg a függvényt, ahelyett, hogy dereferenciálnánk azt az adatok olvasásához vagy írásához.

Igen. Egy függvénymutató NULL értékre állítható, ami azt jelenti, hogy nincs hozzárendelve függvény. Egy NULL függvénymutató meghívása definiálatlan viselkedést okoz, ezért a hívást az if (ptr != NULL) paraméterrel kell védeni a meghívása előtt, különösen az opcionális visszahívások esetén.

Igen. A függvénymutatók struktúratagokként való elhelyezése lehetővé teszi, hogy egy struktúra összefogja az adatokat a kapcsolódó műveletekkel, objektumokat és virtuális metódustáblákat utánozva. Ez a minta számos C könyvtár és eszközillesztő alapját képezi, ahol minden példány kiválasztja a saját függvényimplementációját.

Igen. Egy mesterséges intelligencia által vezérelt kódolási asszisztens képes függvénymutató-deklarációkat, typedef-eket és visszahívási aláírásokat generálni egy egyszerű nyelvi promptból, elmagyarázni a zavaros szintaxist, és kiszűrni az eltérő paramétereket vagy visszatérési típusokat. Mindig fordítsa le és tesztelje a javasolt kódot, mielőtt megbízna benne.

GitHub másodpilóta Javaslatokat tesz a függvénymutató szintaxisára, kiegészíti a visszahívási törzseket egy megjegyzésből vagy aláírásból, és qsort összehasonlító függvényeket javasol. Nyissa meg a releváns header fájlokat, hogy a kiegészítései megegyezzenek a deklarált prototípusokkal, majd tekintse át a logikát.

Foglald össze ezt a bejegyzést a következőképpen: