Apuntar a un puntero parece una redundancia pero tiene sus usos:
1. Construcción de una tabla de forma dinámica:
Para un compilador que no implemente el estándar C99 o superior la única forma de obtener una tabla de MxN de la que las dimensiones no se conocen en tiempo de programación (a partir de ahora en tiempo de compilación) es usando punteros e instrucciones alloc. Ejemplo:
int **tabla;
int m, n;
int i;
/* Se obtienen las dimensiones de la tabla m y n
* n para el número de filas
* m para el número de columnas
*/
/* Se genera el primer array dinámico que contendrá n filas */
tabla
= malloc(sizeof(int*) * filas
);
/* Las filas son punteros porqué contendrán la dirección de inicio
* del array columnas.
* Por tanto, para cada elemento de filas, reservamos una porción de
* memoria de m elementos.
*/
for(i = 0; i < filas; ++i)
tabla
[i
] = malloc(sizeof(int) * columnas
); /* Se puede apreciar notación de array para un puntero */
2. Construcción de una tabla de diente de sierra.
Es parecido al anterior pero con la ventaja de que se gasta menos memoria.
Si, por ejemplo, se necesita una tabla de la siguiente forma:
123456
123
1
123456
123
Se puede generar de la siguiente manera:
int **tabla;
int m, n;
int i;
/* Obtenemos el número de filas: n */
tabla
= malloc(sizeof(*int) * n
);
for(i = 0; i < n; ++i) {
/* Obtenemos el número de columnas m de la fila actual i */
/* Creamos el array de m columnas */
tabla
[i
] = malloc(sizeof(int) * m
);}
3. Cambiar la dirección a la que apunta un puntero e una función externa
Tenemos un dato definido por nosotros, por ejemplo una lista, y decidimos que tenga una funcinalidad, una función, que borre un nodo y deje ese puntero del nodo NULL para no tener problemas extraños si más adelante se referenciara ese nodo borrado: al ser NULL se pararía el programa y se lanzaría un mensaje de error, con lo que nos ayudaría con la depuración.
La función sería así:
/* Supongamos lo siguiente */
typedef struct node_t {
int i;
node_t *next;
} node;
void free_node(node **n) {
node *aux = *n;
if(aux) {
*n = NULL;
}
/* === Código que llama a la función === */
/* Supongamos nodo como un elemento que ya tiene memoria asignada
* con malloc, es decir: *
* node *nodo = malloc(sizeof(node));
* o una función que genere e inicialice un dato node.
* Ya hemos trabajado con él y ahora debemos borrarlo. Además
* se debe llevar a NULL el puntero, por lo que haremos uso
* de la función free_node que forma parte de las funciones de éste tipo
* de datos.
*/
free_node(&nodo);
Hay más funcionalidades para punteros a punteros, pero estas son las más comunes. Ya las irás viendo a medida que avances con C.