Diego, parte de este gran equipo, nos ha hecho el favor de crear esta reseña ya que domina a la perfección dicho tema.
Solución:
Es un puntero a un puntero, como en C (en el que, a pesar de su extraña sintaxis de corchetes, se basa Objective-C):
char c;
char *pc = &c;
char **ppc = &pc;
char ***pppc = &ppc;
y así sucesivamente, ad infinitum (o hasta que se quede sin espacio variable).
A menudo se usa para pasar un puntero a una función que debe poder cambiar el puntero en sí (como reasignar memoria para un objeto de tamaño variable).
=====
Siguiendo su solicitud de una muestra que muestra cómo usarlo, aquí hay un código que escribí para otra publicación que lo ilustra. Se trata de un appendStr()
función que gestiona sus propias asignaciones (todavía tienes que liberar la versión final). Inicialmente configura el string (char *
) a NULL y la propia función asignará espacio según sea necesario.
#include
#include
#include
void appendToStr (int *sz, char **str, char *app)
char *newstr;
int reqsz;
/* If no string yet, create it with a bit of space. */
if (*str == NULL)
*sz = strlen (app) + 10;
if ((*str = malloc (*sz)) == NULL)
*sz = 0;
return;
strcpy (*str, app);
return;
/* If not enough room in string, expand it. We could use realloc
but I've kept it as malloc/cpy/free to ensure the address
changes (for the program output). */
reqsz = strlen (*str) + strlen (app) + 1;
if (reqsz > *sz)
*sz = reqsz + 10;
if ((newstr = malloc (*sz)) == NULL)
free (*str);
*str = NULL;
*sz = 0;
return;
strcpy (newstr, *str);
free (*str);
*str = newstr;
/* Append the desired string to the (now) long-enough buffer. */
strcat (*str, app);
static void dump(int sz, char *x)
if (x == NULL)
printf ("%8p [%2d] %3d [%s]n", x, sz, 0, "");
else
printf ("%8p [%2d] %3d [%s]n", x, sz, strlen (x), x);
static char *arr[] = "Hello.", " My", " name", " is", " Pax",
" and"," I", " am", " old.";
int main (void)
int i;
char *x = NULL;
int sz = 0;
printf (" Pointer Size Len Valuen");
printf (" ------- ---- --- -----n");
dump (sz, x);
for (i = 0; i < sizeof (arr) / sizeof (arr[0]); i++)
appendToStr (&sz, &x, arr[i]);
dump (sz, x);
El código genera lo siguiente. Puede ver cómo cambia el puntero cuando la memoria asignada actualmente se queda sin espacio para la expansión string (en los comentarios):
Pointer Size Len Value
------- ---- --- -----
# NULL pointer here since we've not yet put anything in.
0x0 [ 0] 0 []
# The first time we put in something, we allocate space (+10 chars).
0x6701b8 [16] 6 [Hello.]
0x6701b8 [16] 9 [Hello. My]
0x6701b8 [16] 14 [Hello. My name]
# Adding " is" takes length to 17 so we need more space.
0x6701d0 [28] 17 [Hello. My name is]
0x6701d0 [28] 21 [Hello. My name is Pax]
0x6701d0 [28] 25 [Hello. My name is Pax and]
0x6701d0 [28] 27 [Hello. My name is Pax and I]
# Ditto for adding " am".
0x6701f0 [41] 30 [Hello. My name is Pax and I am]
0x6701f0 [41] 35 [Hello. My name is Pax and I am old.]
En ese caso, pasas **str
ya que necesita poder cambiar el *str
valor.
=====
O lo siguiente, que hace una clasificación de burbuja desenrollada (¡oh, qué lástima!) En cadenas que no están en un array. Lo hace intercambiando directamente las direcciones de las cadenas.
#include
static void sort (char **s1, char **s2, char **s3, char **s4, char **s5)
char *t;
if (strcmp (*s1, *s2) > 0) t = *s1; *s1 = *s2; *s2 = t;
if (strcmp (*s2, *s3) > 0) t = *s2; *s2 = *s3; *s3 = t;
if (strcmp (*s3, *s4) > 0) t = *s3; *s3 = *s4; *s4 = t;
if (strcmp (*s4, *s5) > 0) t = *s4; *s4 = *s5; *s5 = t;
if (strcmp (*s1, *s2) > 0) t = *s1; *s1 = *s2; *s2 = t;
if (strcmp (*s2, *s3) > 0) t = *s2; *s2 = *s3; *s3 = t;
if (strcmp (*s3, *s4) > 0) t = *s3; *s3 = *s4; *s4 = t;
if (strcmp (*s1, *s2) > 0) t = *s1; *s1 = *s2; *s2 = t;
if (strcmp (*s2, *s3) > 0) t = *s2; *s2 = *s3; *s3 = t;
if (strcmp (*s1, *s2) > 0) t = *s1; *s1 = *s2; *s2 = t;
int main (int argCount, char *argVar[])
char *a = "77";
char *b = "55";
char *c = "99";
char *d = "88";
char *e = "66";
printf ("Unsorted: [%s] [%s] [%s] [%s] [%s]n", a, b, c, d, e);
sort (&a,&b,&c,&d,&e);
printf (" Sorted: [%s] [%s] [%s] [%s] [%s]n", a, b, c, d, e);
return 0;
que produce:
Unsorted: [77] [55] [99] [88] [66]
Sorted: [55] [66] [77] [88] [99]
No importa la implementación de sort, solo observe que las variables se pasan como char **
para que puedan intercambiarse fácilmente. Cualquier tipo real probablemente estaría actuando en un true array de datos en lugar de variables individuales, pero ese no es el objetivo del ejemplo.
Puntero a puntero
La definición de "puntero" dice que es una variable especial que almacena el Dirección de otra variable (no el valor). Esa otra variable puede muy bien ser un puntero. Esto significa que es perfectamente legal que un puntero apunte a otro puntero.
Supongamos que tenemos un puntero p1
que apunta a otro puntero p2
que apunta a un personaje c
. En memoria, las tres variables se pueden visualizar como:
Entonces podemos ver eso en la memoria, puntero p1
contiene la dirección del puntero p2
. Puntero p2
tiene la dirección del personaje c
.
Entonces p2
es un puntero al personaje c
, tiempo p1
es puntero a p2
. O también podemos decir que p2
es un puntero a un puntero a un personaje c
.
Ahora, en código p2
puede declararse como:
char * p2 = & c;
Pero p1
se declara como:
char ** p1 = & p2;
Entonces vemos eso p1
es un puntero doble (es decir, un puntero a un puntero a un carácter) y, por lo tanto, los dos * s en la declaración.
Ahora,
p1
es la direccion dep2
es decir, 5000*p1
es el valor dep2
es decir, 8000**p1
es el valor en 8000 es decirc
Creo que eso debería aclarar bastante el concepto, tomemos un pequeño ejemplo:
Fuente: http://www.thegeekstuff.com/2012/01/advanced-c-pointers/
Para algunos de sus casos de uso:
Esto generalmente se usa para pasar un puntero a una función que debe poder cambiar el puntero en sí, algunos de sus casos de uso son:
- Como en el manejo de errores, permite que el método de recepción controle a qué se refiere el puntero. Ver esta pregunta
- Para crear una estructura opaca, es decir, para que otros no puedan asignar espacio. Ver esta pregunta
- En caso de expansión de memoria mencionada en las otras respuestas de esta pregunta.
siéntete libre de editar / mejorar esta respuesta mientras aprendo:]
Si conservas alguna desconfianza y forma de aclarar nuestro artículo te inspiramos añadir un paráfrasis y con placer lo ojearemos.