DOMANDA Quando utilizzare i puntatori?

Pubblicità
Come detto dal signore del tempo, sono dei cast espliciti, li ho usati per lo più per chiarezza, anche se il (void*) è necessario quando mandi in output l'indirizzo puntato da un puntatore char. Infatti il cout interpreta il puntatore come carattere da stampare, quindi senza cast va a stampare il valore puntato interpretandolo come carattere ASCII.
In C++ i cast sono regolati in modo particolare per lo più per le classi, quando parliamo di puntatori a valori primitivi, in realtà non c'è molta differenza d'uso. I cast espliciti sono utili per applicazioni ad alta efficienza quando si lavora direttamente su dati in memoria, in quel caso tipicamente il C++ regredisce a C. Nel C++ di solito si usano funzioni di cast per i primitivi e si sfrutta il dynamic lookup per le classi, ma sono aspetti un po' più complessi da trattare (all'università ho fatto un corso da 10 crediti nel quale per metà del tempo si è parlato quasi esclusivamente del dynamic lookup e tipizzazione di C++ comparato ad altri linguaggi).

ps: Mi correggo per il post precedente, ho scritto che l'unsigned int viene memorizzato in big endian, ma non è stata una svista (per lo più un mistype). Anche dall'output è evidente che è il contrario: little endian. Infatti vengono prima letti i byte meno significativi.
Quindi, se io dovessi scrivere:
char* P;
char X[] = "Ciao";
P = &X;
Per utilizzare P in cout devo scrivere:
cout << (void*) P << endl;
Giusto?
 
Quindi, se io dovessi scrivere:
char* P;
char X[] = "Ciao";
P = &X;
Per utilizzare P in cout devo scrivere:
cout << (void*) P << endl;
Giusto?
No, ci sono degli errori... la variabile X si riferisce a un array, per cui, come già detto, è implicitamente un puntatore al primo elemento dell'array. Nella assegnazione non devi mettere "&", quindi devi scrivere:
P = X;
Per l'output poi non capisco cosa vuoi fare, in quel modo vai a stampare P come se fosse un tipo primitivo (generico void) e quindi stamperà l'indirizzo puntato da P, cioè l'indirizzo puntato da X, che a sua volta è l'indirizzo del vettore.
Se tu togli il cast a void*, e lasci cout << P, avrai in output "Ciao" in quanto cout va a leggere il vettore di char fino a che non incontra il carattere terminatore.
E' sufficiente che provi a compilare ed eseguire il codice... fai molto prima a imparare.
 
No, ci sono degli errori... la variabile X si riferisce a un array, per cui, come già detto, è implicitamente un puntatore al primo elemento dell'array. Nella assegnazione non devi mettere "&", quindi devi scrivere:
P = X;
Per l'output poi non capisco cosa vuoi fare, in quel modo vai a stampare P come se fosse un tipo primitivo (generico void) e quindi stamperà l'indirizzo puntato da P, cioè l'indirizzo puntato da X, che a sua volta è l'indirizzo del vettore.
Se tu togli il cast a void*, e lasci cout << P, avrai in output "Ciao" in quanto cout va a leggere il vettore di char fino a che non incontra il carattere terminatore.
E' sufficiente che provi a compilare ed eseguire il codice... fai molto prima a imparare.
Ho seguito il tuo coniglio ed ho testato un po' di codici.
Ho provato a stampare (void*) P e &P ed ho visto che ritornano entrambi l'indirizzo a cui puntano (in questo caso una variabile di tipo char con scritto "Ciao".
Questo è il codice:
Codice:
	char* P;
	char X[] = "Ciao";
	P = X;
	cout << "(void*) P: " << (void *)P << endl;
	cout << "*P: " << *P << endl;
	cout << "P: " << P << endl;
	cout << "&P: " << &P << endl;
	cout << "&X[10]: " << &X[10] << endl;
	cout << "n+1: " << P+1 << endl;
	cout << "*(P+2): " << *(P+2) << endl;
	cout << "P: " << P << endl;
 
Ho provato a stampare (void*) P e &P ed ho visto che ritornano entrambi l'indirizzo a cui puntano (in questo caso una variabile di tipo char con scritto "Ciao".
In realtà stampano due cose diverse.
Giustamente hai abusato dell'uso dei puntatori per verificarne il funzionamento, ed è bene che tu abbia chiaro cosa fanno quelle istruzioni.

cout << "(void*) P: " << (void *)P << endl;
cout << "&P: " << &P << endl;
Stampano due cose diverse: la prima stampa l'indirizzo puntato da P, ovvero l'indirizzo del primo valore dell'array di char "Ciao\0" ('\0' è il carattere terminatore, chiamato anche NUL terminator). La seconda stampa l'indirizzo del puntatore stesso, che non è l'indirizzo puntato, ma quello dove è memorizzato il valore dell'indirizzo puntato (sembra un gioco di parole...). Ricorda che un puntatore è una variabile numerica intera contenente un indirizzo, e come tale a sua volta ha un proprio indirizzo. Se leggi l'output vedi infatti che non sono lo stesso valore...

cout << "&X[10]: " << &X[10] << endl;
In questo caso il programma si porterà nella posizione 10° dell'array di char, fuori dall'array e punta quindi a un valore non determinabile, e stamperà ciò che trova in memoria come fossero caratteri fino a che non trova un carattere terminatore. Il comportamento di cout con l'operatore << si basa sul presupposto che se riceve un puntatore a char, deve considerarlo come inizio di una serie di char.

Se invece, al posto di un puntatore a char, passi proprio un char:
cout << "*(P+2): " << *(P+2) << endl;
verrà stampato solo il carattere. L'operatore * infatti "preleva" il contenuto puntato dal puntatore a destra, in questo caso P+2, che è la terza lettera della parola.
 
Ultima modifica:
In realtà stampano due cose diverse.
Giustamente hai abusato dell'uso dei puntatori per verificarne il funzionamento, ed è bene che tu abbia chiaro cosa fanno quelle istruzioni.

cout << "(void*) P: " << (void *)P << endl;
cout << "&P: " << &P << endl;
Stampano due cose diverse: la prima stampa l'indirizzo puntato da P, ovvero l'indirizzo del primo valore dell'array di char "Ciao\0" ('\0' è il carattere terminatore, chiamato anche NUL terminator). La seconda stampa l'indirizzo del puntatore stesso, che non è l'indirizzo puntato, ma quello dove è memorizzato il valore dell'indirizzo puntato (sembra un gioco di parole...). Ricorda che un puntatore è una variabile numerica intera contenente un indirizzo, e come tale a sua volta ha un proprio indirizzo. Se leggi l'output vedi infatti che non sono lo stesso valore...

cout << "&X[10]: " << &X[10] << endl;
In questo caso il programma si porterà nella posizione 10° dell'array di char, fuori dall'array e punta quindi a un valore non determinabile, e stamperà ciò che trova in memoria come fossero caratteri fino a che non trova un carattere terminatore. Il comportamento di cout con l'operatore << si basa sul presupposto che se riceve un puntatore a char, deve considerarlo come inizio di una serie di char.

Se invece, al posto di un puntatore a char, passi proprio un char:
cout << "*(P+2): " << *(P+2) << endl;
verrà stampato solo il carattere. L'operatore * infatti "preleva" il contenuto puntato dal puntatore a destra, in questo caso P+2, che è la terza lettera della parola.
Ho fatto altre verifiche e grazie a te ho notato altre cose (correggimi se sbaglio):
Se con il puntatore, punto ad una variabile char, partendo però dall'indice 1 (P = &C[1]) gli output cambiano tutti, infatti leggerà "Iao" e non più "Ciao", giusto?
Per il fail che ho fatto, riguardante &P e (void*) P hai ragione: osservando meglio l'indirizzo è diverso.
Ti ringrazio per tutto l'aiuto che mi stai dando, fortunatamente mi sono iscritto a TomsH.
 
Se con il puntatore, punto ad una variabile char, partendo però dall'indice 1 (P = &C[1]) gli output cambiano tutti, infatti leggerà "Iao" e non più "Ciao", giusto?
Con quella istruzione semplicemente P punterà a una serie di char che inizia dall'indirizzo C+1 e prosegue fino al terminatore, quindi salti il primo carattere di "Ciao", e il risultato è quello che hai notato.
Scrivere &C[1] è uguale a scrivere C+1 (quest'ultima scrittura è più "pulita")
 
Con quella istruzione semplicemente P punterà a una serie di char che inizia dall'indirizzo C+1 e prosegue fino al terminatore, quindi salti il primo carattere di "Ciao", e il risultato è quello che hai notato.
Scrivere &C[1] è uguale a scrivere C+1 (quest'ultima scrittura è più "pulita")
Adesso ho le idee più chiare.
Infatti, nel cout, se provo a fare *(P-1) mi ritornava C.
Ti ringrazio ancora per tutto l'aiuto che mi stai dando.
 
Pubblicità
Pubblicità
Indietro
Top