G. Mecca – Università della Basilicata – mecca@unibas.it
Programmazione Procedurale in Linguaggio C++
Tipi Strutturati Concetti Avanzati
versione 2.5
Questo lavoro è concesso in uso secondo i termini di una licenza Creative Commons (vedi ultima pagina)
Sommario
m
Tipi Riferimento
m
Tipi Puntatore
ðValori per un Puntatore
ðDereferenziazione di un Puntatore
m
Puntatori e Riferimenti
m
Passaggio dei Parametri
ðPuntatori e ArrayTipi Strutturati: Concetti Avanzati >> Sommario
G. Mecca - Programmazione Procedurale in Linguaggio C++ 3
Tipi Riferimento
m
Parametro per riferimento
ðparametro che riceve come valore un
“riferimento” all’argomento
m
Riferimento ad un dato
ðintermediario tra il processore e il dato ðha come valore l’indirizzo di memoria del
dato
ðqualsiasi operazione effettuata sul
riferimento viene effettuata in realtà sul dato
4
Tipi Riferimento
m
In effetti
ði riferimenti in C++ possono essere utilizzati anche al di fuori del passaggio dei parametri ðper esempio è possibile dichiarare variabili
che sono riferimenti ad altri dati
ðe quindi possono essere utilizzate come intermediari per utilizzare i dati in questione
Tipi Strutturati: Concetti Avanzati >> Tipi Riferimento
G. Mecca - Programmazione Procedurale in Linguaggio C++ 5
Tipi Riferimento
m
Di che tipo sono le var. riferimento ?
ði riferimenti sono “tipati”: ogni riferimento può essere intermediario per dati di un solo tipo ðes: riferimento a intero, riferimento a stringa
ecc.
m
Tipo riferimento
ðdato un tipo T, il tipo dei riferimenti a dati di tipo T è T&
ðes: int&, char&, float& ...
Tipi Riferimento
m
Valore per un riferimento
ðoperazione di assegnazione ordinaria ða destra deve esserci il dato a cui riferirsi ðil dato deve essere del tipo opportuno ðil riferimento viene “legato” al dato
m
Esempio
ðchar c;
ðchar& rif = c;
ðstring& rif2 = c; // errore
Tipi Strutturati: Concetti Avanzati >> Tipi Riferimento
G. Mecca - Programmazione Procedurale in Linguaggio C++ 7
Riferimenti: Un Esempio
#include <iostream.h>
void main() { int x;
int& rif = x;
x = 1;
cout << "Valore di x: " << x << endl;
cout << "Valore di rif: " << rif << endl;
rif++;
cout << "Valore di rif dopo l'incr.:" << rif << endl;
cout << "Valore di x dopo l'incr.: " << x << endl;
}
>> riferimenti.cpp Valore di x: 1
Valore di rif: 1 Valore di rif dopo l’incr.: 2 Valore di x dopo l’incr.: 2
rif è un riferimento a x (intermediario per x)
le operazioni su rif
sono in realtà effettuate su x
8
Tipi Riferimento
m
Note sui riferimenti
ðdevono essere necessariamente inizializzati alla dichiarazione
ðint& rif; // errore sintattico ðint& rif = x; // OK
ðda quel momento in poi sono intermediari per il dato a cui sono stati legati
ðint x, y;
ðint& rif = x;
ðrif = y; // assegna a x il valore di y
Tipi Strutturati: Concetti Avanzati >> Tipi Riferimento
G. Mecca - Programmazione Procedurale in Linguaggio C++ 9
Tipi Riferimento
m
In altri termini
ðun riferimento deve essere inizializzato alla dichiarazione legandolo ad un dato del tipo opportuno
ðnon possono esistere riferimenti “indefiniti”
ðda quel momento in poi il riferimento è un intermediario per il dato a cui è stato legato ðe non può essere legato ad alcun altro dato
Tipi Riferimento
m
Utilizzo dei riferimenti
ðin sostanza esclusivamente per il passaggio dei parametri per riferimento
m
Semantica reale dei par. per riferimento
ðun par. per riferimento è un parametro di untipo riferimento
ðal passaggio dei parametri viene legato all’argomento
ðdiventa un intermediario per l’argomento
Tipi Strutturati: Concetti Avanzati >> Tipi Riferimento
G. Mecca - Programmazione Procedurale in Linguaggio C++ 11
Tipi Puntatore
m
Una delle caratteristiche del C/C++
ðconsentire al programmatore di gestire direttamente i registri della memoria ðovvero senza passare per le variabili e i
parametri
m
Compromesso tra vantaggi e svantaggi
ðefficienza (delle operazioni sono più rapide) ðpoca sicurezza (il codice diventa più fragile)12
Tipi Puntatore
m
Lo strumento per farlo
ði puntatorim
Puntatore
ðdato il cui valore corrisponde all’indirizzo di un altro dato (variabile, parametro, costante) ðil puntatore “punta” allo spazio di memoria
del dato
ðattraverso il puntatore è possibile manipolare il dato puntato
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 13
Tipi Puntatore
m ATTENZIONE
ðpuntatori e riferimenti: ci sono delle analogie ma sono concetti diversi
m In sintesi, per ora:
ðun riferimento è un intermediario gestito direttamente dal processore (utilizzo trasparente)
ðun puntatore può essere utilizzato come
intermediario, ma è il programmatore a doverlo fare ði puntatori sono stati pensati principalmente per altri
scopi (gestire direttamente la memoria)
Tipi Puntatore
m
Puntatori e tipi di dato
ðcome i riferimenti, anche i puntatori sono
“tipati”: ciascun puntatore può contenere l’indirizzo di dati di un solo tipo
ðes: puntatore a interi, puntatori a caratteri ...
m
Tipo puntatore
ðdato un tipo T, il tipo dei puntatori a dati di tipo T è T*
ðes: int*, char*, float* ...
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 15
Valori per un Puntatore
m
Valori ammissibili per un puntatore
ðil valore di qualsiasi indirizzo della memoria
m
Inoltre
ðai puntatori sono applicabili liberamente gli operatori aritmetici
m
Esempio
char* p; p = (char*) 1000;
p = p + 1;
p = p – 3;
p = p * 2;
assegna a p il valore del registro (p “punta” al registro 1000); il cast è necessario perché 1000 è una costante di tipo int
16
Valori per un Puntatore
m
Inoltre
ðattraverso il puntatore è possibile cambiare il valore dei registri di memoria
m
Esempio
void main() { char* p;
p = (char*) 1000;
*p = 1; // dereferenziazione >>
}
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
>> puntatori.cpp
ATTENZIONE: questo codice è sintatticamente corretto ma logicamente scorretto
G. Mecca - Programmazione Procedurale in Linguaggio C++ 17
Valori per un Puntatore
m
Il problema dei puntatori
ðla gestione diretta della memoria provoca facilmente errori di sconfinamento
ðtentativo di utilizzare zone di memoria non assegnate al programma (con gravi errori)
m
Utilizzo “corretto” dei puntatori
ðsolo per la manipolazione di zone di memoria assegnate ai dati del programma
ðcostanti, variabili, parametri
Valori per un Puntatore
m
Valori corretti per un puntatore
ðindirizzi di memoria di dati del programma
m
Due modi possibili
ðmodo n.1 chiedere l’indirizzo di un dato (variabile, parametro, costante) già dichiarato ðmodo n. 2 chiedere di assegnare un nuovo
spazio al programma e utilizzare l’indirizzo
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 19
Valori per un Puntatore
m
Modo n. 1
ðindirizzi di memoria di dati del programma ðottenibili a partire dai dati in questione
attraverso l’operazione di “referenziazione”
m
Operatore di “referenziazione”: &
ðapplicato ad un dato, restituisce il suo indirizzo di memoria
ðanche detto “operatore di indirizzo”
ðes: int x; int* p; p = &x; p “punta” a x ...
#1500 xxx
...
#1502 p
#1501 x
#1500
20
Valori per un Puntatore
m
Modo n. 2
ðindirizzo di un nuovo spazio di memoria ðè possibile chiedere un nuovo spazio con
l’operatore new
ðe poi rilasciarlo con l’operatore delete
m
Esempio:
float* p;ðp = new float;
ð... // operazioni su p ðdelete p;
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
...
... ...
xxx ...
xxx
#2500 ... ...
#1500 p #2500
*p
attribuisce al programma un nuovo spazio di memoria e ne assegna l’indirizzo a p
G. Mecca - Programmazione Procedurale in Linguaggio C++ 21
Valori per un Puntatore
m
Semantica di new <tipo>
ðattribuisce al programma un nuovo spazio di memoria del tipo specificato
ðrestituisce l’indirizzo del nuovo spazio
m
Semantica di delete p
ðlibera lo spazio di memoria puntato da p ðal termine il valore di p è indefinito (come
quello di un puntatore non inizializzato)
Valori per un Puntatore
m Attenzione
ðsi tratta di un meccanismo del tutto nuovo
m Finora
ðla memoria veniva attribuita al programma solo sulla base delle dichiarazioni
ðche erano stabilite a tempo di compilazione
m Con new e delete
ðposso richiedere e rilasciare memoria a tempo di esecuzione
ðè lo strumento che viene utilizzato per costruire strutture dinamiche (>>)
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 23
Valori per un Puntatore
m
Inoltre
ðla memoria attribuita al programma attraverso l’istruzione new NON viene allocata nella pila di attivazione
ðviene utilizzata una nuova zona di memoria
m
Heap (“Mucchio”)
ðzona di memoria riservata all’utilizzo dinamico della memoria con new e delete
24
Valori per un Puntatore
m
Un valore speciale per i puntatori: NULL
ðriferimento “nullo”ðquando un puntatore assume il valore NULL
“non punta a nessun registro della memoria”
m
Esempio
ðint* p;
ðp = NULL;
m
In alternativa
ðp = 0; // 0 e NULL sono equivalenti
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 25
Dereferenziazione di un Puntatore
m
Come utilizzare il dato puntato da un puntatore ?
ðattraverso un opportuno operatore applicato al puntatore
ðoperatore di “dereferenziazione”
m
Operatore di “dereferenziazione”: *
ðoperatore che, applicato ad un puntatore,consente di lavorare sullo spazio di memoria puntato dal puntatore
Dereferenziazione
m
Esempio:
char c;
char* p;
p = &c;
m
In questo caso
ð*pfa rappresenta lo spazio di memoria puntato da p (cioè lo spazio di c)
ðè possibile utilizzarlo come un qualsiasi altro dato nelle istruzioni
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 27
Un Esempio
#include <iostream.h>
void main() { char c;
char* p;
p = &c;
*p = 'a';
cout << "Valore di c: " << c << endl;
cout << "Valore di p: " << (int)p << endl;
cout << “Valore di *p: “ << *p << endl;
}
>> puntatori2.cpp Valore di c: a
Valore di p: 2500 Valore di *p: a
p “punta” a c (il valore di p è l’indirizzo di c)
*p rappresenta lo spazio di memoria di c
...
#2500
‘a’
...
#2502 p
#2501 c
#2500
28
Dereferenziazione
m Attenzione
ðil puntatore nullo (NULL) non può essere dereferenziato
ðsi tratta di un grave errore logico
m Nota
ða differenza dei puntatori, i riferimenti del C++ non possono essere nulli
ðdevono essere necessariamente inizializzati alla dichiarazione
ðma in linea di principio avrebbe senso avere anche riferimenti nulli
Tipi Strutturati: Concetti Avanzati >> Tipi Puntatore
G. Mecca - Programmazione Procedurale in Linguaggio C++ 29
Puntatori e Riferimenti
m
Puntatori e riferimenti
ðmolte analogie, alcune differenze sostanziali
m
In sintesi
ðnella sostanza, sono due strumenti diversi per fare le stesse cose
ðqualunque cosa si possa fare con i puntatori si può fare anche con i riferimenti
ðma ciascuno ha un utilizzo privilegiato
Puntatori e Riferimenti
m
Puntatore e riferimento: analogia
ðentrambi hanno come valore l’indirizzo di memoria del dato
Tipi Strutturati: Concetti Avanzati >> Puntatori e Riferimenti
void main() { char c;
char& rif = c;
...
}
void main() { char c;
char* p = &c;
...
}
...
#2500 xxx
...
valori di tipo char&
valori di tipo char
...
#2502 rif
#2501 c
#2500
...
#2500 xxx
...
valori di tipo char*
valori di tipo char
...
#2502 p
#2501 c
#2500
G. Mecca - Programmazione Procedurale in Linguaggio C++ 31
Puntatori e Riferimenti
m
Puntatore e riferimento: differenza
ðil riferimento è un intermediario “automatico”:
qualsiasi operazione sul riferimento viene automaticamente effettuata sul dato
ðil puntatore può essere utilizzato come se fosse un intermediario, ma il programmatore deve manipolare esplicitamente la memoria ðusando l’operatore di dereferenziazione
32
Puntatori e Riferimenti
m
Nell’esempio precedente
Tipi Strutturati: Concetti Avanzati >> Puntatori e Riferimenti
void main() { char c;
char& rif = c;
rif = ‘a’;
}
void main() { char c;
char* p = &c;
*p = ‘a’;
}
...
#2500 xxx
...
valori di tipo char&
valori di tipo char
...
#2502 rif
#2501 c
#2500
...
#2500 xxx
...
valori di tipo char*
valori di tipo char
...
#2502 p
#2501 c
#2500
‘a’ ‘a’
G. Mecca - Programmazione Procedurale in Linguaggio C++ 33
Puntatori e Riferimenti
m
Ricapitolando
ðabbiamo introdotto due nuovi categorie di tipi: tipi riferimento e tipi puntatore
ðabbiamo introdotto due nuovi operatori:
operatore di indirizzo (&), operatore di dereferenziazione (*)
m
Utilizzo di & e *
ðdue funzioni diverse per ciascun simbolo ðattenzione a non fare confusione
Puntatori e Riferimenti
Tipi Strutturati: Concetti Avanzati >> Puntatori e Riferimenti
operatore di dereferenz.:
serve ad utilizzare lo spazio di memoria puntato dal dato (che deve essere un puntatore)
es: *p = ‘x’;
operatore di indirizzo:
restituisce l’indirizzo di memoria del dato (parametro, costante, variabile)
es: char* p = &c;
Prima di un dato
definisce un tipo puntatore es: char* p;
definisce un tipo riferimento es: int& rif = x;
Dopo un tipo
*
&
G. Mecca - Programmazione Procedurale in Linguaggio C++ 35
Puntatori e Riferimenti
m Riferimenti
ðvengono dichiarati di tipo riferimento
(utilizzo di & nella dichiarazione dopo il tipo) ðvengono utilizzati come dati ordinari
(senza bisogno di & né * nelle istruzioni)
m Puntatori
ðvengono dichiarati di tipo puntatore
(utilizzo di * nella dichiarazione dopo il tipo) ðper assegnargli un valore si usa &
ðper utilizzare lo spazio di memoria si usa *
36
Puntatori e Riferimenti
m
Utilizzo principale dei riferimenti
ðpassaggio dei parametri per riferimento
m
Utilizzi principale dei puntatori
ðcostruire strutture di dati “collegate” di carattere dinamico
ðes: rappresentazione collegata per le liste ðne parleremo più avanti (>>)
Tipi Strutturati: Concetti Avanzati >> Puntatori e Riferimenti
G. Mecca - Programmazione Procedurale in Linguaggio C++ 37
Puntatori e Riferimenti
m
Ma
ði due tipi di dato sono in pratica sostituibili
m
In particolare
ði puntatori possono essere utilizzati per
simulare il pass. per riferimento nei linguaggi in cui ci sono solo par. per valore (es: C) ði riferimenti possono essere utilizzati per
costruire strutture collegate nei linguaggi senza gestione della memoria (es: Java)
Passaggio dei Parametri
m
In C++
ðparametri standard (di tipo ordinario)
ðparametri per riferimento (di tipo riferimento)
m
Ma
ðesistono linguaggi in cui non esistono i tipi riferimento
ðesempio: il linguaggio C
ðin questi linguaggi: solo parametri standard ðcome è possibile modificare gli argomenti ?
Tipi Strutturati: Concetti Avanzati >> Passaggio dei Parametri
G. Mecca - Programmazione Procedurale in Linguaggio C++ 39
Passaggio dei Parametri
m
Soluzione
ðsi utilizzano i tipi puntatore
m
Idea
ðil parametro viene dichiarato di tipo puntatore ðl’argomento che viene passato è l’indirizzo
del dato da modificare
ðnel sottoprogramma il puntatore viene dereferenziato per utilizzare il dato
ðcioè: il puntatore è usato come intermediario
40
Passaggio dei Parametri
m
Un esempio semplice
ðun programma che scambia il valore di due variabili
ðun sottoprogramma per lo scambio
m
Scambio di due valori x e y
ðuso un terzo valore, zðassegno il valore di x a z ðassegno il valore di y a x ðassegno il valore di z a y
Tipi Strutturati: Concetti Avanzati >> Passaggio dei Parametri
III passo II passo I passo v. iniziali Esempio
5 5 10
5 10 10
5 10 5
xxx 10 5
z y x
G. Mecca - Programmazione Procedurale in Linguaggio C++ 41
Passaggio dei Parametri
m
Nota
ðse non utilizzassi la variabile z non potrebbe funzionare
m
Esempio
ðassegno il valore di x a y ðassegno il valore di y a x ðanalogamente se faccio il
contrario
II passo I passo v. iniziali Esempio
5 5
5 5
10 5
y x
Passaggio dei Parametri
#include <iostream.h>
void scambia (int& x, int& y);
void main() { int a, b;
cout << "Immetti il valore di a: "; cin >> a;
cout << "Immetti il valore di b: "; cin >> b;
scambia(a, b);
cout << "Valore di a dopo lo scambio: " << a << endl;
cout << "Valore di b dopo lo scambio: " << b << endl;
}
void scambia (int& x, int& y) { int z;
z = x;
x = y;
y = z;
return;
}
Tipi Strutturati: Concetti Avanzati >> Passaggio dei Parametri
>> scambio1.cpp
G. Mecca - Programmazione Procedurale in Linguaggio C++ 43
Puntatori e Array
m
Una particolarità del C++
ðil passaggio dei parametri di tipo array ðfinora considerata una eccezione
m
In realtà
ðsi tratta di un passaggio di parametri basato su puntatori
ðper via della particolare natura degli array in C/C++
44
Puntatori e Array
m
Array
ðzona di memoria di variabili dello stesso tipo ðpiù una variabile aggiuntiva: la variabile array
m
Variabile array
ðpuntatore alla zona di memoria dell’array
m
Parametro array
ðparametro di tipo puntatore
ðil parametro viene dereferenziato con []
Tipi Strutturati: Concetti Avanzati >> Passaggio dei Parametri
G. Mecca - Programmazione Procedurale in Linguaggio C++ 45
Puntatori e Array
m
In effetti, in C/C++
ði tipi array e i tipi puntatori sono strettamente legati e di fatto intercambiabili
ðper ogni tipo T, T* e T[] sono equivalenti es: int* e int[]
ðle parentesi quadre sono operatori di dereferenziazione
ðse x è un array: x[i] = *(x + i)
Puntatori e Array
m
Esempio:
float temp[N];ðla variabile array temp è di tipo float*
ðtemp[0]è equiv a *temp (la prima variabile dell’array)
ðtemp[1]è equiv a *(temp + 1) (la seconda variabile dell’array)
ðtemp[2]è equiv a *(temp + 2) (la terza variabile dell’array) ð...
Tipi Strutturati: Concetti Avanzati >> Passaggio dei Parametri
G. Mecca - Programmazione Procedurale in Linguaggio C++ 47
Puntatori e Array
m
Di conseguenza
ðtutto quello che il sottoprogramma ha
bisogno di conoscere è il puntatore all’array ðnon è indispensabile che conosca la
dimensione dell’array
ðnon vengono fatti controlli sullo sconfinamento
ðdi conseguenza non è indispensabile specificare la dimensione di un par. array
48
Esempio: Le Temperature
#include <iostream.h>
const int N = 12;
void leggi (float temp[N]);
void stampa (float temp[N]);
void main() {
float temperature[N];
leggi (temperature);
stampa (temperature);
...
}
Tipi Strutturati: Concetti Avanzati >> Passaggio dei Parametri
prototipi equivalenti:
void leggi (float* temp);
void stampa (float* temp);
void leggi (float temp[]);
void stampa(float temp[]);
>> temperature3.cpp
G. Mecca - Programmazione Procedurale in Linguaggio C++ 49
Riassumendo
m
Tipi Riferimento
m
Tipi Puntatore
ðValori per un Puntatore
ðDereferenziazione di un Puntatore
m
Puntatori e Riferimenti
m
Passaggio dei Parametri
ðPuntatori e ArrayTermini della Licenza
m This work is licensed under the Creative Commons Attribution- ShareAlike License. To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/1.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
Termini della Licenza
m Questo lavoro viene concesso in uso secondo i termini della licenza “Attribution-ShareAlike” di Creative Commons. Per ottenere una copia della licenza, è possibile visitare
http://creativecommons.org/licenses/by-sa/1.0/ oppure inviare una lettera all’indirizzo Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.