Ukazatele značně dávají možnost funkcím „C“, které jsme omezeni na vrácení jedné hodnoty. S parametry ukazatele mohou nyní naše funkce zpracovávat skutečná data, nikoli jejich kopii.
Aby bylo možné upravit skutečné hodnoty proměnných, volající příkaz předá adresy parametrům ukazatele ve funkci.
V tomto výukovém programu se naučíte
- Funkce Ukazatele Příklad
- Funkce s parametry pole
- Funkce, které vrací pole
- Ukazatele funkcí
- Pole ukazatelů funkcí
- Funkce pomocí neplatných ukazatelů
- Ukazatele funkcí jako argumenty
Funkce Ukazatele Příklad
Například další program zamění dvě hodnoty ze dvou:
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ýstup:
m is 25, n is 100m is 100, n is 25
Program zamění skutečné hodnoty proměnných, protože k nim funkce přistupuje pomocí adresy pomocí ukazatelů. Zde budeme diskutovat o procesu programu:
- Deklarujeme funkci odpovědnou za záměnu dvou hodnot proměnných, která jako parametry vezme dva celočíselné ukazatele a při volání vrátí jakoukoli hodnotu.
- V hlavní funkci deklarujeme a inicializujeme dvě celočíselné proměnné ('m' a 'n'), poté vytiskneme jejich hodnoty.
- Funkci swap () zavoláme předáním adresy dvou proměnných jako argumentů pomocí symbolu ampersand. Poté vytiskneme nové vyměněné hodnoty proměnných.
- Zde definujeme obsah funkce swap (), který jako parametry bere dvě adresy celočíselných proměnných a deklaruje dočasnou celočíselnou proměnnou použitou jako třetí úložný prostor pro uložení jedné z hodnotových proměnných, které budou vloženy do druhé proměnné.
- Uložte obsah první proměnné označené „a“ do dočasné proměnné.
- Uložte druhou proměnnou označenou b do první proměnné označené a.
- Aktualizujte druhou proměnnou (ukazuje b) o hodnotu první proměnné uložené v dočasné proměnné.
Funkce s parametry pole
V C nemůžeme funkci předat pole podle hodnoty. Vzhledem k tomu, název pole je ukazatel (adresa), takže jsme jen předat název pole do funkce, což znamená předat ukazatel do pole.
Zvažujeme například následující 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ýstup:
Total summation is 471
Zde vysvětlíme programový kód s jeho podrobnostmi
- Deklarujeme a definujeme funkci add_array (), která jako parametry přebírá adresu pole (ukazatel) s číslem jeho prvků a vrací celkový kumulovaný součet těchto prvků. Ukazatel se používá k iteraci prvků pole (pomocí notace p [k]) a souhrn se hromadí v místní proměnné, která se vrátí po iteraci celého pole prvků.
- Deklarujeme a inicializujeme celočíselné pole s pěti celočíselnými prvky. Vytiskneme celkový součet předáním názvu pole (který funguje jako adresa) a velikosti pole do funkce add_array () s názvem jako argumenty.
Funkce, které vrací pole
V C můžeme vrátit ukazatel na pole, jako v následujícím programu:
#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ýstup:
12345
A zde probereme podrobnosti o programu
- Definujeme a deklarujeme funkci, která vrací adresu pole obsahující celočíselnou hodnotu a nepřijala žádné argumenty.
- Deklarujeme celočíselný ukazatel, který přijímá celé pole vytvořené po volání funkce, a jeho obsah vytiskneme iterací celého pole pěti prvků.
Všimněte si, že ukazatel, nikoli pole, je definován pro uložení adresy pole vrácené funkcí. Všimněte si také, že když se z funkce vrací lokální proměnná, musíme ji ve funkci deklarovat jako statickou.
Ukazatele funkcí
Jak víme z definice, že ukazatele ukazují na adresu v jakémkoli paměťovém umístění, mohou také ukazovat na začátek spustitelného kódu jako funkce v paměti.
Ukazatel na funkci je deklarován znakem *, obecný příkaz jeho deklarace je:
return_type (*function_name)(arguments)
Musíte si uvědomit, že závorky kolem (* název_funkce) jsou důležité, protože bez nich si kompilátor bude myslet, že název_funkce vrací ukazatel typu return_type.
Po definování ukazatele funkce jej musíme přiřadit funkci. Například další program deklaruje běžnou funkci, definuje ukazatel funkce, přiřadí ukazatel funkce k běžné funkci a poté zavolá funkci pomocí ukazatele:
#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ýstup:
HiHiHi
- Definujeme a deklarujeme standardní funkci, která při volání funkce vytiskne Hi text k krát označený časy parametrů
- Definujeme funkci ukazatele (se speciální deklarací), která přebírá celočíselný parametr a nic nevrací.
- Inicializujeme naši funkci ukazatele pomocí Hi_function, což znamená, že ukazatel ukazuje na Hi_function ().
- Spíše než volání standardní funkce poklepáním na název funkce pomocí argumentů, voláme pouze funkci ukazatele předáním čísla 3 jako argumentů, a je to!
Mějte na paměti, že název funkce ukazuje na počáteční adresu spustitelného kódu jako název pole, který odkazuje na jeho první prvek. Pokyny jako function_ptr = & Hi_function a (* funptr) (3) jsou proto správné.
POZNÁMKA: Během přiřazování funkce a volání funkce není důležité vložit operátor adresy & a operátor indirekce *.
Pole ukazatelů funkcí
Pole funkčních ukazatelů může hrát rozhodovací roli přepínače nebo příkazu if, jako v dalším programu:
#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
Zde diskutujeme o podrobnostech programu:
- Deklarujeme a definujeme čtyři funkce, které berou dva celočíselné argumenty a vracejí celočíselnou hodnotu. Tyto funkce přidávají, odečítají, násobí a dělí dva argumenty týkající se toho, která funkce je volána uživatelem.
- Deklarujeme 4 celá čísla pro zpracování operandů, typu operace a výsledku. Deklarujeme také pole čtyř funkčních ukazatelů. Každý ukazatel funkce prvku pole přebírá dva parametry celých čísel a vrací celočíselnou hodnotu.
- Každý prvek pole přiřadíme a inicializujeme již deklarovanou funkcí. Například třetí prvek, který je třetím ukazatelem funkce, bude ukazovat na funkci operace násobení.
- Hledáme operandy a typ operace od uživatele zadaného pomocí klávesnice.
- Zavolali jsme příslušný prvek pole (ukazatel funkce) s argumenty a uložili jsme výsledek vygenerovaný příslušnou funkcí.
Instrukce int (* ope [4]) (int, int); definuje pole ukazatelů funkcí. Každý prvek pole musí mít stejné parametry a návratový typ.
Výsledek příkazu = ope [volba] (x, y); spustí příslušnou funkci podle volby provedené uživatelem Dvě zadaná celá čísla jsou argumenty předané funkci.
Funkce pomocí neplatných ukazatelů
Ukazatele prázdnoty se používají během deklarací funkcí. K vrácení libovolného typu používáme povolení typu void * return. Pokud předpokládáme, že se naše parametry při přechodu na funkci nezmění, deklarujeme to jako const.
Například:
void * cube (const void *);
Zvažte následující 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ýsledek:
4 cubed is 64
Zde probereme podrobnosti o programu:
- Definujeme a deklarujeme funkci, která vrací celočíselnou hodnotu a přijímá adresu nezměnitelné proměnné bez konkrétního datového typu. Vypočítáme hodnotu krychle proměnné obsahu (x), na kterou ukazuje ukazatel num, a protože se jedná o ukazatel prázdnoty, musíme zadat cast na celočíselný datový typ pomocí specifického ukazatele notace (* datový typ) a vrátíme se hodnotu krychle.
- Deklarujeme operand a výslednou proměnnou. Inicializujeme také náš operand s hodnotou „4.“
- Funkci krychle zavoláme předáním adresy operandu a vracíme hodnotu ve výsledné proměnné
Ukazatele funkcí jako argumenty
Další způsob, jak zneužít ukazatel funkce tak, že jej předáte jako argument jiné funkci, která se někdy nazývá „funkce zpětného volání“, protože přijímací funkce „ji volá zpět“.
V souboru záhlaví stdlib.h používá funkce Quicksort "qsort ()" tuto techniku, což je algoritmus určený k třídění pole.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void * base: void ukazatel na pole.
- size_t num: Číslo prvku pole.
- size_t width Velikost prvku.
- int (* porovnat (const void *, const void *): ukazatel funkce složený ze dvou argumentů a vrátí 0, pokud mají argumenty stejnou hodnotu, <0, když arg1 přijde před arg2, a> 0, když arg1 přijde po arg2.
Následující program třídí pole celých čísel od malého po velké pomocí funkce 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ýsledek:
13 14 48 50 52
Zde probereme podrobnosti o programu:
- Definujeme funkci porovnání složenou ze dvou argumentů a vrátí 0, když mají argumenty stejnou hodnotu, <0, když arg1 přijde před arg2, a> 0, když arg1 přijde po arg2. Parametry jsou typ ukazatelů void vržený na příslušný datový typ pole (celé číslo)
- Definujeme a inicializujeme celočíselné pole Velikost pole je uložena v proměnné num a velikost každého prvku pole je uložena v proměnné width pomocí předdefinovaného operátoru C sizeof ().
- Zavoláme funkci qsort a předáme název pole, velikost, šířku a srovnávací funkci definovanou uživatelem dříve, aby se naše pole seřadilo vzestupně. Porovnání bude provedeno tak, že v každé iteraci vezmeme dva prvky pole, dokud nebude celé pole budou seřazeny.
- Vytiskneme prvky pole, abychom se ujistili, že je naše pole dobře tříděno iterací celého pole pomocí smyčky for.