Memoria e puntatori
In questo capitolo vediamo come è fatta, e come viene
usata, la memoria. La memoria si può vedere come
un array di byte, in cui ogni variabile occupa un certo
numero di byte consecutivi. In C, è possibile determinare
sia quanto spazio occupa una variabile, sia la sua posizione
in questo vettore. In particolare, è possibile memorizzare
la posizione (indirizzo) di una variabile in un'altra
variabile. Le variabili che contengono indirizzi di memoria
sono dette variabili puntatori.
La memoria
- come si rappresenta la memoria ad alto livello
- rappresentazione più precisa, come vettore di celle
- un esempio di alcune variabili in memoria
Indirizzo, byte occupati e valore di una variabile
- variabile = insieme di celle consecutive
- per sapere quali celle sono occupate da una variabile,
ci basta sapere quante sono e l'indirizzo della prima
- ci sono casi in cui serve sapere queste cose
- operatori & e sizeof
- indirizzo e numero di byte si possono anche stampare
- differenza fra valore e indirizzo
- sizeof dipende solo dal tipo; per questa
ragione, si può usare anche sul tipo
Puntatori
- gli indirizzi non sono esattamente dei numeri
- per esempio, int p, a; e poi p=&a;
genera un errore (warning)
- il tipo di un indirizzo non è int
- l'indirizzo di una variabile int è
di tipo int *
- quindi, int *p; int a; e poi p=&a;
non genera errori
Dichiarazioni di variabili di tipo puntatore
- quando si dichiarano più variabili puntatori
insieme, * va ripetuto su tutte
- tranne quando si usa typedef
Valore e indirizzo
- tutte le variabili hanno valore e indirizzo
- questo vale anche per i puntatori
- per i puntatori, sono entrambi indirizzi di memoria
- sono comunque due cose diverse
Usare l'oggetto puntato
- se p è un puntatore, allora
*p è come se fosse una variabile
- esempio di uso dell'operatore *
- cosa succede in memoria quando si esegue
un programma con puntatori
- rappresentazione degli indirizzi con freccie
Tipo dei puntatori
- perchè i puntatori non sono interi?
- perchè altrimenti non so in che modo
*p va interpretato (è un intero?
un carattere?)
- alternativa possibile ma non usata: *
con due argomenti
Copia del valore e copia dell'indirizzo
- differenza fra b=a e p=&a, in pratica
- b=a significa: copia il valore di a in b;
non ci sono più relazioni fra a e b dopo
la copia
- p=&a copia l'indirizzo: anche se è una
copia, ora *p e a sono la stessa cosa
- cosa succede in memoria
Puntatori indefiniti
- i puntatori sono inizialmente indefiniti, come tutte
la variabili
- cosa succede quando si usa un puntatore indefinito
- non si devono usare puntatori indefiniti
Allocazione di memoria
- quali zone di memoria si possono usare (riservate ad
uso esclusivo del programma)
- funzione malloc: dà una zona di memoria
con queste caratteristiche
- esempio di creazione di memoria per contenere un intero
- vale ancora la regola che *p è una
variabile intera, ma si può usare solo se questa
zona di memoria è stata riservata
Il valore NULL
- in un puntatore si può mettere il valore
0
- il programma non può usare la zona di memoria
che inizia dalla posizione 0
- questo valore viene denotato con NULL
- indica che il puntatore non contiene un indirizzo valido
- malloc ritorna questo valore se l'allocazione
è fallita
Zone di memoria inaccessibili
- il valore iniziale della memoria è indeterminato
- se non si perde l'indirizzo di una zona di memoria
allocata con malloc, non la si può
più usare
Passaggio di un puntatore a una funzione
- si può passare l'indirizzo di una
variabile a una funzione
- effetti della modifica a) del valore della zona di
memoria puntata, e b) del valore del parametro formale
stesso
- cosa succede in memoria
Puntatori a puntatori
- i puntatori sono variabili come tutte le altre
- quindi, si può determinare il loro indirizzo
- differenza fra indirizzo e valore