2009-05-07 10 views
14

Capisco che avere un asterisco * sia un puntatore, cosa significa avere due **?Cosa significa avere due asterischi ** in Objective-C?

ho imbattervi in ​​questo dalla documentazione:

- (NSAppleEventDescriptor *)executeAndReturnError:(NSDictionary **)errorInfo 
+0

selvaggio indovinare: un puntatore nel cursore? :) – Constantin

+0

sì, stavo anche io a indovinare, ma non ho trovato nessuna conferma da google. :) – John

risposta

32

E 'un puntatore a un puntatore, proprio come in C (che, nonostante la sua strana sintassi parentesi quadre, Objective-C si basa su):

char c; 
char *pc = &c; 
char **ppc = &pc; 
char ***pppc = &ppc; 

e così via, all'infinito (o fino a quando sei a corto di spazio variabile).

Viene spesso utilizzato per passare un puntatore a una funzione che deve essere in grado di modificare il puntatore stesso (come ad esempio la ridistribuzione della memoria per un oggetto di dimensioni variabili).

=====

In seguito alla vostra richiesta di un esempio che mostra come usarlo, ecco qualche codice che ho scritto per un altro post che lo illustra. È una funzione appendStr() che gestisce le proprie allocazioni (è ancora necessario liberare la versione finale). Inizialmente si imposta la stringa (char *) su NULL e la funzione stessa allocherà lo spazio necessario.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

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 Value\n"); 
    printf (" ------- ---- --- -----\n"); 
    dump (sz, x); 
    for (i = 0; i < sizeof (arr)/sizeof (arr[0]); i++) { 
     appendToStr (&sz, &x, arr[i]); 
     dump (sz, x); 
    } 
} 

Il codice emette il seguente. Si può vedere come il puntatore cambia quando la memoria attualmente allocata esaurisce lo spazio per la stringa espansa (i commenti):

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.] 

In tal caso, si passa **str in quanto è necessario essere in grado di cambiare la Valore *str.

=====

o il seguente, che fa un srotolato bubble sort (oh, che vergogna!) Su stringhe che non sono in un array. Lo fa scambiando direttamente gli indirizzi delle stringhe.

#include <stdio.h> 

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; 
} 

che produce:

Unsorted: [77] [55] [99] [88] [66] 
    Sorted: [55] [66] [77] [88] [99] 

Non importa l'attuazione di specie, basta notare che le variabili sono passati come char ** in modo che possano essere scambiati facilmente. Qualsiasi tipo reale probabilmente agirà su una vera matrice di dati piuttosto che su singole variabili, ma non è questo il punto dell'esempio.

+0

C ed i suoi puntatori mi confondono ... :( –

+0

Puoi approfondire come lo useresti in codice? Questo mi impressiona ancora su come usarlo – John

+1

Wow, ho bisogno di tempo per digerire ... ma grazie !! – John

1

Un puntatore a un puntatore.

1

In C i puntatori e gli array possono essere trattati allo stesso modo, ad es. char * è una stringa (matrice di caratteri). Se si desidera passare una matrice di array (ad esempio molte stringhe) a una funzione, è possibile utilizzare char **.

+0

Con una differenza: sizeof (char [])! = Sizeof (char *): molte persone sono state morse da questo. – paxdiablo

1

(riferimento: più iOS 6 sviluppo)

Nei metodi Objective-C, argomenti, inclusi puntatori all'oggetto, sono passato per valore, il che significa che il metodo chiamato ottiene la propria copia del puntatore passato. Quindi, se il metodo chiamato vuole cambiare il puntatore, in contrasto con i dati a cui punta il puntatore, è necessario un altro livello di riferimento indiretto per lo . Quindi, il puntatore al puntatore.

0

Puntatore Puntatore

Come la definizione di puntatore dice che la sua una variabile speciale che può memorizzare l'indirizzo di un altra variabile. Quindi l'altra variabile può benissimo essere un puntatore. Ciò significa che è perfettamente legale per un puntatore puntare a un altro puntatore.

Supponiamo di avere un puntatore p1 che punta a un altro puntatore p2 che punta a un carattere c. In memoria, le tre variabili possono essere visualizzate come:

enter image description here

Così possiamo vedere che in memoria, puntatore p1 contiene l'indirizzo del puntatore p2. Il puntatore p2 contiene l'indirizzo del carattere c.

Così p2 è puntatore a carattere c, mentre p1 è puntatore a p2 o possiamo anche dire che p2 è un puntatore a puntatore a carattere c.

Ora, nel codice p2 può essere dichiarato come:

char * p2 = & c;

Ma p1 è dichiarato come:

char ** p1 = &p2;

Così vediamo che p1 è un doppio puntatore (cioè puntatore a un puntatore a un carattere) e da qui i due * in dichiarazione.

Ora,

  • p1 è l'indirizzo del p2 vale a dire 5000
  • *p1 è il valore detenuto da p2 vale a dire 8000
  • **p1 è il valore al 8000 vale a direc Penso che dovrebbe più o meno chiaro il concetto, consente di dare un piccolo esempio:

Fonte: http://www.thegeekstuff.com/2012/01/advanced-c-pointers/

Per alcuni dei suoi casi d'uso:

Questo è di solito utilizzato per passare un puntatore a una funzione che deve essere in grado di cambiare il puntatore stesso, alcuni dei suoi casi d'uso sono:

  • Su ch come errori di gestione, consente al metodo di ricezione di controllare a cosa si riferisce il puntatore. Vedi this domanda
  • Per creare una struttura opaca, in modo che altri non siano in grado di allocare spazio. Vedi this domanda
  • In caso di espansione della memoria menzionata nelle altre risposte di questa domanda.

sentirsi libero di modificarla/migliorare questa risposta come sto imparando:]