Un beneficio de utilizar dobles puntero dependiendo de lo que vallas a hacer con tu programa es hacer mejor uso de memoria dinamica.
Hace unos dias participe en el siguiente tema
Re: Sistema de cifrado por lote de texto plano Deje el codigo y utliza dobles punteros para almacenar unas listas de longitud dinámica cada lista.
El detalle que si los usas mal y/o no asginas y/o liberas memoria incorrectamente terminaras haciendo un completo desmadre y posiblemente el programa termine colgándose.
Imaginate esto, quieres hacer un programa que almacene las calificaciones de todos los alumnos de una escuela para despues hacer cualquier otro proceso con ellos.
int **calificaciones;
Estamos de acuerdo que la instrucción anterior solo "reserva" en la pila un espacio para guardar un apuntador.
int i,j;
int *alumnosXsalon;
int **calificaciones;
Mientras tanto en la pila se muestra asi (Uso 4 bytes para los int, y para los apuntadores asumo que estamos en un sistema x86):
Pila:
[4 bytes variable calificaciones] << === Un apuntador doble
[4 bytes variable alumnosXsalon] <<=== Un apuntador
[4 bytes variable j]
[4 bytes variable i]
Asignamos memoria para nuestra variable calificaciones Asumimos que son 30 salones, incluso se podria ser variable menos salones o mas salones incluso mil o un millon suponiendo que hay memoria suficiente no sera problema reservarla.
calificaciones
= calloc(30,sizeof(int*));
Como mencione si el apuntador es de 4 bytes, se nos devolvera una direccion de memoria de longitud 30x4 bytes y como es la funcion calloc la memoria esta limpia esto es los 120 bytes estaran en 0 cada uno.
calificaciones => [Bloque de 120 continuos]
ahora bien la variable calificaciones apunta a un espacio en memoria de 120 bytes donde podemos guardar lo que queramos, pero siguiendo con el ejemplo de apuntadores damos por hecho que cada 4 bytes es un apuntador a otra direccion de memoria (Actualmente no apuntan a ningun lugar ya que no hemos inicializado esos 30 apuntadores).
Como es un ejemplo didactico supondre que alumnosXsalon ya esta inicializado y es un arreglo 30 de enteros y cada uno indica la cantidad de alumnos en cada salon por ejemplo
alumnosXsalon = {20, 30, 10 , 24, 12, 3, 8, 18 , .....}
Ahora vamos a inicializar esos 30 apuntadores:
i = 0
while(i < 30) {
calificaicones
[i
] = calloc(alumnosXsalon
[i
],sizeof(int)); i++;
}
Con esto logramos reservamos la memoria para todas las calificaciones.
calificaciones ==>> [120 bytes, cada 4 bytes es un apuntador a otra segmento de memoria]
o ma claro aun
calificaciones => [[1ros apuntador => 20 enteros],[2do apuntador => 30 enteros], .... ]
Y ahora solo queria escribir las cientos de calificaciones en sus respectivos espacios asignados
Para entenderlo mejor ha que aprender a depurar un poco el código y mostrar las direcciones de memoria sus valores antes y depues asi como a donde estan apuntando.
Si dominas esto entenderas muy bien los apuntadores lo cual es una de las mejores caracteristicas del lenguaje C
Ejemplo comentado:
#include<stdio.h>
#include<stdlib.h>
int main() {
int i,j;
int alumnosXsalon[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30};
int **calificacion;
printf("i esta en 0x%.8x: [%i]\n",&i
,i
); printf("j esta en 0x%.8x: [%i]\n",&j
,j
); printf("alumnosXsalon esta en 0x%.8x: => %X\n",&alumnosXsalon
,alumnosXsalon
); printf("calificacion esta en 0x%.8x: => %X aun no se reserva memori\n",&calificacion
,calificacion
); calificacion
= calloc(30,sizeof(int*)); printf("calificacion esta en 0x%.8x: => %X ya se reservo la memoria\n",&calificacion
,calificacion
); i=0;
while(i < 30) {
printf("Reservado %i bytes\n",(alumnosXsalon
[i
]*sizeof(int))); calificacion
[i
] = calloc(alumnosXsalon
[i
],sizeof(int)); printf("calificacion[%i] esta en 0x%.8x: => %X un segmento de %i bytes \n",i
,calificacion
+ i
,calificacion
[i
],(alumnosXsalon
[i
]*sizeof(int))); i++;
}
}
Salida
i esta en 0xbfbfe834: [0]
j esta en 0xbfbfe830: [0]
alumnosXsalon esta en 0xbfbfe7b8: => BFBFE7B8
calificacion esta en 0xbfbfe7b4: => 1 aun no se reserva memori
calificacion esta en 0xbfbfe7b4: => 2880B080 ya se reservo la memoria
Reservado 4 bytes
calificacion[0] esta en 0x2880b080: => 2880D050 un segmento de 4 bytes
Reservado 8 bytes
calificacion[1] esta en 0x2880b084: => 2880D058 un segmento de 8 bytes
Reservado 12 bytes
calificacion[2] esta en 0x2880b088: => 2880E030 un segmento de 12 bytes
Reservado 16 bytes
calificacion[3] esta en 0x2880b08c: => 2880E040 un segmento de 16 bytes
Reservado 20 bytes
calificacion[4] esta en 0x2880b090: => 2880F020 un segmento de 20 bytes
Reservado 24 bytes
calificacion[5] esta en 0x2880b094: => 2880F040 un segmento de 24 bytes
Reservado 28 bytes
calificacion[6] esta en 0x2880b098: => 2880F060 un segmento de 28 bytes
Reservado 32 bytes
calificacion[7] esta en 0x2880b09c: => 2880F080 un segmento de 32 bytes
Reservado 36 bytes
calificacion[8] esta en 0x2880b0a0: => 28810040 un segmento de 36 bytes
Reservado 40 bytes
calificacion[9] esta en 0x2880b0a4: => 28810070 un segmento de 40 bytes
Reservado 44 bytes
calificacion[10] esta en 0x2880b0a8: => 288100A0 un segmento de 44 bytes
Reservado 48 bytes
calificacion[11] esta en 0x2880b0ac: => 288100D0 un segmento de 48 bytes
Reservado 52 bytes
calificacion[12] esta en 0x2880b0b0: => 28811040 un segmento de 52 bytes
Reservado 56 bytes
calificacion[13] esta en 0x2880b0b4: => 28811080 un segmento de 56 bytes
Reservado 60 bytes
calificacion[14] esta en 0x2880b0b8: => 288110C0 un segmento de 60 bytes
Reservado 64 bytes
calificacion[15] esta en 0x2880b0bc: => 28811100 un segmento de 64 bytes
Reservado 68 bytes
calificacion[16] esta en 0x2880b0c0: => 28812060 un segmento de 68 bytes
Reservado 72 bytes
calificacion[17] esta en 0x2880b0c4: => 288120B0 un segmento de 72 bytes
Reservado 76 bytes
calificacion[18] esta en 0x2880b0c8: => 28812100 un segmento de 76 bytes
Reservado 80 bytes
calificacion[19] esta en 0x2880b0cc: => 28812150 un segmento de 80 bytes
Reservado 84 bytes
calificacion[20] esta en 0x2880b0d0: => 28813040 un segmento de 84 bytes
Reservado 88 bytes
calificacion[21] esta en 0x2880b0d4: => 288130A0 un segmento de 88 bytes
Reservado 92 bytes
calificacion[22] esta en 0x2880b0d8: => 28813100 un segmento de 92 bytes
Reservado 96 bytes
calificacion[23] esta en 0x2880b0dc: => 28813160 un segmento de 96 bytes
Reservado 100 bytes
calificacion[24] esta en 0x2880b0e0: => 28814080 un segmento de 100 bytes
Reservado 104 bytes
calificacion[25] esta en 0x2880b0e4: => 288140F0 un segmento de 104 bytes
Reservado 108 bytes
calificacion[26] esta en 0x2880b0e8: => 28814160 un segmento de 108 bytes
Reservado 112 bytes
calificacion[27] esta en 0x2880b0ec: => 288141D0 un segmento de 112 bytes
Reservado 116 bytes
calificacion[28] esta en 0x2880b0f0: => 2880B100 un segmento de 116 bytes
Reservado 120 bytes
calificacion[29] esta en 0x2880b0f4: => 2880B180 un segmento de 120 bytes
Respondiendo tus preguntas:
Por ahí leí que los punteros dobles se asemejan a los array de 2 dimensiones, es esto cierto y porque?.
No del todo, depende de como se usen.
Si declaras un array de 2 dimenciones por ejemplo 15x10 es y sera siempre de 15x10.
En cambio si apuntador lo declaras de 15 x 10 es en ese momento de 15x10 y se podria quedar asi o modificarse, liberar la memoria asginar algunos elementos (digamos los primeros 5) a una longitud de solo 7 por ejemplo. Si se asemejan paro para fines didacticos pero los apuntadores son mejores. Ve el ejemplo anterior tengo un apuntador dinamico de 30 apuntadores apuntado a 1, 2, 3, 4, .. respectivamente,