Ukazovatele výrazne poskytujú možnosti funkcií „C“, ktoré sú obmedzené na vrátenie jednej hodnoty. Vďaka parametrom ukazovateľa môžu teraz naše funkcie spracovávať skutočné údaje, a nie ich kópiu.
Aby bolo možné upraviť skutočné hodnoty premenných, volajúci príkaz odovzdá adresy parametrom ukazovateľa vo funkcii.
V tomto návode sa naučíte
- Funkcie Ukazovatele Príklad
- Funkcie s parametrami poľa
- Funkcie, ktoré vracajú pole
- Ukazovatele funkcií
- Pole ukazovateľov funkcií
- Funkcie Používanie neplatných ukazovateľov
- Ukazovatele funkcií ako argumenty
Funkcie Ukazovatele Príklad
Napríklad nasledujúci program zamení dve hodnoty za dve:
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;}}
Výkon:
m is 25, n is 100m is 100, n is 25
Program zamení skutočné hodnoty premenných, pretože funkcia k nim pristupuje pomocou adresy pomocou ukazovateľov. Tu budeme diskutovať o procese programu:
- Deklarujeme funkciu zodpovednú za zámenu dvoch hodnôt premenných, ktorá berie ako parametre dva celočíselné ukazovatele a vráti každú hodnotu, keď sa volá.
- V hlavnej funkcii deklarujeme a inicializujeme dve celočíselné premenné ('m' a 'n'), potom vytlačíme ich hodnoty.
- Funkciu swap () nazývame odovzdaním adresy dvoch premenných ako argumentov pomocou symbolu ampersand. Potom vytlačíme nové vymenené hodnoty premenných.
- Tu definujeme obsah funkcie swap (), ktorá berie ako parametre dve adresy celočíselných premenných a deklarujeme dočasnú celočíselnú premennú použitú ako tretie úložné pole na uloženie jednej z hodnotových premenných, ktorá bude vložená do druhej premennej.
- Uložte obsah dočasnej premennej označenej znakom „a“.
- Uložte druhú premennú označenú b do prvej premennej označenej a.
- Aktualizujte druhú premennú (ukazuje na b) o hodnotu prvej premennej uloženej v dočasnej premennej.
Funkcie s parametrami poľa
V jazyku C nemôžeme funkcii odovzdať pole podľa hodnoty. Zatiaľ čo názov poľa je ukazovateľ (adresa), takže iba odovzdáme názov poľa funkcii, čo znamená odovzdať smerník do poľa.
Zvažujeme napríklad nasledujúci 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);}
Výkon:
Total summation is 471
Tu vysvetlíme programový kód s jeho podrobnosťami
- Deklarujeme a definujeme funkciu add_array (), ktorá ako parametre vezme adresu poľa (ukazovateľ) s počtom jeho prvkov a vráti celkový súhrn týchto prvkov. Ukazovateľ sa používa na iteráciu prvkov poľa (pomocou notácie p [k]) a súčet sa hromadí v lokálnej premennej, ktorá sa vráti po iterácii celého poľa prvkov.
- Deklarujeme a inicializujeme celočíselné pole s piatimi celočíselnými prvkami. Vytlačíme celkový súčet odovzdaním názvu poľa (ktoré slúži ako adresa) a veľkosti poľa funkcii s názvom add_array () ako argumentom.
Funkcie, ktoré vracajú pole
V jazyku C môžeme vrátiť ukazovateľ na pole, ako v nasledujúcom programe:
#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);}
Výkon:
12345
A tu budeme diskutovať o detailoch programu
- Definujeme a deklarujeme funkciu, ktorá vracia adresu poľa, ktorá obsahuje celočíselnú hodnotu, a nevzala žiadne argumenty.
- Deklarujeme celočíselný ukazovateľ, ktorý prijme celé pole zostavené po vyvolaní funkcie a jeho obsah vytlačíme iteráciou celého päťprvkového poľa.
Všimnite si, že na uloženie adresy poľa vrátenej funkciou je definovaný ukazovateľ, nie pole. Všimnite si tiež, že keď sa z funkcie vracia lokálna premenná, musíme ju vo funkcii vyhlásiť za statickú.
Ukazovatele funkcií
Ako je známe z definície, že ukazovatele ukazujú na adresu v ľubovoľnom pamäťovom mieste, môžu tiež ukazovať na začiatok spustiteľného kódu ako funkcie v pamäti.
Ukazovateľ na funkciu je deklarovaný znakom *, všeobecné vyhlásenie o jeho deklarácii je:
return_type (*function_name)(arguments)
Musíte si uvedomiť, že zátvorky okolo (* function_name) sú dôležité, pretože bez nich si kompilátor bude myslieť, že function_name vracia ukazovateľ return_type.
Po definovaní ukazovateľa funkcie ho musíme priradiť k funkcii. Napríklad nasledujúci program deklaruje bežnú funkciu, definuje ukazovateľ funkcie, priradí ukazovateľ funkcie k bežnej funkcii a potom zavolá funkciu pomocou ukazovateľa:
#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");}
Výkon:
HiHiHi
- Definujeme a deklarujeme štandardnú funkciu, ktorá pri volaní funkcie vytlačí Hi text k krát označený časmi parametra
- Definujeme funkciu ukazovateľa (s jej špeciálnou deklaráciou), ktorá berie celočíselný parameter a nič nevracia.
- Inicializujeme našu funkciu ukazovateľa pomocou Hi_function, čo znamená, že ukazovateľ smeruje na Hi_function ().
- Namiesto štandardného volania funkcie ťuknutím na jej názov pomocou argumentov voláme iba funkciu ukazovateľa tak, že číslo 3 odovzdáme ako argumenty a je to!
Majte na pamäti, že názov funkcie ukazuje na začiatočnú adresu spustiteľného kódu ako názov poľa, ktoré ukazuje na jeho prvý prvok. Preto sú pokyny ako function_ptr = & Hi_function a (* funptr) (3) správne.
POZNÁMKA: Počas priradenia funkcie a volania funkcie nie je dôležité vkladať operátor adresy & a operátor indukcie *.
Pole ukazovateľov funkcií
Pole funkčných ukazovateľov môže pri rozhodovaní hrať rolu prepínača alebo príkazu if, ako v nasledujúcom programe:
#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
Tu diskutujeme o podrobnostiach programu:
- Deklarujeme a definujeme štyri funkcie, ktoré obsahujú dva celočíselné argumenty a vrátia celočíselnú hodnotu. Tieto funkcie sčítajú, odčítajú, násobia a delia dva argumenty týkajúce sa toho, ktorá funkcia je používateľom volaná.
- Deklarujeme 4 celé čísla na spracovanie operandov, typu operácie a výsledku. Deklarujeme tiež pole štyroch funkčných ukazovateľov. Každý funkčný ukazovateľ prvku poľa má dva celočíselné parametre a vráti celočíselnú hodnotu.
- Priraďujeme a inicializujeme každý prvok poľa s už deklarovanou funkciou. Napríklad tretí prvok, ktorý je tretím ukazovateľom funkcie, bude ukazovať na funkciu násobenia.
- Operandy a typ operácie hľadáme od používateľa zadaného pomocou klávesnice.
- Zavolali sme príslušný prvok poľa (ukazovateľ funkcie) s argumentmi a uložili sme výsledok vygenerovaný príslušnou funkciou.
Inštrukcia int (* ope [4]) (int, int); definuje pole ukazovateľov funkcií. Každý prvok poľa musí mať rovnaké parametre a návratový typ.
Výsledok výpisu = ope [výber] (x, y); spustí príslušnú funkciu podľa voľby, ktorú urobí používateľ. Dve zadané celé čísla sú argumenty odovzdané funkcii.
Funkcie Používanie neplatných ukazovateľov
Ukazovatele neplatnosti sa používajú počas deklarácií funkcií. Na vrátenie ľubovoľného typu používame povolenia typu void * return. Ak predpokladáme, že sa naše parametre pri prechode na funkciu nemenia, deklarujeme to ako konšt.
Napríklad:
void * cube (const void *);
Zvážte nasledujúci program:
#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;}
Výsledok:
4 cubed is 64
Tu budeme diskutovať o detailoch programu:
- Definujeme a deklarujeme funkciu, ktorá vracia celočíselnú hodnotu a berie adresu nezmeniteľnej premennej bez konkrétneho dátového typu. Vypočítame hodnotu kocky premennej obsahu (x), na ktorú ukazuje ukazovateľ num, a keďže ide o ukazovateľ neplatnosti, musíme ju napísať cast na celočíselný údajový typ pomocou ukazovateľa špecifickej notácie (* datový typ) a vrátime sa hodnota kocky.
- Deklarujeme operand a výslednú premennú. Inicializujeme tiež náš operand s hodnotou "4."
- Funkciu kocky zavoláme odovzdaním adresy operandu a návratovú hodnotu spracujeme vo výslednej premennej
Ukazovatele funkcií ako argumenty
Ďalším spôsobom, ako využiť ukazovateľ funkcie tak, že ho odovzdáte ako argument inej funkcii, ktorá sa niekedy nazýva „funkcia spätného volania“, pretože prijímajúca funkcia „ju volá späť“.
V hlavičkovom súbore stdlib.h používa funkcia Quicksort „qsort ()“ túto techniku, čo je algoritmus určený na triedenie poľa.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void * base: void ukazovateľ na pole.
- size_t num: číslo prvku poľa.
- size_t width Veľkosť prvku.
- int (* porovnaj (const void *, const void *): ukazovateľ funkcie zložený z dvoch argumentov a vráti 0, ak majú argumenty rovnakú hodnotu, <0, keď arg1 príde pred arg2, a> 0, keď arg1 príde po arg2.
Nasledujúci program zoraďuje celé celé pole od malého po veľké pomocou funkcie qsort ():
#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;}
Výsledok:
13 14 48 50 52
Tu budeme diskutovať o detailoch programu:
- Definujeme funkciu porovnania zloženú z dvoch argumentov a vráti 0, keď majú argumenty rovnakú hodnotu, <0, keď arg1 príde pred arg2, a> 0, keď arg1 príde po arg2. Parametre sú neplatné ukazovatele typu vrhnuté na vhodný dátový typ poľa (celé číslo)
- Definujeme a inicializujeme celočíselné pole. Veľkosť poľa je uložená v premennej num a veľkosť každého prvku poľa je uložená v premennej width pomocou preddefinovaného operátora C sizeof ().
- Zavoláme funkciu qsort a odovzdáme názov poľa, veľkosť, šírku a porovnávaciu funkciu definovanú predtým používateľom, aby sme zoradili naše pole vo vzostupnom poradí. Porovnanie sa uskutoční tak, že sa v každej iterácii vezmú dva prvky poľa, kým sa nezruší celé pole. budú zoradené.
- Vytlačíme prvky poľa, aby sme sa ubezpečili, že naše pole je dobre zoradené iteráciou celého poľa pomocou slučky for.