Mint tudjuk, egy mutatót használnak egy változó címének C-ben történő tárolására. A mutató csökkenti a változó elérési idejét. C-ben azonban definiálhatunk egy mutatót is, amely egy másik mutató címét tárolja. Az ilyen mutatót dupla mutatónak (pointer to pointer) nevezik. Az első mutató egy változó címének tárolására szolgál, míg a második mutató az első mutató címének tárolására szolgál. Értsük meg az alábbi diagram alapján.
A kettős mutató deklarálásának szintaxisa alább látható.
int **p; // pointer to a pointer which is pointing to an integer.
Tekintsük a következő példát.
#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 }
Kimenet
address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10
C duplamutató példa
Nézzünk egy példát, ahol az egyik mutató egy másik mutató címére mutat.
Ahogy a fenti ábrán látható, a p2 tartalmazza p címét (fff2), p pedig a számváltozó címét (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; }
Kimenet
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
K. Mi lesz a következő program kimenete?
#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 }
Magyarázat
A fenti kérdésben a mutató aritmetikáját a kettős mutatóval együtt használjuk. Egy 6 elemből álló tömb van meghatározva, amelyet egy p mutató tömbje mutat. A p mutatótömbre egy pp dupla mutató mutat. A fenti kép azonban rövid képet ad arról, hogy a memória hogyan kerül lefoglalásra az a tömbhöz és a p mutatótömbhöz. A p elemei azok a mutatók, amelyek az a tömb minden elemére mutatnak. Mivel tudjuk, hogy a tömbnév tartalmazza a tömb alapcímét, ezért mutatóként fog működni, és az értéket át lehet-e haladni az *(a), *(a+1) stb. használatával. Ahogy a képen látható , a[0] a következő módokon érhető el.
- a[0]: ez a legegyszerűbb módja a tömb első elemének elérésének
- *(a): mivel egy a tömb első elemének címét tárolja, az értékét az indirect pointer használatával érhetjük el.
- *p[0]: ha az a[0]-t egy p mutató használatával kell elérni, akkor a p mutatótömb első elemén használhatjuk az indirekt operátort (*), azaz *p[0]-t.
- **(pp): mivel az pp a mutatótömb alapcímét tárolja, a *pp a mutatótömb első elemének az értékét adja meg, amely az egész tömb első elemének a címe. **p megadja az egész tömb első elemének tényleges értékét.
A programhoz érve az 1. és 2. sor relatíve deklarálja az egész számot és a mutatótömböt. A 3. sor inicializálja a dupla mutatót a p mutatótömbre. A képen látható módon, ha a tömb címe 200-tól kezdődik és az egész szám mérete 2, akkor a mutatótömb a 200, 202, 204, 206, 208, 210 értékeket fogja tartalmazni. a mutatótömb alapcíme 300; a pp kettős mutató tartalmazza a mutatótömb címét, azaz 300. A 4-es sor 1-gyel növeli a pp értékét, azaz a pp most a 302-es címre fog mutatni.
bharti jha
Az 5-ös sor egy olyan kifejezést tartalmaz, amely három értéket ír ki, azaz: pp - p, *pp - a, **pp. Számoljuk ki mindegyiket.
- pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, azaz 1 kerül kinyomtatásra.
- pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, azaz 1 kerül kinyomtatásra.
- pp = 302, *pp = 202, *(*pp) = 206, azaz 206 kerül kinyomtatásra.
Ezért az 5. sor eredményeként az 1, 1, 206 kimenet kerül kinyomtatásra a konzolra. A 6. sorban *pp++ van írva. Itt meg kell jegyeznünk, hogy két unáris * és ++ operátornak ugyanaz a prioritása. Ezért az asszociativitás szabálya szerint jobbról balra lesz értékelve. Ezért a *pp++ kifejezés átírható a következőre: (*(pp++)). Mivel pp = 302, amely most 304 lesz. *pp 204-et ad.
A 7. sorban ismét megjelenik az a kifejezés, amely három értéket ír ki, azaz: pp-p, *pp-a, *pp. Számoljuk ki mindegyiket.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, azaz 2 kerül kinyomtatásra.
- pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, azaz 2 kerül kinyomtatásra.
- pp = 304, *pp = 204, *(*pp) = 300, azaz 300 kerül kinyomtatásra.
Ezért a 7. sor eredményeként a 2, 2, 300 kimenet kerül kinyomtatásra a konzolra. A 8. sorban a ++*pp van írva. Az asszociativitás szabálya szerint ez átírható a következőre: (++(*(pp))). Mivel pp = 304, *pp = 204, a *pp = *(p[2]) = 206 értéke, amely most a[3]-ra mutat.
A 9. sorban ismét megjelenik az a kifejezés, amely három értéket ír ki, azaz: pp-p, *pp-a, *pp. Számoljuk ki mindegyiket.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, azaz 2 kerül kinyomtatásra.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, azaz 3 kerül kinyomtatásra.
- pp = 304, *pp = 206, *(*pp) = 409, azaz a 409 kerül kinyomtatásra.
Ezért a 9. sor eredményeként a 2, 3, 409 kimenet kerül kinyomtatásra a konzolra. A 10. sorban ++**pp van írva. az asszociativitás szabálya szerint ezt átírhatjuk így: (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. Más szóval a[3] = 410.
A 11. sorban ismét megjelenik az a kifejezés, amely három értéket ír ki, azaz: pp-p, *pp-a, *pp. Számoljuk ki mindegyiket.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, azaz 2 kerül kinyomtatásra.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, azaz 3 kerül kinyomtatásra.
- A 8. sorban **pp = 410.
Ezért a 9. sor eredményeként a 2, 3, 410 kimenet kerül kinyomtatásra a konzolra.
Végül a teljes program kimenete a következőképpen lesz megadva:
Kimenet
1 1 206 2 2 300 2 3 409 2 3 410