2009-06-19 17 views
6
char **Data[70]={NULL}; 

Qual è la terminologia corretta per questo? In che altro modo potrebbe essere scritto? Che aspetto ha in memoria? Sto leggendo molti tutorial sui puntatori ma non lo vedo in questa sintassi. Qualsiasi aiuto è apprezzato. Grazie.Come funziona una serie di puntatori ai puntatori?

risposta

24

Questa struttura

char **Data[70]={NULL}; 

è un array di 70 puntatori a puntatori a char. Il compilatore alloca i byte 70 * sizeof(char**) per questo array, che presuppone che i puntatori a 32 bit siano 280 byte.

Se internamente si pensa a un "puntatore al carattere" come una stringa, che non è vero ma è abbastanza vicino, allora questo è un array di 70 puntatori alle stringhe. Per fare un po 'arte ASCII e far finta che avete assegnato e riempito alcuni valori ....

Array of  One or more 
char **   char * 
+---------+  +---------+ 
| 0 | --> | ptr | --> "Hello, world" 
+---------+  +---------+ 
| 1 | 
+---------+  +---------+ 
| 2 | ----> | ptr2 | --> "Goodbye, cruel world" 
+---------+  +---------+ 
| 3 | 
+---------+   +---------+ 
| 4 | ------> | ptr3[0] | --> "Message 0" 
+---------+   +---------+ 
    ...    | ptr3[1] | --> "Message 1" 
+---------+   +---------+ 
| 69 |   | ptr3[2] | --> "Message 2" 
+---------+   +---------+ 

Si potrebbe fare quanto sopra con codice come questo (i valori di ritorno di errore controllo malloc saltati):

char **Data[70]={NULL}; 
char **ptr, **ptr2, **ptr3; 

ptr = (char **) malloc(sizeof(char *)); 
*ptr = "Hello, world"; 
Data[0] = ptr; 

ptr2 = (char **) malloc(sizeof(char *)); 
*ptr2 = "Goodbye, cruel world"; 
Data[2] = ptr2; 

ptr3 = (char **) malloc(10 * sizeof(char *)); 
Data[4] = ptr3; 

ptr3[0] = "Message 0"; 
ptr3[1] = "Message 1"; 
... 
ptr3[9] = "Message 9"; 

printf("%s\n", *Data[0]); 
printf("%s\n", Data[2][0]); 
printf("%s\n", Data[4][0]); 
printf("%s\n", Data[4][1]); 
     ... 
printf("%s\n", Data[4][9]); 

Pensateci in questo modo: ogni voce nell'array è un char **. Ogni voce può puntare a una posizione arbitraria in memoria, detta posizione (s) è char * e quindi essere in grado di puntare a un array di caratteri terminato da null aka "stringa".

Nota con attenzione la distinzione tra questo e quello che si ottiene quando si assegna una matrice 2D:

char *Data2[10][70]={NULL}; 

L'assegnazione dei Data2 sopra vi dà una matrice a 2 dimensioni di char * puntatori, ha detto 2-d array di essere allocati in un singolo blocco di memoria (10 * 70 * sizeof(char*) byte o 2800 byte con puntatori a 32 bit). Non è possibile assegnare i puntatori a posizioni arbitrarie in memoria con l'array a una dimensione di puntatori .

anche notare (di cui sopra dichiarazioni di Data e Data2) che il compilatore genererà il codice diverso per i seguenti riferimenti ad array:

Data[0][0] 
Data2[0][0] 

Ecco un altro modo di pensare a questo: Immaginate di avere diversi matrici di puntatori a stringhe:

char *table0[] = { "Tree", "Bench", "Stream" }; 
char *table1[] = { "Cow", "Dog", "Cat" }; 
char *table2[] = { "Banana", "Carrot", "Broccoli" }; 
char **Data[3]; 

Data[0] = table0; 
Data[1] = table1; 
Data[2] = table2; 

Si dispone di un array di puntatori a "matrice di puntatore a carattere". Se ora si stampa il valore di data[1][1], pensare in questo modo: ottiene un puntatore all'array table1. Quindi il valore table1[1] equivale a "Dog".

+1

la tua ottima risposta è stata spudoratamente collegata a questa risposta pet-peeve: http://stackoverflow.com/questions/423823/whats-your-favorite-programmer-ignorance-pet-peeve/484900#484900. evviva :) –

+0

grazie per aver trovato il tempo di scrivere una così buona risposta. Questo chiarisce molto. Per quanto riguarda il tuo primo diagramma, come fai a sapere se il puntatore punta a un singolo puntatore (come ptr2) oa un array di puntatori, come ptr3 [0-2] Può essere sia come nel diagramma? Ad esempio, il tuo secondo diagramma è coerente. Grazie. –

+0

Non c'è modo di sapere a cosa punta esattamente un puntatore char **. Potrebbe puntare a un'area di memoria di qualsiasi dimensione. Senza guardare il codice dove è assegnato, non c'è modo di sapere. – Eddie

0

Questo è, in pratica, un puntatore a un puntatore ai puntatori. Tuttavia, dal momento che un "puntatore" non è altro che una posizione nella memoria, non è molto utile fare semplicemente char * Data [70], oltre a rendere ovvio che ogni char * è un puntatore a un altro char *, invece di un puntatore al char.

1

Questo non è molto evidente:

char **Data[70]={NULL}; 

ma con una dichiarazione alternativa, come:

char* Data[2][3] = { 
    {"Nick", "Tom", "Helen"}, 
    {"one", "two", "three"} 
}; 

possiamo facilmente vedere che è una matrice bidimensionale 2 di stringhe.

Modifica: Ho usato Dati [2] [3] per mostrare che si tratta di un array 2D. Ho usato fisso dimensioni per le dimensioni come 2 & 3 solo per dimostrazione. Naturalmente possiamo avere:

char* Data[][3]={ 
    {"Nick", "Tom", "Helen"}, 
    {"one", "two", "three"}, 
    // ... 
}; 

o char** Data[]

Ok, ecco cosa intendo per 2-D array:

char** Data[2]={0}; 

void test() 
{ 
    char* d1[] = {"1", "2"}; 
    char* d2[] = {"10", "20", "30"}; 
    Data[0] = d1; 
    Data[1] = d2; 

    printf("%s\n", Data[0][0]); 
    printf("%s\n", Data[0][1]); 
    printf("%s\n", Data[1][0]); 
    printf("%s\n", Data[1][1]); 
    printf("%s\n", Data[1][2]); 
} 
+1

In realtà non è una matrice 2-D di stringhe. La tua dichiarazione ti dà qualcosa di diverso dal suo. – Eddie

+0

Quindi non è un array 2D, di puntatori? –

+0

Qual è la differenza? –

2

E 'un po' difficile pensare ad un uso pratico per un serie di caratteri **. Soprattutto uno con 70 elementi.

Tuttavia, supponiamo che eseguirò 70 programmi. Come probabilmente saprai, gli argomenti del programma vengono comunemente passati come parametro char** argv su main() (o char*[] argv, che in una firma di funzione è la stessa cosa). Quindi, se volevo memorizzare i puntatori argv per tutti quei programmi, avevo usato un array come Data. Ovviamente avrei anche bisogno di un po 'più di memoria altrove, perché le stringhe e gli array argv attuali occupino, ma è un inizio.

L'inizializzazione di una matrice con {NULL} imposta tutti i suoi elementi su NULL. Questa è un'utile stenografia: è possibile inizializzare un array con {firstelement, secondelement, ...}, ma se non si forniscono abbastanza termini, tutto il resto viene trattato come 0.

Proprio come qualsiasi altro array di puntatori, inizializzato con {NULL}, ciò che appare in memoria è di 70 puntatori NULL seduti in fila. C'è (di solito) nessuna differenza di memoria tra un char** e qualsiasi altro puntatore a oggetti. Penso che sia legale scrivere una strana implementazione in cui c'è una differenza, ma non trattenere il respiro in attesa di trovarne uno.

Quindi, la differenza tra 70 NULL char** fila e 70 NULL char* in una fila è quello sarebbe essere sull'altra estremità del puntatore, se non fossero NULL. Dall'altra parte di un char** c'è un puntatore a un carattere. Dall'altra parte di un char* è un carattere. O il puntatore, o il carattere, potrebbe essere il primo di un array, a seconda di come viene utilizzato.

1

Quello che hai è un array di 70 puntatori, ognuno dei quali punta a un altro puntatore, ognuno di questi puntatori punta a un carattere. Su una nota interessante, gli array stessi sono indicatori in modo da avere tre livelli di indicatori.

+0

Gli array NON sono puntatori. –

Problemi correlati