Puntatori a costanti e puntatori costanti - TelPar

Download Report

Transcript Puntatori a costanti e puntatori costanti - TelPar

Appunti di OOP in C++
telpar.altervista.org
Puntatori a costanti e puntatori costanti
Quando usiamo la parola chiave 'const' con i puntatori, abbiamo due opzioni:
- const può essere applicata a qualcosa cui il puntatore sta puntando
- const può essere applicata all'indirizzo memorizzato nello stesso puntatore
La sintassi confonde un po' le idee agli inizi, ma la pratica dissipa ogni dubbio.
PUNTATORI A CONST
Se vogliamo prevenire qualsiasi modifica all'elemento che stiamo puntando, la sintassi consigliata è
la seguente:
const int* u;
// oppure (meno preferita):
int const *u
Iniziamo a leggere dall'identificatore, da destra a sinistra:
“u è un puntatore, che punta a un elemento di tipo 'const int'.
Non ci interessa l'inizializzazione dell'oggetto cui punta (l'oggetto può anche essere non
inizializzato); stiamo solo dicendo che la 'cosa' cui punta u non può essere modificata perché è stata
qualificata 'const'.
La 'cosa' cui punta, attenzione, non l'indirizzo contenuto dal puntatore. Es.
{
int b; // b può essere anche non inizializzata...
const int* p = &b; // p punta a b
b = 100; // inizializzo b
(*p)++; // ERRORE! p non può modificare la variabile che punta
}
Altro es.
La var. a, definita come intera, contiene il valore 100 ed è allocata alla locazione 2000
a
[100]
(2000)
Il puntatore u, definito come puntatore a un intero costante (dunque non modificabile), punta ad a,
contiene cioè il valore 2000; esso è allocata alla locazione 3000
u
[2000]
(3000)
Appunti di OOP in C++
telpar.altervista.org
Se ora proviamo a modificare il valore contenuto in 'a' attraverso il puntatore u otterremo un errore!
(perché u punta a una 'cosa' constante)
Prendiamo una seconda variabile di tipo intero b; contiene il valore 2000 ed è allocata alla locazione
4000:
b
[2000]
(4000)
Aggiorniamo il punt. u e lo facciamo puntare ora a b; lo possiamo fare, il puntatore non è costante!
u
[4000]
(3000)
Ovviamene se proviamo di nuovo a modificare il contenuto di b otterremo un errore, come nel caso
precedente.
Ecco il codice
int a = 100;
const int* u ;
u = &a; // ok
*(u)++;
// ERRORE!!! non poss. modificare la 'cosa' puntata da u
int b = 2000;
u = &b; // lo posso fare perché il punt. u non è costante.
*(u)++;
// ERRORE!!! non poss. modificare la 'cosa' puntata
PUNTATORI CONST
Un puntatore costante è un puntatore che punta sempre allo stesso oggetto, assegnato all'atto della
definizione del puntatore stesso (non è possibile definire puntatori costanti senza la contestuale
assegnazione dell'indirizzo dell'oggetto a cui punta).
Sintassi: Il const va messo a destra del *
Per rendere lo stesso puntatore un const (cioè costante, immodificabile) si deve piazzare lo
specificatore const alla destra del *, come questo esempio:
int d = 1;
int* const w = &d;
// w punta a d e punterà sempre a d!
Adesso leggiamo, da destra a sinistra: “ w è un costante puntatore che punta a un int”
Appunti di OOP in C++
telpar.altervista.org
Da notare che il compilatore richiede all'atto della definizione l'assegnazione di un valore iniziale
che non potrà essere cambiato per tutta la vita del puntatore.
Notiamo una certa similitudine con il reference; il reference è come un puntatore costante: deve
essere esplicitamente inizializzato nella fase di definizione e non può essere più cambiato l'oggetto
a cui punta.
Ovviamente, a differenza del primo caso, possiamo cambiare quello che è puntato dal puntatore. Es.
*w = 2;
Non solo, ma possiamo anche avere un puntatore const a un oggetto const! Es.
const int* const x = &d;
Esempio di programma completo:
#include <iostream>
int main()
{
int a = 100;
int b = 200;
const int c; // promettiamo che c non verrà mai modificata
const int*
int const*
int* const
const int*
u;
z;
w = &a;
const y = &b;
//
//
//
//
Non
Non
Non
Non
modificabile:
modificabile:
modificabile:
modificabile:
la
la
il
né
cosa puntata
cosa puntata
solo puntatore
puntatore, né la cosa puntata
(*w)++;
w = &b; // ERRORE: w è un const pointer
u = &a; // ok
(*u)++; //ERRORE: u punta a una cosa const.
u = &b; // ok, u può essere modificato perché non è un const pointer
y = &a; // ERRORE: y è const pointer!
*y = 300;
//ERRORE y è anche puntatore a una cosa costante
}
ASSEGNAMENTI E CONTROLLO DEI TIPI
Come abbiamo visto è possibile assegnare l'indirizzo di un oggetto non costante a un puntatore
costante, perché, semplicemente, si sta promettendo che quel puntatore, durante tutta la sua vita,
Appunti di OOP in C++
telpar.altervista.org
punterà sempre e solo a quell'oggetto.
// Corretto
int a;
int* const p = &a; // p punterà sempre e solo ad a, finché vivrà
Non è, però, possibile assegnare l'indirizzo di un oggetto costante a un puntatore a un oggetto non
costante, perché si potrebbe cambiare l'oggetto. Es.
// Errato
const int b;
int* w = &b;
E' sempre possibile forzare l'assegnamento ma ciò romperebbe la costanza della variabile
int* w = (int*) &b; // casting forzato: legale ma sconsigliato
L'ARRAY DI CARATTERI
Quando scriviamo una cosa del genere:
char* s = “CIAO”;
andiamo ad allocare in memoria una sequenza di caratteri che iniziano dall'indirizzo s e terminano
quando c'è il carattere '\0'
il compilatore l'accetta senza problemi, ma considera il puntatore s come l'indirizzo iniziale di un
array costante di caratteri ovvero l'indirizzo del primo carattere
quindi ogni tentativo di modificare il contenuto di questo array, per esempio con istruzioni tipo:
s[0] = 'M';
comporta un errore in fase di compilazione.
Perciò, se intendiamo modificare successivamente la nostra stringa, dobbiamo definire in questo
modo:
char s[] = “CIAO”;
s[0] = 'M'; // ora s[] = “MIAO”