Fondamenti di Informatica 2
Ingegneria Informatica
Docente: Giovanni Macchia
a.a. 2002-2003
Puntatori
Una variabile di tipo puntatore contiene un
indirizzo di memoria con la locazione di una
variabile(detta variabile puntata).
La variabile puntata può essere di qualsiasi tipo
(non solo quindi di tipo fondamentale ) e può
quindi essere un puntatore stesso.
Indirizzo
Memoria
100
220
puntatore
variabile
puntata
220
10
Dichiarazione di variabile puntatore
In C++, la sintassi per la dichiarazione di una
variabile puntatore è effettuata tramite il
qualificatore di tipo * (suffisso *):
T *var_puntatore
dove T è il tipo del puntatore e var_puntatore è il
nome della variabile puntatore (puntatore a T)
Es:
int *p;
p è puntatore ad una variabile int
double **vel vel è puntatore a puntatore di
variabile double
Un puntatore può puntare solo a variabili di tipo
specificato nella dichiarazione, cioè di tipo T.
Dichiarazione di variabile puntatore
ATTENZIONE!!!
La dichiarazione di un puntatore comporta
l’allocazione di memoria del puntatore, non della
variabile puntata.
Nell’esempio precedente, int* p comporta
l’allocazione di memoria p (p.e. 100) ma non vi è
allocazione per *p.
Dichiarazione di variabile puntatore
ATTENZIONE!! E’ corretta anche la seguente
sintassi
T* var_puntatore
ma ricordate che in una lista di variabili , con
questa sintassi, solo la prima variabile è un
puntatore.
Es: int* p, quota;
p è un puntatore ad int, mentre quota è una
variabile di tipo int, non un puntatore !!
Operatori per puntatori
Gli operatori non aritmetici usati in espressioni
in cui sono coinvolti puntatori sono i seguenti
operatori unari:
• Operatore di indirizzo &
• Operatore di dereferenza *
Operatore di indirizzo
L’operatore unario di indirizzo & restituisce
l’indirizzo di memoria dell’operando.
L’operando è un oggetto.
Es:
&a
restituisce l’indirizzo di a
int* p, a;
p=&a;
p contiene l’indirizzo di memoria di a;
Operatore di indirizzo
L’operatore di indirizzo & non può mai essere
usato come lvalue, in quanto l’indirizzo di
memoria di una variabile è predeterminato e
non può essere modificato
Es:
&a=p;
&(a++);
Errato
Errato
Operatore di dereferenza
L’operatore unario di dereferenza * restituisce il
valore della variabile puntata dall’operando.
L’operando è un puntatore.
L’operatore * può essere usato:
•come rvalue ed esegue operazioni di estrazione
a=*p;
assegna ad a il valore della variabile
puntata da p
•come lvalue ed esegue operazioni di inserimento
*p=a;
assegna alla variabile puntata da p il
valore della variabile a
Operatore di dereferenza
Nel caso di puntatori a puntatori (puntatori a
indirizzamento multiplo), l’operatore * si può
applicare più volte:
int ***p, *p1,**p2, p3;
…..
p2 = *p;
p1 = **p;
p3 = ***p;
DOMANDA: E’ POSSIBILE APPLICARE PIU’
VOLTE L’OPERATORE & NELLA STESSA
ISTRUZIONE?
Operatore di dereferenza
L’operazione di dereferenza * è l’inversa
dell’operazione di indirizzamento &:
Es.
p = &a; // assegna a p l’indirizzo di a
allora l’espressione booleana
(*p ==a )
è sempre vera, cioè:
la dereferenza di p coincide con a
Operatore di dereferenza
ATTENZIONE!!!
Non è vero il contrario!!
Nell’istruzione
*p = a;
il valore di p non diventa l’indirizzo di a, ma il
valore della variabile puntata da p coincide con a.
Dichiarazione e Operatori: un esempio
int* p, val, n;
100
220 400 Indirizzo
... p ... ... val ... n Memoria
val = 12;
...
p ... ... val ... n
12
p= &val;
...
p ... ... val ... n
12
220
n = *p;
...
p ... ... val ... n
12
12
220
Aritmetica dei puntatori
Il valore di un puntatore è un numero intero che
rappresenta in byte un indirizzo di memoria.
Gli operatori aritmetici che è possibile usare con i
puntatori sono:
++
-+
+=
-=
Aritmetica dei puntatori
Vale la seguente regola:
Sia i un intero e p un puntatore ad un oggetto di
tipo T che occupa n locazioni di memoria. Sia addr
il valore di p.
L’espressione p + i ha come risultato addr + i x n
L’espressione p - i ha come risultato addr - i x n
Aritmetica dei puntatori
Esempi:
float *v;
int *p;
p= p + 5;
p++;
p-v++;
v = v+ 6;
// int è un intero a 2 byte
// p viene incrementato di 10 byte
// p viene incrementato di 2 byte
// p viene decrementato di 2 byte
// v viene incrementato di 4 byte
// v viene incrementato di 24 byte
Aritmetica dei puntatori
ATTENZIONE!!
E’ possibile sottrarre puntatori dello stesso tipo ma
NON è possibile sommare dei puntatori !!!
Assegnazione di valore a puntatori
E’ possibile assegnare un valore ad un puntatore
SOLAMENTE nei seguenti casi:
• assegnazione al puntatore del valore NULL (il
puntatore “punta a niente”)
• assegnazione al puntatore, tramite l’operatore
unario &, dell’indirizzo di una variabile definita
precedentemente (p.e. int i, *p=&i;)
•assegnazione tramite la allocazione dinamica della
memoria
Ulteriori operazioni con i puntatori
• Confronto tra puntatori ( p.e. = = , !=)
• E’ possibile, tramite il qualificatore const, definire
un puntatore in modo che non cambi il proprio
valore
Es:
int i;
int *const p = &i ; // p è un puntatore costante
all’intero i
Tentativi di modificare il valore di p portano ad
errore.
Ulteriori operazioni con i puntatori
E’ possibile, tramite il qualificatore const , definire
un puntatore in modo che non possa cambiare il
valore dell’oggetto puntato
Es:
int i;
const int *p = &i ; // p non può modificare i ;
Tentativi di modificare il valore di i tramite p
portano ad errore.
Puntatori e Reference
• Un riferimento (reference indipendente) è un nome
alternativo per un oggetto e deve essere sempre
inizializzato.
• Un riferimento è un puntatore costante ad un
oggetto e viene dereferenziato ogni volta che viene
richiamato
int x, &ret = x; //ret è un riferimento a x
int* p, y =10;
ret = y;
// x = y
ret++
// x viene incrementato di 1
p = &ret;
// p punta ad x
Puntatore void
Un puntatore void è un puntatore che accetta come
valore un indirizzo senza puntare ad un tipo
determinato.
Il puntatore void può riferirsi ad oggetti di tipo
differente
int x, *pi=&x;
float f, *pf=&f;
void *p;
p=pi;
*(int *)p = 3;
*(float *)p = 3.23;
Puntatori e Array
Il nome di un array senza indice è un puntatore
costante all’indirizzo del primo elemento
dell’array.
Pertanto, tale valore non può essere modificato
Es: str contiene l’indirizzo dell’elemento str[0]
dell’array str[80]
Puntatori e Array
La dichiarazione di un array comporta l’allocazione
di memoria di una variabile puntatore (il nome
dell’array) e dell’area puntata, di lunghezza
predefinita.
Il puntatore è definito const e inizializzato con
l’indirizzo dell’area puntata
Puntatori e Array
Es: int v [4]
• alloca memoria per il puntatore costante v
• alloca memoria per 4 elementi int
• inizializza v con l’indirizzo di v[0]
Per un int a 32 bit :
Indirizzo
Memoria
100
220 224 228 232
... v
... v[0] v[1] v[2] v[3] ...
220
valore
COSTANTE
Puntatori e Array
L’aritmetica dei puntatori può essere pertanto usata
per accedere agli elementi di in array.
Si ottiene un elemento di un array tramite
l’operatore di dereferenza * applicato al
puntatore-array incrementato di una quantità
pari all’indice dell’elemento cercato.
Es:
int v[20];
*(v+i) è equivalente a v[i]
Indicizzazione di Puntatori
E’ possibile indicizzare un puntatore come se fosse
un array per ottenere il valore dell’elemento
dell’array desiderato
Es:
int *p, v[20];
p=v;
…
cout << p[5] // visualizza il 6° elemento dell’array
Array di Puntatori
E’ possibile raggruppare i puntatori in array, come
una qualsiasi variable.
Es:
int *v[20];
dichiara un array di 20 puntatori a int.
Il nome di un array equivale ad un puntatore,
pertanto nel caso di array a puntatori equivale ad
un puntatore a puntatore.
Array di Puntatori
L’allocazione di memoria per un array di puntatori
è analoga a quella di un array qualsiasi.
Le regole di inizializzazione di ogni singolo
elemento di un array sono le stesse usate per
l’assegnazione di valori a puntatori
Es:
int p, i, *v[2]={&p, NULL};
Stringhe
Le stringhe sono degli array di tipo char con ‘\0’
come elemento che segue l’ultimo carattere
dell’array. In questo modo gli operatori e le funzioni
distinguono le stringhe dagli array di tipo char. Si
dice pertanto che una stringa è un “array di tipo
char null terminated”
L’inserimento di ‘\0’ è eseguito automaticamente dal
compilatore nel caso di costanti stringa.
Es:
char str[6]="Torre”
Il compilatore valorizza
str[0]=‘T’, str[1]=‘o’, str[2]=‘r’, str[3]=‘r’,
str[4]=‘e’, str[5]= ‘\0’
Stringhe
Es.:
char val[20];
Viene allocata memoria per 20 elementi di tipo char.
Affinchè val sia riconosciuta da operatori e funzioni
come una stringa occorre inserire il carattere ‘\0’;.
Es.:
val[0]=‘c’,val[1]=‘i’, val[2]=‘a’, val[3]=‘o’,
val[4]=‘\0’;
vengono impegnati 5 elementi di val[20] e i
rimanenti sono disponibili.
Stringhe
Se nella dichiarazione-inizializzazione di un array di
char a stringa viene omessa la dimensione
dell’array, allora viene allocata memoria per un
numero di byte pari alla lunghezza della stringa
aumentata di uno per considerare il carattere per
‘\0’.
Es.:
char str[ ]="Torre”;
alloca in memoria 6 elementi di tipo char.
Array di Stringhe
L’uso più frequente di array di puntatori è quello
degli array di stringhe , che vengono inizializzati in
maniera atipica per array di puntatori.
Es:
char *str[5]={"Torre", "Alfiere", "Cavallo", "Re", "Regina"};
Le stringhe possono essere di lunghezza diversa. In
memoria vengono allocate consecutivamente delle
locazioni pari al numero di bytes della stringa,
terminatore compreso.
Array di Stringhe
char *str[5]={"Torre", "Alfiere", "Cavallo", "Re", "Regina"};
• str[5] è un array di 5 elementi
• Ogni elemento dell’array è un puntatore al primo
elemento della stringa.
Il compilatore infatti memorizza tutte le costanti
stringa in una tabella apposita e pertanto è
necessario conoscere solo il puntatore per accedervi.
Scarica

1-_puntatori