Kot vemo, se kazalec uporablja za shranjevanje naslova spremenljivke v C. Kazalec zmanjša čas dostopa do spremenljivke. Vendar pa lahko v C-ju definiramo tudi kazalec za shranjevanje naslova drugega kazalca. Tak kazalec je znan kot dvojni kazalec (kazalec na kazalec). Prvi kazalec se uporablja za shranjevanje naslova spremenljivke, medtem ko se drugi kazalec uporablja za shranjevanje naslova prvega kazalca. Razumejmo ga s spodnjim diagramom.
Sintaksa deklaracije dvojnega kazalca je podana spodaj.
int **p; // pointer to a pointer which is pointing to an integer.
Razmislite o naslednjem primeru.
#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 }
Izhod
address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10
Primer dvojnega kazalca C
Oglejmo si primer, kjer en kazalec kaže na naslov drugega kazalca.
Kot lahko vidite na zgornji sliki, p2 vsebuje naslov p (fff2), p pa vsebuje naslov številske spremenljivke (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; }
Izhod
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
V. Kakšen bo rezultat naslednjega programa?
#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 }
Pojasnilo
V zgornjem vprašanju je aritmetika kazalca uporabljena z dvojnim kazalcem. Definiran je niz 6 elementov, na katerega kaže niz kazalca p. Na niz kazalcev p kaže dvojni kazalec pp. Vendar vam zgornja slika daje kratko predstavo o tem, kako je pomnilnik dodeljen nizu a in nizu kazalcev p. Elementi p so kazalci, ki kažejo na vsak element matrike a. Ker vemo, da ime matrike vsebuje osnovni naslov matrike, bo delovalo kot kazalec in lahko vrednost prečkamo z uporabo *(a), *(a+1) itd. Kot je prikazano na sliki , a[0] lahko dostopate na naslednje načine.
- a[0]: je najenostavnejši način za dostop do prvega elementa matrike
- *(a): ker a shrani naslov prvega elementa matrike, lahko do njegove vrednosti dostopamo z uporabo posrednega kazalca na njem.
- *p[0]: če je treba do [0] dostopati z uporabo kazalca p nanj, potem lahko uporabimo posredni operator (*) na prvem elementu niza kazalcev p, tj. *p[0].
- **(pp): ker pp shrani osnovni naslov matrike kazalcev, bo *pp dal vrednost prvega elementa matrike kazalcev, ki je naslov prvega elementa matrike celih števil. **p bo dal dejansko vrednost prvega elementa niza celih števil.
Ko pridemo do programa, vrstica 1 in 2 relativno deklarirata niz celih števil in kazalcev. Vrstica 3 inicializira dvojni kazalec na matriko kazalcev p. Kot je prikazano na sliki, če se naslov matrike začne pri 200 in je velikost celega števila 2, bo matrika kazalcev vsebovala vrednosti kot 200, 202, 204, 206, 208, 210. Predpostavimo, da osnovni naslov matrike kazalcev je 300; dvojni kazalec pp vsebuje naslov niza kazalcev, tj. 300. Vrstica številka 4 poveča vrednost pp za 1, tj. pp bo zdaj kazal na naslov 302.
Vrstica številka 5 vsebuje izraz, ki izpiše tri vrednosti, tj. pp - p, *pp - a, **pp. Izračunajmo vsakega od njih.
- pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, tj. natisnjena bo 1.
- pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, tj. natisnjena bo 1.
- pp = 302, *pp = 202, *(*pp) = 206, tj. 206 bo natisnjenih.
Zato bo kot rezultat vrstice 5 na konzoli natisnjen izhod 1, 1, 206. V 6. vrstici je zapisano *pp++. Tukaj moramo opaziti, da bosta dva unarna operatorja * in ++ imela enako prednost. Zato bo po pravilu asociativnosti ovrednoten od desne proti levi. Zato lahko izraz *pp++ prepišemo kot (*(pp++)). Ker je pp = 302, kar bo zdaj postalo 304. *pp bo dalo 204.
V vrstici 7 je ponovno zapisan izraz, ki izpiše tri vrednosti, to so pp-p, *pp-a, *pp. Izračunajmo vsakega od njih.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, tj. izpisano bo 2.
- pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, tj. izpisano bo 2.
- pp = 304, *pp = 204, *(*pp) = 300, tj. natisnjenih bo 300.
Zato bo kot rezultat vrstice 7 na konzoli natisnjen izhod 2, 2, 300. V vrstici 8 je zapisano +*pp. V skladu s pravilom asociativnosti je to mogoče prepisati kot (++(*(pp))). Ker je pp = 304, *pp = 204, je vrednost *pp = *(p[2]) = 206, ki bo zdaj kazala na a[3].
V 9. vrstici je ponovno zapisan izraz, ki izpiše tri vrednosti, to so pp-p, *pp-a, *pp. Izračunajmo vsakega od njih.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, tj. izpisano bo 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, tj. izpisano bo 3.
- pp = 304, *pp = 206, *(*pp) = 409, tj. 409 bo natisnjenih.
Zato bo kot rezultat vrstice 9 na konzoli natisnjen izhod 2, 3, 409. V 10. vrstici je zapisano ++**pp. v skladu s pravilom asociativnosti je to mogoče prepisati kot (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. Z drugimi besedami, a[3] = 410.
V 11. vrstici je spet zapisan izraz, ki izpiše tri vrednosti, to so pp-p, *pp-a, *pp. Izračunajmo vsakega od njih.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, tj. izpisano bo 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, tj. izpisano bo 3.
- V vrstici 8, **pp = 410.
Zato bo kot rezultat vrstice 9 na konzoli natisnjen izhod 2, 3, 410.
Končno bo rezultat celotnega programa podan kot:
Izhod
1 1 206 2 2 300 2 3 409 2 3 410