Saltar al contenido

¿Qué significa tener dos asteriscos ** en Objective-C?

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:

ingrese la descripción de la imagen aquí

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 de p2 es decir, 5000
  • *p1 es el valor de p2 es decir, 8000
  • **p1 es el valor en 8000 es decir c
    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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *