Funkcijski pokazivači u C programiranju s primjerima
⚡ Pametni sažetak
Pokazivači funkcija u C-u pohranjuju adresu izvršnog koda, omogućujući programima da neizravno pozivaju funkcije, prosljeđuju ih kao argumente, grade tablice otpreme iz nizova i implementiraju povratne pozive poput rutine usporedbe qsort za fleksibilne, višekratno upotrebljive dizajne.

Pokazivači daju velike mogućnosti 'C' funkcijama koje su ograničene na vraćanje jedne vrijednosti. S parametrima pokazivača, naše funkcije sada mogu obraditi stvarne podatke umjesto kopije podataka.
Kako bi se modificirale stvarne vrijednosti varijabli, pozivna izjava prosljeđuje adrese parametrima pokazivača u funkciji.
Primjer pokazivača funkcija
Na primjer, sljedeći program mijenja dvije vrijednosti od dva:
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;} }
Izlaz:
m is 25, n is 100 m is 100, n is 25
Program mijenja stvarne vrijednosti varijabli jer im funkcija pristupa putem adrese pokazivač. Ovdje ćemo razgovarati o procesu programa:
- Deklariramo funkciju odgovornu za zamjenuping dvije varijable vrijednosti, koja uzima dva cjelobrojna pokazivača kao parametre i vraća bilo koju vrijednost kada se pozove.
- U glavnoj funkciji deklariramo i inicijaliziramo dvije cjelobrojne varijable ('m' i 'n'), a zatim ispisujemo njihove vrijednosti.
- Funkciju swap() pozivamo prosljeđivanjem adrese dviju varijabli kao argumenata pomoću simbola ampersend. Nakon toga ispisujemo nove zamijenjene vrijednosti varijabli.
- Ovdje definiramo sadržaj funkcije swap() koja uzima dvije adrese cjelobrojnih varijabli kao parametre i deklariramo privremenu cjelobrojnu varijablu koja se koristi kao treća kutija za pohranu za spremanje jedne od varijabli vrijednosti koje će se staviti u drugu varijablu.
- Sačuvajte sadržaj prve varijable označene s 'a' u privremenoj varijabli.
- Pohranite drugu varijablu označenu s b u prvu varijablu označenu s a.
- Ažurirajte drugu varijablu (označenu s b) vrijednošću prve varijable spremljene u privremenoj varijabli.
Funkcije s parametrima polja
U C-u ne možemo proslijediti niz prema vrijednosti u funkciju. Dok je naziv niza pokazivač (adresa), tako da samo prosljeđujemo naziv niza funkciji što znači proslijediti pokazivač na niz.
Na primjer, razmatramo sljedeći program:
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);}
Izlaz:
Total summation is 471
Ovdje ćemo objasniti programski kod s detaljima
- Deklariramo i definiramo funkciju add_array() koja uzima adresu polja (pokazivač) s brojem elemenata kao parametre i vraća ukupni akumulirani zbroj tih elemenata. Pokazivač se koristi za ponavljanje elemenata niza (koristeći p[k] notaciju), a zbroj akumuliramo u lokalnoj varijabli koja će biti vraćena nakon ponavljanja cijelog niza elemenata.
- Deklariramo i inicijaliziramo niz cjelobrojnih brojeva s pet cjelobrojnih elemenata. Ukupni zbroj ispisujemo prosljeđujući naziv niza (koji djeluje kao adresa) i veličinu niza add_array()zove funkcija kao argumenti.
Funkcije koje vraćaju niz
U C-u možemo vratiti pokazivač na niz, kao u sljedećem programu:
#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);}
Izlaz:
1 2 3 4 5
A ovdje ćemo razgovarati o detaljima programa
- Definiramo i deklariramo funkciju koja vraća adresu niza koja sadrži cjelobrojnu vrijednost i ne uzima nikakve argumente.
- Deklariramo cjelobrojni pokazivač koji prima cijeli niz izgrađen nakon poziva funkcije i ispisujemo njegov sadržaj iteracijom čitavog niza od pet elemenata.
Primijetite da je pokazivač, a ne niz, definiran za pohranjivanje adrese niza koju vraća funkcija. Također primijetite da kada se lokalna varijabla vraća iz funkcije, moramo je deklarirati kao statičnu u funkciji.
Funkcijski pokazivači
Kako po definiciji znamo da pokazivači pokazuju na adresu u bilo kojoj memorijskoj lokaciji, oni također mogu pokazivati na početak izvršnog koda kao funkcije u memoriji.
Pokazivač na funkciju je deklariran sa *, opći iskaz njegove deklaracije je:
return_type (*function_name)(arguments)
Morate zapamtiti da su zagrade oko (*function_name) važne jer će bez njih prevoditelj misliti da function_name vraća pokazivač return_type.
Nakon definiranja pokazivača funkcije, moramo ga dodijeliti funkciji. Na primjer, sljedeći program deklarira običnu funkciju, definira pokazivač funkcije, dodjeljuje pokazivač funkcije običnoj funkciji i nakon toga poziva funkciju preko pokazivača:
#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");}
Izlaz:
Hi Hi Hi
- Definiramo i deklariramo standardnu funkciju koja ispisuje Hi tekst k puta naznačeno parametrom puta kada se funkcija pozove
- Definiramo pokazivačku funkciju (sa svojom posebnom deklaracijom) koja uzima cjelobrojni parametar i ne vraća ništa.
- Inicijaliziramo našu funkciju pokazivača s Hi_function što znači da pokazivač pokazuje na Hi_function().
- Umjesto standardnog poziva funkcije od strane taping naziv funkcije s argumentima, pozivamo samo pokazivačku funkciju prosljeđujući broj 3 kao argumente i to je to!
Imajte na umu da naziv funkcije pokazuje na početnu adresu izvršnog koda poput naziva niza koji pokazuje na njegov prvi element. Stoga su upute poput function_ptr = &Hi_function i (*funptr)(3) točne.
NAPOMENA: Nije važno umetnuti adresni operator & i indirektni operator * tijekom dodjele funkcije i poziva funkcije.
Niz pokazivača funkcija
Niz funkcijskih pokazivača može igrati ulogu prekidača ili naredbe if za donošenje odluke, kao u sljedećem programu:
#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
Ovdje raspravljamo o detaljima programa:
- Proglašavamo i definiramo četiri Funkcije koje uzimaju dva cjelobrojna argumenta i vraćaju cjelobrojnu vrijednost. Ove funkcije zbrajaju, podračunavajutract, pomnožite i podijelite dva argumenta u vezi s tim koju funkciju korisnik poziva.
- Deklariramo 4 cijela broja za rukovanje operandima, tipom operacije i rezultatom. Također, deklariramo niz od četiri funkcijska pokazivača. Svaki funkcijski pokazivač elementa niza uzima dva cjelobrojna parametra i vraća cjelobrojnu vrijednost.
- Svaki element niza dodjeljujemo i inicijaliziramo s već deklariranom funkcijom. Na primjer, treći element koji je pokazivač treće funkcije pokazat će na funkciju operacije množenja.
- Tražimo operande i vrstu operacije od korisnika tipkanog tipkovnicom.
- Pozvali smo odgovarajući element niza (Function pointer) s argumentima, a rezultat koji je generirala odgovarajuća funkcija pohranili smo.
Instrukcija int (*ope[4])(int, int); definira niz funkcijskih pokazivača. Svaki element niza mora imati iste parametre i vrstu povrata.
Rezultat iskaza = ope[izbor](x, y); pokreće odgovarajuću funkciju prema izboru korisnika. Dva unesena cijela broja su argumenti proslijeđeni funkciji.
Funkcije koje koriste void pokazivače
Void pokazivači se koriste tijekom deklaracije funkcija. Koristimo void * povratni tip dopušta vraćanje bilo kojeg tipa. Ako pretpostavimo da se naši parametri ne mijenjaju prilikom prijelaza na funkciju, deklariramo je kao const.
Na primjer:
void * cube (const void *);
Razmotrite sljedeći program:
#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;}
Rezultat:
4 cubed is 64
Ovdje ćemo razgovarati o detaljima programa:
- Definiramo i deklariramo funkciju koja vraća cjelobrojnu vrijednost i uzima adresu nepromjenjive varijable bez specifičnog tipa podataka. Izračunavamo kubnu vrijednost varijable sadržaja (x) na koju pokazuje pokazivač num, a budući da je to pokazivač void, moramo ga utipkati pretvoriti u cjelobrojni tip podataka pomoću pokazivača specifične notacije (* datatype), i vraćamo vrijednost kocke.
- Deklariramo operand i varijablu rezultata. Također, inicijaliziramo naš operand s vrijednošću "4."
- Funkciju kocke pozivamo prosljeđivanjem adrese operanda i obrađujemo povratnu vrijednost u varijabli rezultata
Funkcijski pokazivači kao argumenti
Još jedan način za iskorištavanje pokazivača funkcije prosljeđivanjem kao argumenta drugoj funkciji koja se ponekad naziva "funkcija povratnog poziva" jer je funkcija primatelja "poziva natrag".
U datoteci zaglavlja stdlib.h funkcija Quicksort "qsort()" koristi ovu tehniku koja je algoritam posvećen razvrstavanju niza.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *baza : void pokazivač na niz.
- size_t num : Broj elementa niza.
- size_t width Veličina elementa.
- int (*usporedi (const void *, const void *) : pokazivač funkcije sastavljen od dva argumenta i vraća 0 kada argumenti imaju istu vrijednost, <0 kada arg1 dolazi prije arg2, i >0 kada arg1 dolazi nakon arg2.
Sljedeći program sortira niz cijelih brojeva od malog do velikog broja pomoću funkcije 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;}
Rezultat:
13 14 48 50 52
Ovdje ćemo razgovarati o detaljima programa:
- Definiramo funkciju usporedbe koja se sastoji od dva argumenta i vraća 0 kada argumenti imaju istu vrijednost, <0 kada arg1 dolazi prije arg2, i >0 kada arg1 dolazi nakon arg2. Parametri su tip void pokazivača koji se pretvaraju u odgovarajući tip podataka niza (cijeli broj)
- Definiramo i inicijaliziramo niz cijelih brojeva. Veličina niza pohranjuje se u broj varijabla, a veličina svakog elementa niza pohranjuje se u varijabli širine pomoću unaprijed definiranog sizeof() C operator.
- Pozivamo funkciju qsort i prosljeđujemo naziv polja, veličinu, širinu i funkciju usporedbe koju je prethodno definirao korisnik kako bismo sortirali naše polje uzlaznim redoslijedom. Usporedba će se izvršiti uzimanjem dva elementa polja u svakoj iteraciji dok se cijeli niz ne sortira.
- Ispisujemo elemente niza kako bismo bili sigurni da je naš niz dobro sortiran ponavljanjem cijelog niza koristeći za petlju.







