Com ho sabem, un punter s'utilitza per emmagatzemar l'adreça d'una variable en C. El punter redueix el temps d'accés d'una variable. Tanmateix, a C, també podem definir un punter per emmagatzemar l'adreça d'un altre punter. Aquest punter es coneix com a punter doble (punter a punter). El primer punter s'utilitza per emmagatzemar l'adreça d'una variable mentre que el segon punter s'utilitza per emmagatzemar l'adreça del primer punter. Entenem-ho amb el diagrama que es mostra a continuació.
La sintaxi de declarar un punter doble es mostra a continuació.
int **p; // pointer to a pointer which is pointing to an integer.
Considereu l'exemple següent.
#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 }
Sortida
address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10
Exemple de punter doble C
Vegem un exemple on un punter apunta a l'adreça d'un altre punter.
Com podeu veure a la figura anterior, p2 conté l'adreça de p (fff2) i p conté l'adreça de la variable numèrica (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; }
Sortida
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
P. Quina serà la sortida del programa següent?
#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 }
Explicació
A la pregunta anterior, s'utilitza l'aritmètica del punter amb el punter doble. Es defineix una matriu de 6 elements que està apuntada per una matriu de punter p. La matriu de punters p està apuntada per un punter doble pp. Tanmateix, la imatge de dalt us dóna una breu idea de com s'assigna la memòria a la matriu a ia la matriu de punters p. Els elements de p són els punters que apunten a tots els elements de la matriu a. Com que sabem que el nom de la matriu conté l'adreça base de la matriu, per tant, funcionarà com a punter i es pot recórrer el valor utilitzant *(a), *(a+1), etc. Com es mostra a la imatge , es pot accedir a a[0] de les maneres següents.
- a[0]: és la manera més senzilla d'accedir al primer element de la matriu
- *(a): com que emmagatzema l'adreça del primer element de la matriu, podem accedir al seu valor mitjançant el punter d'indirecció.
- *p[0]: si s'ha d'accedir a a[0] mitjançant un punter p, podem utilitzar l'operador d'indirecció (*) al primer element de la matriu de punters p, és a dir, *p[0].
- **(pp): com pp emmagatzema l'adreça base de la matriu de punters, *pp donarà el valor del primer element de la matriu de punters que és l'adreça del primer element de la matriu d'enters. **p donarà el valor real del primer element de la matriu enter.
Arribats al programa, les línies 1 i 2 declaren relativament la matriu d'enters i punters. La línia 3 inicialitza el punter doble a la matriu de punters p. Com es mostra a la imatge, si l'adreça de la matriu comença des de 200 i la mida de l'enter és 2, aleshores la matriu de punters contindrà els valors com 200, 202, 204, 206, 208, 210. Considerem que el l'adreça base de la matriu de punters és 300; el punter doble pp conté l'adreça de la matriu de punters, és a dir, 300. La línia número 4 augmenta el valor de pp en 1, és a dir, pp apuntarà ara a l'adreça 302.
La línia número 5 conté una expressió que imprimeix tres valors, és a dir, pp - p, *pp - a, **pp. Anem a calcular-los cadascun d'ells.
- pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, és a dir, s'imprimirà 1.
- pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, és a dir, s'imprimirà 1.
- pp = 302, *pp = 202, *(*pp) = 206, és a dir, s'imprimirà 206.
Per tant, com a resultat de la línia 5, la sortida 1, 1, 206 s'imprimirà a la consola. A la línia 6, s'escriu *pp++. Aquí, hem de notar que dos operadors unaris * i ++ tindran la mateixa prioritat. Per tant, per la regla de l'associativitat, s'avaluarà de dreta a esquerra. Per tant, l'expressió *pp++ es pot reescriure com a (*(pp++)). Com que, pp = 302 que ara es convertirà en 304. *pp donarà 204.
A la línia 7, de nou s'escriu l'expressió que imprimeix tres valors, és a dir, pp-p, *pp-a, *pp. Anem a calcular cadascun d'ells.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, és a dir, s'imprimirà 2.
- pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, és a dir, s'imprimirà 2.
- pp = 304, *pp = 204, *(*pp) = 300, és a dir, s'imprimiran 300.
Per tant, com a resultat de la línia 7, la sortida 2, 2, 300 s'imprimirà a la consola. A la línia 8, s'escriu ++*pp. Segons la regla de l'associativitat, això es pot reescriure com, (++(*(pp))). Com que, pp = 304, *pp = 204, el valor de *pp = *(p[2]) = 206 que ara apuntarà a a[3].
A la línia 9, de nou s'escriu l'expressió que imprimeix tres valors, és a dir, pp-p, *pp-a, *pp. Anem a calcular cadascun d'ells.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, és a dir, s'imprimirà 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, és a dir, s'imprimirà 3.
- pp = 304, *pp = 206, *(*pp) = 409, és a dir, s'imprimirà 409.
Per tant, com a resultat de la línia 9, la sortida 2, 3, 409 s'imprimirà a la consola. A la línia 10, s'escriu ++**pp. d'acord amb la regla de l'associativitat, es pot reescriure com, (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. És a dir, a[3] = 410.
A la línia 11, de nou s'escriu l'expressió que imprimeix tres valors, és a dir, pp-p, *pp-a, *pp. Anem a calcular cadascun d'ells.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, és a dir, s'imprimirà 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, és a dir, s'imprimirà 3.
- A la línia 8, **pp = 410.
Per tant, com a resultat de la línia 9, la sortida 2, 3, 410 s'imprimirà a la consola.
Finalment, la sortida del programa complet es donarà com:
Sortida
1 1 206 2 2 300 2 3 409 2 3 410