Si, ma non conforderti.
Tu hai specificato "SOLO", in realtà non ha senso dire "SOLO", in quanto un puntatore per definizione punta sempre a una locazione di memoria (e solo una ovviamente).
Il valore contenuto in una variabile di tipo puntatore è un indirizzo di memoria (indirizzo del valore detto "puntato"), mentre il tipo di puntatore, per esempio int*, indica che quando uso quel puntatore, vado a leggere non solo l'indirizzo di memoria puntato ma tutti quelli successivi necessari a definire un dato di tipo int, tipicamente 4 byte.
Se poi effettui dell'aritmetica sui puntatori, per esempio P++, avendo fissato il tipo int*, il compilatore sa che quella istruzione sommerà 4 (il numero di byte di un int) all'indirizzo puntato, così da puntare il valore int successivo.
Alcuni esempi di aritmetica sui puntatori:
Creo un array di unsigned int (unsigned per rendere le cose più semplici)
Codice:
unsigned int interi[10];
for (int i = 0; i < 10; i++)
interi[i] = i;
Creo un puntatore di tipo unsigned int e lo uso per leggere l'array:
Codice:
unsigned int *n = interi;
for (int i = 0; i < 10; i++)
cout << n+i << "\t" << *(n+i) << endl;
while (n < &interi[10]){
cout << n << "\t" << *n << endl;
n++;
}
Entrambi i cicli produrranno lo stesso output, che nel mio pc è stato:
Codice:
0022FC28 0
0022FC2C 1
0022FC30 2
0022FC34 3
0022FC38 4
0022FC3C 5
0022FC40 6
0022FC44 7
0022FC48 8
0022FC4C 9
Per ogni riga, il primo valore è l'indirizzo puntato dal puntatore, il secondo è il valore puntato.
Puoi notare che gli indirizzi sono spaziati di 4 uno dall'altro, infatti, sulla mia macchina, gli interi sono di 4 byte.
E se cambiassi il tipo di puntatore?
Proviamo con un unsigned short, che ha dimensione 2 byte, quindi l'aritmetica sul puntatore sarà diversa:
Codice:
unsigned short *ns = (unsigned short*) interi;
while (ns < (unsigned short*) &interi[10]){
cout << ns << "\t" << *ns << endl;
ns++;
}
//Output:
0022FC28 0
0022FC2A 0
0022FC2C 1
0022FC2E 0
0022FC30 2
0022FC32 0
0022FC34 3
0022FC36 0
0022FC38 4
0022FC3A 0
0022FC3C 5
0022FC3E 0
0022FC40 6
0022FC42 0
0022FC44 7
0022FC46 0
0022FC48 8
0022FC4A 0
0022FC4C 9
0022FC4E 0
Come puoi notare, gli indirizzi sono spaziati di 2 byte, perchè il puntatore punta a valori di 2 byte.
Ma il linguaggio C/C++ mi permette ugualmente di leggere i dati in memoria (C e C++ non sono linguaggi type-safe) e ottengo in output il valore intero letto ogni 2 byte. Un unsigned int di 4 byte è scritto in notazione binaria semplice, in formato big endian (i byte più significativi prima).
Quindi, per esempio il valore 1 sarà rappresentato da 4 byte, di cui il primo vale 00000001 e gli altri 3 00000000.
Leggendo la seconda posizione dell'array, per esempio, otterrò prima 00000001 00000000 e poi 00000000 00000000.
A questo punto tanto vale che facciamo un'altra prova, con i char (1 byte):
Codice:
char* nc = (char *) interi;
while (nc < (char*) &interi[10]){
cout << (void*)nc << "\t" << (unsigned int)(*nc) << endl;
nc++;
}
//Output:
0022FC28 0
0022FC29 0
0022FC2A 0
0022FC2B 0
0022FC2C 1
0022FC2D 0
0022FC2E 0
0022FC2F 0
0022FC30 2
0022FC31 0
0022FC32 0
0022FC33 0
0022FC34 3
0022FC35 0
0022FC36 0
0022FC37 0
0022FC38 4
0022FC39 0
0022FC3A 0
0022FC3B 0
0022FC3C 5
0022FC3D 0
0022FC3E 0
0022FC3F 0
0022FC40 6
0022FC41 0
0022FC42 0
0022FC43 0
0022FC44 7
0022FC45 0
0022FC46 0
0022FC47 0
0022FC48 8
0022FC49 0
0022FC4A 0
0022FC4B 0
0022FC4C 9
0022FC4D 0
0022FC4E 0
0022FC4F 0
Stessa storia di prima, ma ora leggiamo ogni singolo byte come se fosse un valore intero di un byte (char).
Ogni valore del nostro array viene diviso in 4 parti, e ognuna viene stampata a parte. Essendo il dato originale scritto in big endian, il byte meno significato è il primo, seguito dai 3 meno significativi, che nel nostro caso sono tutti zero, in quanto abbiamo inserito numeri inferiori a 256.
ps: si mi sono divertito :asd:
pps: ah, e l'aritmetica dei puntatori vale anche quando si usano strutture o altri tipi di dato.