2010-05-11 13 views
11

Penso di capire bene i riferimenti e i puntatori. Ecco cosa so (penso):Informazioni sui puntatori C++ (quando puntano a un puntatore)

int i = 5; //i is a primitive type, the value is 5, i do not know the address. 
int *ptr; //a pointer to an int. i have no way if knowing the value yet. 
ptr = &i; //now i have an address for the value of i (called ptr) 
*ptr = 10; //Go to the value in ptr, use it to find a location and store 10 there 

Non esitate a commentare o correggere queste dichiarazioni.

Ora sto provando a fare il salto agli array di puntatori. Ecco quello che non conosco:

char **char_ptrs = new char *[50]; 
Node **node_ptrs = new Node *[50]; 

La mia comprensione è che ho 2 array di puntatori, una serie di puntatori a caratteri e uno a nodi. Quindi, se ho voluto impostare i valori, vorrei fare qualcosa di simile:

char_ptrs[0] = new char[20]; 
node_ptrs[0] = new Node; 

ora ho un puntatore, nella 0 posizione del mio schieramento, in ogni rispettiva disposizione. Di nuovo, sentiti libero di commentare qui se sono confuso.

Quindi, cosa fa l'operatore **? Allo stesso modo, cosa sta mettendo un singolo * accanto alla creazione dell'istanza (* [50])? (come si chiama esattamente, l'istanza?)

+3

* ptr = 10 non è "andare a ottenere il valore memorizzato in ptr e cambiarlo in 10". Dovrebbe essere "Vai al valore in ptr, usalo per trovare un'altra posizione e memorizza 10 lì". Questo è il punto di dereferenziazione del puntatore. – Uri

+0

@Uri bene incontrato. modificato e aggiornato. – Stephano

+0

Devo notare che questo libro è stato straordinariamente utile nell'apprendimento dei puntatori in C: Comprensione e utilizzo dei puntatori C di Richard Reese. Lo consiglierei a chiunque stia imparando C o C++, poiché i concetti in esso contenuti sono inestimabili. – Stephano

risposta

7

Alcuni commenti:

*ptr = 10; // Doesn't need to "go get" the value. Just overwrites it. 

anche:

char **char_ptrs = new char *[50]; 
Node **node_ptrs = new Node *[50]; 

E 'più facile pensare di avere due array. Tuttavia, tecnicamente (e per quanto riguarda il compilatore) ciò che hai sono due puntatori. Uno è un puntatore a un (puntatore a un carattere) e l'altro è un puntatore a un (puntatore a un nodo).

questo è facilmente visibile dalle dichiarazioni delle variabili, che, tra l'altro, possono essere più facilmente leggere da destra a sinistra:

char **char_ptrs 

lettura da destra a sinistra: char_ptrs è un puntatore a un puntatore a char

Mettere un * accanto a un puntatore è propriamente chiamato dereferenziazione tale puntatore. Poiché gli array non esistono tecnicamente, l'operatore [] sugli array è anche un'operazione di dereferenziazione: arr[i] è un altro modo di scrivere *(arr + i). Per comprendere correttamente questo, è necessario avere familiarità con pointer arithmetic.

Più di un * s consecutivo: ciascuno denota il risultato dell'espressione su cui opera. Così, quando scriveva:

char c = **char_ptrs; 

ciò che accade è:

char_ptrs è un puntatore a un puntatore a un char. Dereferenziarlo una volta (per l'estrema destra *) ti dà il suo valore, che è un puntatore a un carattere. Dereferenziare quel valore (per il più a sinistra *) fornisce a sua volta il proprio valore, che è un carattere. Alla fine, c contiene il valore del carattere salvato in memoria nel punto in cui punta il puntatore a puntatore di char_ptrs (in altre parole, il primo puntatore dell'array).

Al contrario, se si scrive **char_ptrs = 'a';, si modifica il valore in tale posizione di memoria.

+0

+1 detto bene. collegamento eccellente anche. – Stephano

+0

Node * tmp = node_ptrs [0]; Quindi è corretto? – Stephano

+0

@Stephano: certo che lo è. – Jon

6

** è solo * due volte, quindi un puntatore a un puntatore.

Se inserito accanto a un tipo, * si collega a sinistra, non a destra. Dire new char *[50] è in realtà new char* [50] e crea un'istanza di 50 char*.

2

Le dichiarazioni fatte nel primo blocco di codice sono tutte corrette.

char **char_ptrs = new char *[50]; 

... significa avere un array di 50 char * s.

tuo assesment di

char_ptrs[0] = new char[20]; 
node_ptrs[0] = new Node; 

è corretta pure.

** significa semplicemente "puntatore a un puntatore". Non è un operatore.

Quando si scrive

new char *[50]; 

... voi dicono 'allocare memoria per 50 char * s'.

+0

A volte la sintassi è confusa. Preferisco: "char ** char_ptrs = new char * [50];" Per renderlo esplicito, ma anche questo ha i suoi lati negativi. –

0

Chiarire la prima sezione:

int i = 5; // i is a primitive type, the value is 5, the address is retrieved via &i. 
int *ptr; // an unassigned pointer to an int 
ptr = &i; // ptr now point to the address of variable i 
*ptr = 10; // access (dereference) the value through ptr and change it to 10 (same as i=10) 

Non c'è nessun operatore **, basta * operatore. Come hanno detto gli altri, ** dichiara un puntatore a un puntatore. Poiché si dichiarano matrici di puntatori e i puntatori vengono dichiarati con l'operatore *, è necessario dichiararli come tali quando si assegnano loro memoria con new. Quindi, hai:

char **char_ptrs = new char *[50]; // allocates memory for 50 contiguous char* (pointers) 
Node **node_ptrs = new Node *[50]; // allocates memory for 50 contiguous Node* (pointers) 

I puntatori ai puntatori non devono necessariamente dichiarare gli array. Si può benissimo avere un puntatore regolare puntato da un altro puntatore, come in:

char i = 'p'; 
char *myptr = &i; 
char **mysecondptr = &myptr; 
3

Se si trova il * notazione di difficile lettura uso typedef per contribuire a rendere il codice di facile lettura.

typedef char*  CharPtr; 
typedef CharPtr* CharPtrPtr; 
// Alternative to the line above 
// typedef char**  CharPtrPtr; 

// When you call new. You get a ptr to the type you are newing. 
// new int returns an intPtr. new char returns a charPtr 
CharPtrPtr char_ptrs = new CharPtr[50]; 

// So new CharPtr returns a CharPtrPtr 
// In this case we return a pointer to contigious 
// chunk of memory large enough to hold 50 CharPtr objects. 
+0

No, no. Nascondere il fatto che qualcosa è un puntatore è uno stile molto povero, IMHO. –

+1

Sono d'accordo con Neil nel caso generale. Ma Ptr va bene perché non lo stai nascondendo (IMHO). Ma poiché questo è un excersise di apprendimento solo per abituarsi a usare i puntatori funziona. Quando diventi vecchio e pigro come me, un Niel * è altrettanto facile da leggere e più veloce da digitare :-) –