Jak víme, ukazatel se používá k uložení adresy proměnné v C. Ukazatel snižuje dobu přístupu proměnné. V C však můžeme také definovat ukazatel pro uložení adresy jiného ukazatele. Takový ukazatel je známý jako dvojitý ukazatel (ukazatel na ukazatel). První ukazatel se používá k uložení adresy proměnné, zatímco druhý ukazatel se používá k uložení adresy prvního ukazatele. Pochopme to podle níže uvedeného diagramu.
Syntaxe deklarování dvojitého ukazatele je uvedena níže.
int **p; // pointer to a pointer which is pointing to an integer.
Zvažte následující příklad.
linuxové soubory
#include void main () { int a = 10; int *p; int **pp; p = &a; // pointer p is pointing to the address of a pp = &p; // pointer pp is a double pointer pointing to the address of pointer p printf('address of a: %x ',p); // Address of a will be printed printf('address of p: %x ',pp); // Address of p will be printed printf('value stored at p: %d ',*p); // value stoted at the address contained by p i.e. 10 will be printed printf('value stored at pp: %d ',**pp); // value stored at the address contained by the pointer stoyred at pp }
Výstup
address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10
C příklad dvojitého ukazatele
Podívejme se na příklad, kdy jeden ukazatel ukazuje na adresu jiného ukazatele.
Jak můžete vidět na obrázku výše, p2 obsahuje adresu p (fff2) a p obsahuje adresu číselné proměnné (fff4).
#include int main(){ int number=50; int *p;//pointer to int int **p2;//pointer to pointer p=&number;//stores the address of number variable p2=&p; printf('Address of number variable is %x ',&number); printf('Address of p variable is %x ',p); printf('Value of *p variable is %d ',*p); printf('Address of p2 variable is %x ',p2); printf('Value of **p2 variable is %d ',*p); return 0; }
Výstup
Address of number variable is fff4 Address of p variable is fff4 Value of *p variable is 50 Address of p2 variable is fff2 Value of **p variable is 50
Otázka: Co bude výstupem následujícího programu?
#include void main () { int a[10] = {100, 206, 300, 409, 509, 601}; //Line 1 int *p[] = {a, a+1, a+2, a+3, a+4, a+5}; //Line 2 int **pp = p; //Line 3 pp++; // Line 4 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 5 *pp++; // Line 6 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 7 ++*pp; // Line 8 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 9 ++**pp; // Line 10 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 11 }
Vysvětlení
Ve výše uvedené otázce se aritmetika ukazatele používá s dvojitým ukazatelem. Je definováno pole 6 prvků, na které ukazuje pole ukazatele p. Pole ukazatelů p ukazuje dvojitý ukazatel pp. Obrázek výše vám však poskytuje stručnou představu o tom, jak je paměť přidělována poli a a poli ukazatelů p. Prvky p jsou ukazatele, které ukazují na každý prvek pole a. Protože víme, že název pole obsahuje základní adresu pole, bude fungovat jako ukazatel a lze hodnotu procházet pomocí *(a), *(a+1) atd. Jak je znázorněno na obrázku , a[0] lze získat následujícími způsoby.
linuxový souborový systém
- a[0]: je to nejjednodušší způsob přístupu k prvnímu prvku pole
- *(a): protože ukládáme adresu prvního prvku pole, můžeme přistupovat k jeho hodnotě pomocí nepřímého ukazatele.
- *p[0]: pokud má být a[0] zpřístupněno pomocí ukazatele p na něj, pak můžeme použít nepřímý operátor (*) na prvním prvku pole ukazatelů p, tj. *p[0].
- **(pp): protože pp ukládá základní adresu pole ukazatelů, *pp udává hodnotu prvního prvku pole ukazatelů, což je adresa prvního prvku pole celých čísel. **p udává skutečnou hodnotu prvního prvku celočíselného pole.
Když přijdeme k programu, řádek 1 a 2 deklarují pole celých čísel a ukazatelů relativně. Řádek 3 inicializuje dvojitý ukazatel na pole ukazatelů p. Jak je znázorněno na obrázku, pokud adresa pole začíná od 200 a velikost celého čísla je 2, pak pole ukazatelů bude obsahovat hodnoty jako 200, 202, 204, 206, 208, 210. Uvažujme, že základní adresa pole ukazatelů je 300; dvojitý ukazatel pp obsahuje adresu pole ukazatelů, tj. 300. Řádek číslo 4 zvyšuje hodnotu pp o 1, tj. pp nyní bude ukazovat na adresu 302.
Řádek číslo 5 obsahuje výraz, který vypíše tři hodnoty, tj. pp - p, *pp - a, **pp. Pojďme je spočítat každý z nich.
- pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, tj. vytiskne se 1.
- pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, tj. vytiskne se 1.
- pp = 302, *pp = 202, *(*pp) = 206, tj. vytiskne se 206.
Proto jako výsledek řádku 5 bude výstup 1, 1, 206 vytištěn na konzole. Na řádku 6 je napsáno *pp++. Zde si musíme všimnout, že dva unární operátory * a ++ budou mít stejnou přednost. Proto se podle pravidla asociativity bude vyhodnocovat zprava doleva. Proto lze výraz *pp++ přepsat jako (*(pp++)). Protože pp = 302, což se nyní stane 304. *pp dá 204.
Na řádku 7 je opět napsán výraz, který vypíše tři hodnoty, tj. pp-p, *pp-a, *pp. Pojďme spočítat každou z nich.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, tj. vytiskne se 2.
- pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, tj. vytiskne se 2.
- pp = 304, *pp = 204, *(*pp) = 300, tj. vytiskne se 300.
Proto jako výsledek řádku 7 bude výstup 2, 2, 300 vytištěn na konzole. Na řádku 8 je napsáno +**pp. Podle pravidla asociativity to lze přepsat jako, (++(*(pp))). Protože pp = 304, *pp = 204, hodnota *pp = *(p[2]) = 206, která nyní bude ukazovat na a[3].
jaké měsíce jsou q1
Na řádku 9 se opět napíše výraz, který vypíše tři hodnoty, tj. pp-p, *pp-a, *pp. Pojďme spočítat každý z nich.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, tj. vytiskne se 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, tj. vytiskne se 3.
- pp = 304, *pp = 206, *(*pp) = 409, tj. vytiskne se 409.
Proto jako výsledek řádku 9 bude výstup 2, 3, 409 vytištěn na konzole. Na řádku 10 se zapíše ++**pp. podle pravidla asociativity to lze přepsat jako, (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. Jinými slovy, a[3] = 410.
Na řádku 11 je opět napsán výraz, který vypíše tři hodnoty, tj. pp-p, *pp-a, *pp. Pojďme spočítat každou z nich.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, tj. vytiskne se 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, tj. vytiskne se 3.
- Na řádku 8, **pp = 410.
Proto jako výsledek řádku 9 bude výstup 2, 3, 410 vytištěn na konzole.
Nakonec bude výstup kompletního programu uveden jako:
Výstup
1 1 206 2 2 300 2 3 409 2 3 410