Wednesday, September 5, 2012

POINTING OUT

Software and cathedrals are much the same 
– first we build them, then we pray.

I famigerati puntatori del linguaggio C, spiegati decentemente, non sono poi questo gran arcano. Con
int n 
dichiariamo una "scatola" che conterrà un intero e si chiamerà n, mentre con
int *n
dichiariamo una scatola che conterrà un intero e si chiamerà *n.
Stessa cosa dunque, ma

  • nel primo caso con n il computer intende il contenuto della scatola
  • nel secondo caso il contenuto per lui si chiamerà *n mentre se scriveremo solo n ci restituirà l'etichetta dello scatolone, cioè una stringa che corrisponde all'indirizzo di memoria fisico del computer dove il dato è registrato (vedere come è fatta la memoria di un pc dal punto di vista hardware).


Prima di arrivare a capire decentemente i puntatori nel modo che abbiamo tradotto in scatoloni e etichette, mi restava oscuro il fatto che l'asterisco quando dichiaravamo un puntatore assurgeva a indicatore del fatto che n avrebbe "puntato" un indirizzo di memoria, mentre nel restante testo del programma avrebbe funto da "operatore di dereferenziazione", cioè avrebbe indicato il "contenuto della scatola";
in altre parole i prof scrivevano
int *n
e dicevano "sto dichiarando un puntatore di tipo int", dunque io pensavo "qui '*' indica che n è un puntatore, cioè un indirizzo di memoria", mentre poi nel testo scrivevano
*n=1
e dicevano "ora nella memoria puntata dall'indirizzo indicato da n, stiamo registrando il valore 1", dunque io pensavo "qui '*' mi dice che sto andando a scrivere all'indirizzo n e non dentro n".
Dunque, mi pareva che al momento dell'inizializzazione l'asterisco significasse "è un puntatore" mentre in seguito volesse dire "è l'indirizzo del puntatore", ovvero due cose praticamente opposte...

L'errore derivava appunto dal fraintendimento riguardo che cosa volesse dire "dichiarare un puntatore".
Mentre inizializzare una variabile, per esempio facendo
int n
significa dire come dovranno essere letti e scritti i bit in un certo indirizzo di memoria (ad esempio il tipo unsigned int è un intero senza il segno, mentre int può essere negativo, dunque quest'ultimo a differenza del primo avrà un bit specificatamente dedicato a memorizzare se è positivo o negativo), ed n sarà associato al contenuto dell'indirizzo di memoria, cioè sarà il dato stesso;
inizializzare un puntatore invece, ad esempio facendo
int *n
significa che la lettera n designerà l'indirizzo stesso di memoria, e non il contenuto, e il tipo che precede l'asterisco non sarà riferito propriamente a n, ma a come dovranno essere scritti e letti i bit all'indirizzo n.
In parole povere, è sbagliato dire che si inizializza un puntatore (come dicevano i prof mandandomi in pappa), perché o si inizializza una variabile oppure si inizializza IL CONTENUTO ALL'INDIRIZZO DATO DAL PUNTATORE.