Strutture Dati
Nicola Fanizzi
Linguaggi di
Dipartimento di Informatica Programmazione [010194]
Università degli Studi di Bari 9 mag, 2016
Sommario
1
2
Tipi e sistemi di tipi
Definizioni
Sistemi di tipi
Tipi scalari
Tipi scalari e ordinali
Booleani
Caratteri
3
Numerici: interi, reali,
complessi
void
Enumerazioni e intervalli
Tipi Composti
Record
LdP.ITPS/[email protected]
Array
Insiemi
Puntatori
4 Relazioni fra tipi
Equivalenza
Compatibilità e
conversione di tipo
Polimorfismo
Controllo e Inferenza
5 Strutture dati e gestione
della memoria
Dangling reference
Garbage collection
Strutture Dati
9 mag, 2016
2 / 88
Agenda
1
Tipi e sistemi di tipi
Definizioni
Sistemi di tipi
3
Tipi Composti
4
Relazioni fra tipi
5
2
Tipi scalari
LdP.ITPS/[email protected]
Strutture dati e gestione
della memoria
Strutture Dati
9 mag, 2016
3 / 88
Introduzione
Scopi dei Tipi di dato:
Progetto: supporto all’organizzazione concettuale
Programma: supporto alla correttezza
Traduzione: supporto all’implementazione
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
4 / 88
Tipi
Definizione (Tipo)
Un tipo di dato è una
collezione di valori omogenei,
effettivamente presentabili,
dotata di un insieme di operazioni che manipolano tali valori
Omogeneità I valori condividono alcune proprietà strutturali
Presentabilità Devono potere avere una presentazione finita per
la loro scrittura
es. non esiste un tipo dei numeri reali veri e
propri
Operazioni La stessa collezione di valori può essere impiegata
in tipi diversi a seconda delle operazioni definite
es. i tipi interi nei vari linguaggi
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
5 / 88
Tipi – utilità
Progetto: Supporto all’organizzazione concettuale
Dominare la complessità dei problemi
Esplicitare i concetti tipici attraverso nuovi tipi
Aumento di leggibilità (documentazione)
e di sicurezza (controlli automatici)
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
6 / 88
Tipi – utilità [. . . cont.]
Programma: Supporto alla correttezza
Vincoli di tipo (problemi di semantica)
errori HW
es. salto a zona di memoria che non contiene codice
errori logici
es. somma intero + stringa
Controlli semantica statica: Type checker
come i commenti ma i controlli sono effettuabili
automaticamente
non risolvono tutti i problemi logici:
es. formule della fisica, prima controlli sulle dim.
Polimorfismo
es. stessa funzione (es. sort) su strutture di tipi diversi
Sicurezza: vincoli soddisfatti ma problemi rilevati in fase
d’esecuzione?
linguaggi sicuri e non
es. dangling reference
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
7 / 88
Tipi – utilità [. . . cont.]
Traduzione: Supporto all’implementazione
Informazioni per la macchina astratta
disponibili staticamente
Dimensione richiesta per l’allocazione
sia nel RdA sullo stack
sia su heap
Ottimizzazioni sulle op. d’accesso
Calcoli statici
Ind. oggetto + offset
LdP.ITPS/[email protected]
(no ricerca per nome)
Strutture Dati
9 mag, 2016
8 / 88
Sistemi di tipi
Sistema di tipi: complesso delle informazioni e delle regole che
governano i tipi di un linguaggio
1
Insieme dei tipi predefiniti
2
Costrutti per definire nuovi tipi
Meccanismi per il controllo dei tipi
3
Regole di equivalenza: due tipi formalmente diversi possono
essere equivalenti livello semantico
Regole di compatibilità: un valore di un tipo diverso da quello
atteso può essere comunque utilizzato
Regole di inferenza: attribuzione di un tipo ad un’espressione
complessa in base alle componenti
4
se/quali vincoli controllare staticamente/dinamicamente
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
9 / 88
Sistemi di tipi - sicurezza
Un sistema di tipi (e, per estensione, un linguaggio) si dice
type-safe1 (sicuro a livello di tipi) quando nessun programma
può ignorare le differenze tra tipi definite dal sistema/linguaggio
nessun programma può generare errori inattesi derivanti da
violazioni di tipo a run-time
ad esempio:
accesso a memoria non allocata
chiamata di un valore che non si riferisce ad una funzione
1
o strongly typed (fortemente tipizzato).
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
10 / 88
Classificazione dei tipi
In base ai valori (... ed alle operazioni):
denotabili possono essere associati ad un nome
esprimibili possono essere il risultato di una espressione
complessa (più di un semplice nome)
memorizzabili possono essere memorizzati in una variabile
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
11 / 88
Classificazione dei tipi [. . . cont.]
Esempi
Tipo delle funzioni (int -> int)
valore denotabile: possiamo associare un nome ad una
funzione
1
2
3
int succ (int x) {
return x + 1;
}
valore esprimibile: solo nei ling. funzionali e non negli
imperativi
Funzioni risultato della valutazione di un’espressione
valore memorizzabile
idem (ML, HASKELL, SCHEME)
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
12 / 88
Sistemi di tipi – controlli
Tipizzazione statica: controlli a compile-time (es. JAVA)
Controlli anticipati
Correttezza garantita per ogni sequenza d’esecuzione
Controlli a run-time inutili: maggiore efficienza
Progettazione più complessa se il linguaggio deve anche
essere type-safe
Compilazione lenta e complessa ma facilita debugging/testing
Tipizzazione dinamica: controlli a run-time (es. LISP)
Ogni oggetto ha un descrittore che ne contiene il tipo
La macchina astratta controlla la correttezza degli operandi
nelle operazioni
Il compilatore ha generato codice di controllo opportuno
Caratteristiche
previene errori di tipo (troppo tardi?)
esecuzione meno efficiente
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
13 / 88
Sistemi di tipi – controlli [. . . cont.]
Osservazioni
Programmi sicuri che la tipizzazione statica può male
interpretare come errati:
Controllo statico: più conservatore
Esempio
dato il frammento:
int x;
if (1==0) x = "errore";
3 else x = x + 2;
1
2
l’esecuzione non causa errore ma risulta non corretto al
controllo statico
Controllo sui tipi in generale: problema indecidibile
Per prudenza un controllo statico esclude anche casi non
pericolosi, come il precedente
In molti linguaggi (es. PASCAL) controllo statico+dinamico
es. utilizzo di vettori con controllo degli indici a run-time
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
14 / 88
Indecidibilità del controllo sui tipi
Controllo statico: più conservatore
1
2
3
int x;
Proc();
x = "errore";
Se si potesse sapere sempre se Proc() termina
allora si potrebbe segnalare l’errore di tipo
E se Proc() non terminasse mai ?
allora l’errore di tipo non si verificherebbe
quindi il programma sarebbe corretto
Essendo il problema della fermata indecidibile
lo sarà anche quello del controllo della correttezza dei tipi
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
15 / 88
Agenda
Enumerazioni e intervalli
1
2
Tipi e sistemi di tipi
Tipi scalari
Tipi scalari e ordinali
Numerici: interi, reali,
complessi
void
LdP.ITPS/[email protected]
3
Tipi Composti
4
Relazioni fra tipi
5
Strutture dati e gestione
della memoria
Strutture Dati
9 mag, 2016
16 / 88
Tipi scalari
Tipi scalari (o semplici): tipi i cui valori sono atomici,
i.e. non sono costituiti da aggregati di altri valori
notazione
type <nometipo> = <espressione>;
Tipi ordinali (o discreti): dotati di una relazione d’ordine totale
Valori: discreti
booleani, caratteri, interi, enumerazioni ed intervalli
Operazioni: precedente e successivo
Utili per gli indici
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
17 / 88
Booleani
Per valori logici (o di verità)
Valori: uno per il vero (es. true) uno per il falso (es. false)
Operazioni:
congiunzione (and), disgiunzione (or), negazione (not), or
esclusivo, uguaglianza
Valori denotabili, esprimibili, memorizzabili
Memorizzazione nelle minime unità di memoria indirizzabili
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
18 / 88
Caratteri
Valori: un insieme di codici di caratteri fissato durante la
progettazione del linguaggio
Es: ASCII, UNICODE
Operazioni:
logiche uguaglianza, confronti,
ordinali carattere successivo (succ) o precedente (prec)
Valori denotabili, esprimibili, memorizzabili
Memorizzazione con 1 (ASCII) o 2 (UNICODE) byte
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
19 / 88
Interi
Valori: sottoinsieme finito dei numeri interi
fissato durante la progettazione del linguaggio o della
macchina astratta
Di solito del tipo [−2t , +2t − 1]
A volte sono possibili interi di lunghezza illimitata
Operazioni aritmetiche e confronti
Somma, differenza, prodotto, divisione (intera), resto, potenza
Valori denotabili, esprimibili, memorizzabili
Memorizzazione con un numero (pari) di byte in
complemento a due
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
20 / 88
Reali
numeri reali in virgola fissa
Valori: sottoinsieme finito dei numeri razionali
fissato durante la progettazione del linguaggio o della
macchina astratta
Ampiezza e granularità, ecc. dell’insieme dipendono dalla
rappresentazione scelta
Operazioni aritmetiche e confronti
Somma, differenza, prodotto, divisione (intera), resto,
esponenziale, radice quadrata
Valori denotabili, esprimibili, memorizzabili
Memorizzazione con un numero di 4 o 8 byte
complemento a 2
numero fissato di bit per la parte decimale
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
21 / 88
Reali [. . . cont.]
virgola mobile
Valori: sottoinsieme finito dei numeri razionali
fissato durante la progettazione del linguaggio o della
macchina astratta
Ampiezza e granularità, ecc. dell’insieme dipendono dalla
rappresentazione scelta
Operazioni aritmetiche e confronti
Somma, differenza, prodotto, divisione (intera), resto,
esponenziale, radice quadrata
Valori denotabili, esprimibili, memorizzabili
Memorizzazione con un numero di 4,8,10 byte
Standard IEEE 754
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
22 / 88
Complessi
numeri complessi
Valori: sottoinsieme finito dei numeri complessi fissato
durante la progettazione del linguaggio
Ampiezza e granularità, ecc. dell’insieme dipendono dalla
rappresentazione scelta
Operazioni aritmetiche e confronti
Somma, differenza, prodotto, divisione (intera), resto,
esponenziale, radice quadrata
Valori denotabili, esprimibili, memorizzabili
Memorizzazione con una coppia di reali in virgola mobile
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
23 / 88
void
Valori: un solo valore
void o unit (insieme singoletto) oppure { }
una funzione matematica non può avere codominio vuoto
sono tali le funzioni che divergono sempre
Operazioni: nessuna
Utile a denotare operazioni che non restituiscono un valore
utile (ma hanno effetti collaterali)
es. assegnamento (in molti linguaggi)
ossia restituiscono un unico valore implicitamente
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
24 / 88
Enumerazioni
Tipi semplici definiti dall’utente
Valori: un insieme finiti di costanti caratterizzate da un
proprio nome
es. type giorni = (lun,mar,mer,gio,ven,sab,dom);
Operazioni: confronti, operatori per raggiungere il valore
precedente o il successivo
Vantaggi
Aumenta la leggibilità
Ausilio del controllo dei tipi
Memorizzazione: mappaggio sugli interi
In alcuni linguaggi (C/C++, ADA, ...) si possono anche scegliere
esplicitamente
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
25 / 88
Intervalli
Tipi semplici definiti dall’utente
Valori: sottoinsieme contiguo dei valori di un altro tipo
scalare (tipo base)
1
2
type NumeriLotto = 1..90;
Giorniferiali = lun..ven;
Operazioni: confronti, operatori per raggiungere il valore
precedente o il successivo
Vantaggi
Maggiore la leggibilità
Ausilio al controllo dei tipi: dinamico
Memorizzazione: mappati sugli interi
Come per il tipo base
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
26 / 88
Agenda
1
Tipi e sistemi di tipi
2
Tipi scalari
Array
Insiemi
Puntatori
Relazioni fra tipi
4
3
Tipi Composti
Record
LdP.ITPS/[email protected]
5
Strutture dati e gestione
della memoria
Strutture Dati
9 mag, 2016
27 / 88
Tipi Composti
Tipi non scalari, ottenuti per combinazione di tipi più semplici
Record (o strutture): collezione di valori eterogenei
Array: collezione di valori omogenei
Insiemi: sottoinsiemi di un tipo (base, ordinale)
Puntatori: l-valori per accedere indirettamente ad altri valori
Tipi ricorsivi: definiti per ricorsione
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
28 / 88
Record (o strutture)
Record: Collezione di un numero finito (e spesso ordinato) di
elementi detti campi
Ogni campo è caratterizzato
dal nome
dal tipo (anche diverso da quello degli altri campi) si può
assimilare quindi ad una variabile
Spesso è possibile annidare record all’interno di record
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
29 / 88
Record (o strutture) [. . . cont.]
Esempio
type studente = struct {
int matricola;
3
float statura;
4 };
1
2
LdP.ITPS/[email protected]
Esempio
annidamento
type Aula = struct {
char nome[5];
3
int capienza;
4
struct {
5
char dipart[10];
6
int tel;
7
} segreteria;
8 };
9 ...
10 Aula a;
11 a.nome = ’B-1’
12 a.segreteria.tel = 1234;
1
2
Strutture Dati
9 mag, 2016
30 / 88
Record (o strutture) [. . . cont.]
Operazioni:
selezione, indicata con “.”
alcuni linguaggi ammettono
assegnazione e test di uguaglianza tra interi record
se non permesse bisogna procedere campo per campo
l’ordine dei campi può essere significativo
Memorizzazione in locazioni
contigue nell’ordine di
definizione
Esempio
nome
capienza
Diverse organizzazioni
possibili dovute
all’allineamento
dipartimento
Migliora l’efficienza nel
reperimento
LdP.ITPS/[email protected]
arch. 32bit
telefono
Strutture Dati
9 mag, 2016
31 / 88
Record varianti e unioni
Record varianti: record con campi mutuamente esclusivi
Nomi e sintassi diverse per ogni linguaggio
es. in PASCAL, record con una parte della struttura variabile:
solo una delle varianti ammesse è significativa
Esempio
type studente = record
nome: array [1..6] of char;
3
matricola: integer;
4
case fuoricorso: boolean of
5
true: (ultimoanno: 2000..maxint);
6
false:( inpari: boolean;
7
anno: (primo,secondo,terzo)
8
)
9
end;
1
2
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
32 / 88
Record varianti e unioni [. . . cont.]
unioni strutture con campi mutualmente esclusivi
Nomi e sintassi diverse per ogni linguaggio
es. in C, struttura con un solo campo alla volta valido
union per la parte variante
struct studente {
char[6] nome;
3
int matricola;
4
int fuoricorso;
5
union { int ultimoanno;
6
struct { int inpari;
7
int anno;
8
} studente_in_corso;
9
} campi_varianti;
10 }
1
2
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
33 / 88
Record varianti e unioni [. . . cont.]
Record varianti vs. Unioni
Similarità
Differenze
Le varianti e le unioni condividono le stesse aree
di memoria
In C un campo della union è svincolato dal resto
più flessibile
più oneroso per il programmatore
più rischioso
Livelli di nomi:
In PASCAL, campo come gli altri: s.inpari
In C, occorre aggiungere ulteriori livelli di nomi
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
34 / 88
Record varianti e unioni [. . . cont.]
Problema di sicurezza modifica tag discriminante con
assegnamento ordinario (in PASCAL e C)
La macchina astratta potrebbe controllare (dinamicamente)
il tag per sapere se il record è usato correttamente
risolve molti problemi semantici ma non tutti
1 type Tre = 1..3;
ma anche
var tmp: record
case quale: Tre of
4
1: (a:integer);
5
2: (b:boolean);
6
3: (c:char);
7
end
8 ...
9 tmp.quale:=1;
10 tmp.a:=123;
11 write(tmp.c);
12 (* errore a run-time *)
2
3
LdP.ITPS/[email protected]
tmp.quale:=1;
tmp.a:=123;
3 tmp.quale:=3;
4 write(tmp.c);
5 (* semanticamente errato,
6
ma non rilevato *)
1
2
Strutture Dati
9 mag, 2016
35 / 88
Array
Array: Collezione finita di elementi dello stesso tipo (tipo base)
indicizzata su un intervallo di tipo ordinale (tipo indice)
Specifica
Nome
Tipo indice
Tipo dei componenti
es. in C: int v[10];
Array multidimensionali:
usando indici molteplici
a volte come array di
array
op. di slicing ritagliare
una “fetta”, fissando una
dim.
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
36 / 88
Array [. . . cont.]
Operazioni
Selezione: si indica (spesso tra [...]) un’espressione il cui
valore rappresenta l’indice dell’elemento da selezionare
es. array monodimensionale: v[<espr>]
es. array multidimensionale:
m[<espr_1>][<espr_2>]...[<espr_n>]
Assegnamento
Test di uguaglianza ed altri test di confronto
Op. dell’algebra lineare
nei ling. che supportano il trattamento delle matrici
Slicing
slice: sezione di array costituita da elementi contigui in una
data dimensione (es. un piano)
in alcuni linguaggi si possono estrarre anche selezioni
diagonali cornici, ecc.
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
37 / 88
Array [. . . cont.]
Controlli
Selezione entro i limiti del tipo indice
A run-time
Per un linguaggio safe:
il compilatore genera controlli per ogni selezione
generazione spesso disattivabile con un’opzione del compilatore
Safety & security
Attacchi buffer overflow
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
38 / 88
Array [. . . cont.]
Memorizzazione
Sezioni contigue di memoria
Array monodimensionale
Allocazione secondo l’ordine degli indici
Array multidimensionale
Ordine di riga
Elementi contigui differiscono di un’unita nell’indice più a
destra nella lista
Ordine di colonna
Elementi contigui differiscono di un’unita nell’indice più a
sinistra nella lista
Dividere nell’una o l’altra maniera può avere un impatto
sull’efficienza del caching
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
39 / 88
Array [. . . cont.]
Calcolo degli indici
Dato un array m a n dimensioni di tipo T
T m[L1 ,U1 ][L2 ,U2 ]...[Ln ,Un ]
Sn : unità di mem. indirizzabili per elem. di T (per riga)
Sn−1 = (Un − Ln + 1)Sn (slice di ordine superiore)
...
S1 = (U2 − L2 + 1)S2
Per cercare l’indirizzo di m[i1 ][i2 ]...[in ]
all’indirizzo iniziale, si somma l’offset:
(i1 − L1 )S1 + (i2 − L2 )S2 + · · · + (in − Ln )Sn
Se le dim. sono tutte note, meglio usare:
i1 S1 + · · · + in Sn − (L1 S1 + · · · + Ln Sn )
n moltiplicazioni, n addizioni, n sottrazioni
(che
P non servono se gli indici partono da 0,
i Li Si predeterminato)
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
40 / 88
Array [. . . cont.]
Forma (shape): numero delle dim. e intervallo per ogni dim.
Quando viene fissata ?
Statica al momento della compilazione (dim. fissate)
Array nel RdA (o nella mem. per le var. globali)
Accesso tramite la formula precedente
Elaborazione della dichiarazione
Intervallo indici dipendente da un’espressione variabile
Calcolo a run-time
Array nel RdA: ma offset non noto!
Parte fissa (offset) e parte variabile (ind. indiretto)
Dinamica
Limiti modificabili
Allocazione sull’heap: (sulla pila non è possibile)
Nel RdA: puntatore all’array
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
41 / 88
Array [. . . cont.]
Dope vector: descrittore di array di forma non nota staticamente
Allocato nella parte a lunghezza fissa del RdA riservata
all’array
Contiene:
puntatore alla prima cella dell’area di mem. riservata all’array
informazioni dinamiche utili
(non memorizzate se determinabili staticamente)
numero dimensioni
limiti per ogni dim. (Li , Ui )
occupazione per ogni dim. (Si )
Accesso ad un elemento:
accesso per offset tramite frame pointer al dope vector
calcolo della formula precedente
si somma all’indirizzo dell’inizio dell’array
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
42 / 88
Array [. . . cont.]
...
lunghezza variabile
m
...
var locali
lunghezza fissa
L3
S3
L2
S2
L1
S1
dope vector di m
puntatore ad m
...
frame pointer
ind.ritorno
parametri
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
43 / 88
Insiemi
Insieme: collezione di valori che costituiscono un sottoinsieme di
un tipo base (universo)
Solitamente il tipo base è ordinale (PASCAL)
Esempi
set of char S;
set of Giorni IG; WE = (Sab, Dom);
Operazioni
Appartenenza (∈, in)
Unione (+), intersezione (*), differenza (-)
(a volte anche complemento)
Rappresentazione
vettori di bit (vettore caratteristico)
Vj = 1 sse il j-esimo elemento dell’universo appartiene
all’insieme
Tabelle hash . . .
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
44 / 88
Puntatori
Puntatore: tipo di variabili atte a contenere l-valori, direttamente
manipolabili, utili a riferirsi indirettamente ad altre var.
In genere è possibile indicare anche il tipo delle variabili
puntate
TipoBase * P;
In PASCAL o ADA: possono solo puntare a variabili del tipo dato
In C/C++: non c’è un vincolo stretto
Ove presenti, consentono la definizione di tipi ricorsivi senza
primitive apposite
Nei linguaggi con variabili-riferimento, gli l-valori non
possono essere manipolati direttamente
valore nullo: il puntatore non punta ad alcuna variabile
es. null (o nil, in PASCAL)
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
45 / 88
Puntatori [. . . cont.]
Operatori
Assegnamento di un valore ad un puntatore mediante
Allocazione esplicita
int *p;
p = (int *) malloc(sizeof (int));
Costruttori (di oggetti)
Operatore &
float pigreco = 3.1415, *pp;
pp = &pigreco;
Dereferenziazione
^ (PASCAL) oppure * (in C/C++)
es. precedente: float circ = 2 * r * (*pp );
Vale sia per l’l-valore sia per l’r-valore
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
46 / 88
Puntatori [. . . cont.]
test di uguaglianza
Creazione di strutture ricorsive
Quando non previste dal linguaggio
es. lista di interi (successione ordinata di dim. variabile)
typedef nodo* lista_int;
typedef struct { int val;
3
lista_int succ} nodo;
1
2
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
47 / 88
Puntatori [. . . cont.]
Aritmetica
In C ed alcuni derivati: operazioni aritmetiche su puntatori
Incremento/decremento di un puntatore: p++ / p-indirizzo incrementato di sizeof(tipobase)
Sottrazione di puntatori: p1 - p2
Offset tra p1 e p2
Somma di un quantità ad un puntatore: p + n
punta alla variabile con offset pari a n*sizeof(tipobase)
Nociva per la type-safety del linguaggio
Non c’è garanzia che in tutti i momenti un puntatore punti
effettivamente ad una variabile del tipo atteso
int *p;
int *c;
3 p = (int*) malloc(sizeof(int));
4 c = (char*) malloc(sizeof(char));
5 p = p+1
6 c++;
1
2
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
48 / 88
Puntatori [. . . cont.]
Deallocazione
implicita nessuno strumento per deallocare la memoria
avviene quando non c’è più spazio sullo heap
possibile recuperare memoria inutilizzata
tecniche di garbage collection
esplicita costrutto previsto dal linguaggio
In C: funzione free()
free(p) libera la memoria della variabile puntata da p
e conviene anche assegnare: p=null;
se p vale già null allora si ha un errore semantico
Dangling reference: puntatori con valore diverso da
null che puntano a zone non più significative
memoria deallocata o ri-allocata
riferimenti non validi alla pila d’esecuzione
(anche con deallocazione implicita)
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
49 / 88
Tipi ricorsivi
Tipi composti in cui un valore può contenere (un riferimento ad)
un valore dello stesso tipo
Esempi
1
2
(pseudocodice):
type ListaInt = { int val;
ListaInt next; }
type AlberoChar = { char val;
AlberoChar sinistro;
3
AlberoChar destro; }
1
2
Operazioni
Selezione
Test di uguaglianza
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
50 / 88
Tipi ricorsivi [. . . cont.]
Rappresentati con strutture dati su heap
Ling. Imperativi: Strutture concatenate
(ottenute con riferimenti/puntatori)
Allocazione esplicita
Ling. Funzionali: espressione diretta di val. di tipi ricorsivi
No deallocazione
1
ListaInt: (2,(33,(1,(4,(3,(1,21,null)))))))
2
CharAlbero:
(A,
5
(B,
6
(C,null,null),
7
(D,
8
(E,null,null),
9
null
10
),
11
(F,null,null)
12 )
3
A
4
LdP.ITPS/[email protected]
B
C / /
F / /
D
/
E / /
Strutture Dati
9 mag, 2016
51 / 88
Tipi di funzioni
Alcuni linguaggi permettono di definire tipi di funzioni
i valori di questi tipi sono funzioni
tipo di funzione denotato con
T f(S1 s1, S2 s2, ... , Sn sn) {...}
oppure anche con
S1 x S2 x ... x Sn -> T
Operazioni
Definizione (soprattutto funzionali)
Applicazione (chiamata su parametri effettivi)
Valori implementati come puntatori
PASCAL, C, C++
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
52 / 88
Agenda
1
Tipi e sistemi di tipi
2
Tipi scalari
3
Tipi Composti
LdP.ITPS/[email protected]
4
Relazioni fra tipi
Equivalenza
Compatibilità e
conversione di tipo
Polimorfismo
Controllo e Inferenza
5
Strutture dati e gestione
della memoria
Strutture Dati
9 mag, 2016
53 / 88
Equivalenza
Regole utili a stabilire quando due tipi, formalmente diversi, sono
intercambiabili, ossia non distinguibili nel loro uso
per due tipi equivalenti, ogni espressione/valore del primo
tipo è anche espressione/valore del secondo e viceversa
Definizione di un nuovo tipo
type nuovotipo = espressioneTipo
Regole per la sua interpretazione:
Definizione opaca: equivalenza per nome
Definizione trasparente: equivalenza strutturale
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
54 / 88
Equivalenza per nome
Ogni nuova definizione introduce un nuovo tipo
Definizione (equivalenza per nome)
Due tipi si dicono equivalenti per nome
sse hanno lo stesso nome
un tipo è equivalente solo a se stesso
Esempio
T1
T2
T3
T4
=
=
=
=
1..10;
1..10;
int;
int;
sono tutti diversi e non equivalenti
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
55 / 88
Equivalenza per nome [. . . cont.]
Osservazioni
vincolo indebolito in alcuni linguaggi (PASCAL)
nell’es. la ridenominazione genera alias e non nuovi tipi
(caso di T3 e T4)
Ogni def. di tipo in un solo punto:
OK dal punto di vista ingegneristico
Equivalenza relativa ad un programma, non in generale
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
56 / 88
Equivalenza strutturale
Definizioni trasparenti:
nome come abbreviazione del nuovo tipo definito
conta la sostituzione dei nomi con le definizioni dei tipi
Definizione (Equivalenza strutturale)
Due tipi T1 e T2 sono strutturalmente equivalenti sse
hanno lo stesso nome,
oppure
T1 è definito con type T1 = espressione;
ed espressione rappresenta un tipo equivalente a T2,
oppure
T1 e T2 definiti applicando lo stesso costruttore di tipo a due
tipi tra loro equivalenti
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
57 / 88
Equivalenza strutturale [. . . cont.]
Esempi
(pseudo-codice)
equivalenza di T3 e T4
type
type
3 type
4 type
1
2
T1
T2
T3
T4
=
=
=
=
int;
char;
struct { T1 a; T2 b; }
struct { int a; char b; }
equivalenti?
type S = struct { int a; int b; }
type T = struct { int n; int m; }
3 type U = struct { int m; int n; }
1
2
equivalenti ? (ricorsione)
1
2
type R1 = struct { int a; R2 p; }
type R2 = struct { int a; R1 p; }
Osservazioni
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
58 / 88
Equivalenza strutturale [. . . cont.]
Equivalenza strutturale non legata al singolo programma
Sostituzione sempre possibile:
si parla di trasparenza referenziale
I linguaggi spesso adottano regole di equivalenza miste
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
59 / 88
Compatibilità
Il tipo T è compatibile con il tipo S sse
un valore del tipo T è ammesso in qualsiasi contesto in cui
sarebbe richiesto un valore di tipo S
Compatibilità più debole dell’equivalenza
Due tipi equivalenti sono sempre compatibili
(ma non viceversa)
Relazione riflessiva, transitiva ma non simmetrica
es. char e int
Relazione adottata da molti linguaggi
nella disciplina dell’assegnamento:
tra il tipo dell’espressione (RHS) e quello della variabile (LHS)
nella disciplina del passaggio parametri
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
60 / 88
Compatibilità [. . . cont.]
Gradi di compatibilità: T compatibile con S
1
T e S equivalenti
2
I valori di T costituiscono un sottoinsieme dei valori di S
es. tipi intervallo
3
Tutte le operazioni per S sono ammissibili sui valori di T
es. record e op. di selezione “.”
type S = struct {int a;}
type T = struct {int a; char b;}
rel. di sottotipo (nei linguaggi ad oggetti)
4
I valori di T corrispondono canonicamente a certi valori di S
int e float
5
I valori di T corrispondono ad alcuni valori di S,
tramite una convenzione per la trasformazione da T a S
float e int, tramite arrotondamento, troncamento, . . .
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
61 / 88
Conversione di tipo
Conversione implicita:
operata tacitamente dalla macchina astratta
si chiama anche coercizione, o conversione forzata
Conversione esplicita:
indicata mediante costrutti linguistici nel sorgente del
programma
si chiama anche cast
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
62 / 88
Coercizioni
Se T compatibile con S:
valori di tipo T sono ammessi dov’è atteso un valore di tipo S
Conversione operata dalla m. astratta (o dal compilatore)
Implementazioni
Stessa rappresentazione
livello sintattico, nulla da aggiungere
Compatibilità canonica
codice di conversione (a run-time) aggiunto dalla m. astratta
es. da int a float
Corrispondenza arbitraria
es. dominio di T sovrainsieme di quello di S
la macchina astratta inserisce codice per la conversione
(e controllo dinamico per la type safety)
es.: T è int e S è un intervallo di interi
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
63 / 88
Conversioni esplicite
Annotazioni nel linguaggio che specificano il tipo in cui
trasformare un valore di un altro tipo
S s = (S)t;
Possibilità
Indicazione sintattica
Indicazione per la macchina astratta (come prima)
Vantaggi
In genere, possibile anche quando basterebbe la
compatibilità
Maggiore leggibilità
Indipendenza dal contesto sintattico
Utili ad overloading e polimorfismo
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
64 / 88
Polimorfismo
Sistema di tipi monomorfo: ogni oggetto ha un solo tipo
Sistema di tipi polimorfo: ogni oggetto può avere più tipi
Casi di polimorfismo in molti linguaggi (anche datati)
operatore +
int x int -> int oppure float x float -> float
funzione length: non dipende dal tipo di vettore
Funzioni polimorfiche indipendenti da tipi specifici
Es. ordinamento di vettori (di interi, caratteri, ecc.)
con uso di tipi generici: void sort(<T>[] v)
Tipologie:
Polimorfismo ad hoc (overloading)
Polimorfismo universale
p. parametrico
p. di sottotipo o inclusione
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
65 / 88
Polimorfismo [. . . cont.]
Polimorfismo ad hoc: overloading
Nome sovraccaricato quando vi corrispondono più oggetti
L’informazione del contesto aiuta a decidere staticamente
es. operatore +
es. funzioni con ugual nome ma tipo e numero di parametri
differente
Polimorfismo apparente
Legato ai nomi più che agli oggetti del linguaggio
es. funzioni distinte / codice distinto
Può essere gestito con una fase di pre-processing
assegna un nome interno diverso ai nomi sovraccarichi
Overloading 6= Coercizione
es. + polimorfico
1 + 2, 1.0 + 2.0,
LdP.ITPS/[email protected]
1 + 2.0, 1.0 + 2
Strutture Dati
9 mag, 2016
66 / 88
Polimorfismo [. . . cont.]
Polimorfismo parametrico universale:
un valore può assumere tanti tipi diversi,
ottenuti per istanziazione di un unico schema universale
Codice di gestione unico
che lavora uniformemente
le differenze non contano
Istanziazione
automatica: compilatore o macchina astratta
in base al contesto
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
67 / 88
Polimorfismo [. . . cont.]
Esempi p. universale
Valore null vale per tutti i tipi puntatore (T*)
Tipo indicabile con <T>*
void sort(<T>[] v)
funzione di tipo <T>[]->void
Funzione di swap() chiamata da sort()
void swap(reference <T>, reference <T>)
e istanziazione
int * k = null;
char v,w;
3 int i,j;
4 ...
5 swap(v,w);
6 swap(i,j);
1
2
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
68 / 88
Polimorfismo [. . . cont.]
Polimorfismo parametrico universale
p. esplicito annotazioni esplicite: <T>
Template C++, Generics JAVA 5.0+
p. implicito operato dal modulo di inferenza dei tipi
Ling. di scripting
Ling. funzionali:
l’applicazione comporta istanziazione giusta
es. fun Ide(x){return x;} è di tipo <T> -> <T>
Funzioni di ordine superiore
es. fun Comp(f,g,x){return f(g(x));} di tipo
((<S> -> <T>) × (<R> -> <S>) × <R>) -> <T>
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
69 / 88
Polimorfismo [. . . cont.]
Non tutte le istanziazioni dello schema universale sono
ammissibili, quindi:
forma limitata tipica degli OOL
una forma di compatibilità strutturale
Nel p. universale di sottotipo:
un valore può assumere una molteplicità di tipi diversi,
ottenuti istanziando, in uno schema generale,
un parametro con sottotipi di un tipo assegnato
esprimibile tramite la notazione: ∀ S :< T.S -> void
dove :< indica la rel. di sottotipo
istanziabile con qualunque sottotipo S di T
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
70 / 88
Polimorfismo [. . . cont.]
Implementazione
gestione statica: a linking-time
istanziazione funzioni polimorfe (in base ai tipi)
produzione codice opportuno (più copie del template) e
collegamento
efficiente come per le funzioni non polimorfiche
es. template C++
gestione dinamica:
unica versione del codice generata
rappresentazione più complessa: invece di allocare i dati sul
RdA vengono allocati loro descrittori (dim., struttura, ind.)
più flessibile ma meno efficiente a run-time
es. in ML
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
71 / 88
Controllo di tipo
Il controllo di tipo determina e controlla la compatibilità dei tipi
degli oggetti: assegnazioni, dichiarazioni, uso parametri,
conversioni, ...
statico: modulo del compilatore (semantica statica)
segue l’albero sintattico (bottom-up)
determina e trasmette le informazioni sui tipi degli oggetti
coinvolti
dinamico: modulo di supporto al run-time
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
72 / 88
Inferenza di tipo
Inferenza: deduzione dei tipi coinvolti
in assenza di informazione esplicita
spesso sostituisce il controllo di tipo
es. in JAVASCRIPT, ML, . . .
quando non si può determinare subito il tipo
si utilizzano variabili di tipo: ’a
es. fun f(n) { return n+1; }
si può dedurre che f è di tipo int-> int
caso difficile:
fun g(v) { return v; } polimorfa
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
73 / 88
Inferenza di tipo [. . . cont.]
Algoritmo: dato l’albero di derivazione
assegnare un tipo/var. di tipo ad ogni nodo (anche variabile)
risalire l’albero imponendo vincoli (uguaglianze di tipo)
usare l’algoritmo di unificazione per risolvere i vincoli
Esempio
fun f(n) { return n+1; }
<funzione> ’a = int->int
fun
f
(
<par>
’z=int n
)
<blocco>
{ <istruzione> }
return <espr>
’x n
LdP.ITPS/[email protected]
Strutture Dati
+
; ’x = ’y = int
1 ’y
9 mag, 2016
74 / 88
Agenda
Relazioni fra tipi
4
1
Tipi e sistemi di tipi
5
2
Tipi scalari
3
Tipi Composti
LdP.ITPS/[email protected]
Strutture dati e gestione
della memoria
Dangling reference
Garbage collection
Strutture Dati
9 mag, 2016
75 / 88
Dangling reference
Esempio
1
2
int *p = malloc();
int *q = malloc();
3
4
5
*p = 123;
*q = 321;
6
7
q=p;
8
9
free(p);
10
11
LdP.ITPS/[email protected]
// q dangling reference!
Strutture Dati
9 mag, 2016
76 / 88
Dangling reference - tombstone
Si aggiunge un livello di indirizzamento indiretto, quello della
tombstone
allocazione di nuovo oggetto su heap/pila:
crea tombstone
copia tra puntatori:
copia indirizzi di tombstone
deallocazione (da heap/pila):
inserimento valore nullo speciale
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
77 / 88
Dangling reference - tombstone [. . . cont.]
q = p;
free(p);
p
123
123
q
321
321
RIP
p = malloc();
q = malloc();
*p = 123;
*q = 321;
321
Osservazioni
spazio: memoria aggiuntiva
cimitero: zona di memoria speciale per le tombstone
riuso delle tombstone (garbage collection)
tempo: doppia dereferenziazione
eventualmente + garbage collection
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
78 / 88
Dangling reference – locks & keys
lucchetto parola in memoria inizializzata con valore casuale
associata all’oggetto allocato
chiave parola in memoria corrispondente ad un lucchetto
puntatore = indirizzo + chiave
allocazione di nuovo oggetto su heap: crea lucchetto
copia tra puntatori: copia di indirizzo e chiave
dereferenziazione: controllo che la chiave del puntatore
“apra” il lucchetto (abbia lo stesso valore)
deallocazione: inserimento valore nullo speciale nel
lucchetto
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
79 / 88
Dangling reference – locks & keys [. . . cont.]
p = malloc();
q = malloc();
*p = 123;
*q = 321;
p
q = p;
free(p);
54321
123
54321
54321
123
54321
54321
0
12345
321
12345
54321
321
12345
54321
321
12345
q
Osservazioni
spazio: memoria aggiuntiva
tempo : op. più efficienti che con il tombstone
deallocazione automatica della mem. aggiuntiva
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
80 / 88
Garbage collection
Deallocazione implicita
GC: Storia dei LdP
LISP ’60 −→ JAVA ’90
Fasi (non necessariamente separate)
distinguere gli oggetti utilizzati dagli altri
per sicurezza politica conservativa
recuperare la memoria degli oggetti non utilizzati
Classificazione dei GC
contatori di riferimenti
marcatura
mark & sweep
mark & compact
copia
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
81 / 88
Garbage collection – contatori
Un contatore (reference count) per ogni oggetto;
solo per la m. astratta: inaccessibile al programmatore
allocazione: inizializza il contatore a 1
assegnazione q = p;
(o anche quando si esce da un ambiente locale con puntatori)
incremento del contatore della var. puntata da p
decremento del contatore della var. puntata da q
deallocazione: quando un contatore raggiunge il valore 0 si
può deallocare la memoria e restituirla alla lista libera
se l’oggetto da deallocare contiene puntatori
applica la procedura ricorsivamente
Osservazioni
vantaggi: semplicità e incrementalità
svantaggi: inefficienza; GC non funziona con str. circolari
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
82 / 88
Garbage collection – mark & sweep
mark
marcatura oggetti “non in uso” attraversando l’heap
a partire dai puntatori sulla pila (root set),
visita in ampiezza/profondità degli oggetti referenziati,
lungo gli archi rappresentati dai puntatori,
etichettando gli oggetti attraversati come “in uso”
sweep
deallocazione degli oggetti marcati come “non in uso”
Osservazioni (svantaggi)
non incrementale: parte quando la memoria si sta esaurendo
frammentazione esterna
inefficiente: tempo proporzionale alla dim. dell’heap
sfavorisce la località dei riferimenti in memoria
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
83 / 88
Garbage collection – pointer reversal
Per visitare agevolmente strutture concatenate (es. alberi) in fase
di deallocazione
occorre uno stack (ricorsione)
Con il rovesciamento dei puntatori
basta ricordare il nodo corrente e quello precedente
A
B
C /
F / /
B
p.prec C
D / /
corrente E / /
LdP.ITPS/[email protected]
A
stack: A B C
Strutture Dati
/
F / /
D
/
p.corr E / /
9 mag, 2016
84 / 88
Garbage collection – mark & compact
Problema della frammentazione causato dal mark & sweep
Fase di sweep =⇒ fase di compattamento
oggetti spostati in zone di mem. contigue
più passaggi necessari
Osservazioni
svantaggi
più passaggi necessari:
marcatura calcolo nuovi puntatori, spostamento, ...
vantaggi
no frammentazione
località dei riferimenti
lista libera monoblocco
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
85 / 88
Garbage collection – copia
No fase marcatura: copia (e compattazione) dei blocchi vivi
GC stop & copy: heap diviso in 2 semispazi (FromSpace,ToSpace)
normalmente solo 1 in uso (FromSpace);
memoria libera = unico blocco
memoria esaurita: chiamata al GC
a partire dal root set si copia (alg. di Cheney) nell’altro
semispazio (toSpace), compattando
quindi ToSpace e FromSpace si scambiano i ruoli
Osservazioni
vantaggi
allocazione efficiente: soprattutto se è noto il fabbisogno degli
oggetti vivi contemporaneamente
no frammentazione
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
86 / 88
ToSpace
FromSpace
Garbage collection – copia [. . . cont.]
root set
ToSpace
FromSpace
root set
libera
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
87 / 88
Riferimenti
Gabbrielli & Martini: Linguaggi di Programmazione,
McGraw-Hill. 2a edizione. Cap. 10
LdP.ITPS/[email protected]
Strutture Dati
9 mag, 2016
88 / 88