Como sabemos, se utiliza un puntero para almacenar la dirección de una variable en C. El puntero reduce el tiempo de acceso de una variable. Sin embargo, en C también podemos definir un puntero para almacenar la dirección de otro puntero. Este tipo de puntero se conoce como puntero doble (puntero a puntero). El primer puntero se usa para almacenar la dirección de una variable, mientras que el segundo puntero se usa para almacenar la dirección del primer puntero. Entendámoslo mediante el diagrama que figura a continuación.
La sintaxis para declarar un puntero doble se proporciona a continuación.
int **p; // pointer to a pointer which is pointing to an integer.
Considere el siguiente ejemplo.
#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 }
Producción
address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10
Ejemplo de doble puntero en C
Veamos un ejemplo donde un puntero apunta a la dirección de otro puntero.
Como puede ver en la figura anterior, p2 contiene la dirección de p (fff2) y p contiene la dirección 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; }
Producción
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. ¿Cuál será el resultado del siguiente 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 }
Explicación
En la pregunta anterior, la aritmética de punteros se utiliza con el puntero doble. Se define una matriz de 6 elementos apuntada por una matriz de puntero p. La matriz de punteros p está apuntada por un puntero doble pp. Sin embargo, la imagen de arriba le brinda una breve idea sobre cómo se asigna la memoria a la matriz a y a la matriz de punteros p. Los elementos de p son los punteros que apuntan a cada elemento de la matriz a. Como sabemos que el nombre de la matriz contiene la dirección base de la matriz, funcionará como un puntero y el valor se puede recorrer usando *(a), *(a+1), etc. Como se muestra en la imagen , se puede acceder a a[0] de las siguientes maneras.
- a[0]: es la forma más sencilla de acceder al primer elemento del array
- *(a): dado que almacena la dirección del primer elemento de la matriz, podemos acceder a su valor utilizando un puntero de indirección sobre él.
- *p[0]: si se va a acceder a [0] usando un puntero p, entonces podemos usar el operador de indirección (*) en el primer elemento de la matriz de puntero p, es decir, *p[0].
- **(pp): como pp almacena la dirección base de la matriz de punteros, *pp dará el valor del primer elemento de la matriz de punteros que es la dirección del primer elemento de la matriz de enteros. **p dará el valor real del primer elemento de la matriz de enteros.
Al llegar al programa, las líneas 1 y 2 declaran la matriz de números enteros y punteros de forma relativa. La línea 3 inicializa el puntero doble a la matriz de punteros p. Como se muestra en la imagen, si la dirección de la matriz comienza en 200 y el tamaño del número entero es 2, entonces la matriz de puntero contendrá los valores 200, 202, 204, 206, 208, 210. Consideremos que la la dirección base de la matriz de punteros es 300; el puntero doble pp contiene la dirección de la matriz de punteros, es decir, 300. La línea número 4 aumenta el valor de pp en 1, es decir, pp ahora apuntará a la dirección 302.
La línea número 5 contiene una expresión que imprime tres valores, es decir, pp - p, *pp - a, **pp. Calculémoslos cada uno de ellos.
- pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, es decir, se imprimirá 1.
- pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, es decir, se imprimirá 1.
- pp = 302, *pp = 202, *(*pp) = 206, es decir, se imprimirá 206.
Por lo tanto, como resultado de la línea 5, la salida 1, 1, 206 se imprimirá en la consola. En la línea 6, se escribe *pp++. Aquí debemos notar que dos operadores unarios * y ++ tendrán la misma precedencia. Por tanto, por la regla de asociatividad, se evaluará de derecha a izquierda. Por lo tanto, la expresión *pp++ se puede reescribir como (*(pp++)). Ya que, pp = 302 que ahora se convertirá en 304. *pp dará 204.
En la línea 7, nuevamente se escribe la expresión que imprime tres valores, es decir, pp-p, *pp-a, *pp. Calculemos cada uno de ellos.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, es decir, se imprimirá 2.
- pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, es decir, se imprimirá 2.
- pp = 304, *pp = 204, *(*pp) = 300, es decir, se imprimirán 300.
Por lo tanto, como resultado de la línea 7, la salida 2, 2, 300 se imprimirá en la consola. En la línea 8, se escribe +***pp. Según la regla de asociatividad, esto se puede reescribir como (++(*(pp))). Ya que, pp = 304, *pp = 204, el valor de *pp = *(p[2]) = 206 que ahora apuntará a a[3].
En la línea 9, nuevamente se escribe la expresión que imprime tres valores, es decir, pp-p, *pp-a, *pp. Calculemos cada uno de ellos.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, es decir, se imprimirá 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, es decir, se imprimirá 3.
- pp = 304, *pp = 206, *(*pp) = 409, es decir, se imprimirá 409.
Por lo tanto, como resultado de la línea 9, la salida 2, 3, 409 se imprimirá en la consola. En la línea 10, se escribe ++**pp. De acuerdo con la regla de asociatividad, esto se puede reescribir como (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. En otras palabras, a[3] = 410.
En la línea 11, nuevamente se escribe la expresión que imprime tres valores, es decir, pp-p, *pp-a, *pp. Calculemos cada uno de ellos.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, es decir, se imprimirá 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, es decir, se imprimirá 3.
- En la línea 8, **pp = 410.
Por lo tanto, como resultado de la línea 9, la salida 2, 3, 410 se imprimirá en la consola.
Por último, el resultado del programa completo quedará como:
Producción
1 1 206 2 2 300 2 3 409 2 3 410