G. Mecca – Università della Basilicata – mecca@unibas.it
Programmazione Procedurale in Linguaggio C++
Tipi Strutturati Parte 4 Record
versione 2.1
Questo lavoro è concesso in uso secondo i termini di una licenza Creative Commons (vedi ultima pagina)
Sommario
m
Introduzione
m
Dichiarazione di Record (o “Strutture”)
ðDescrizione del ModelloðSintassi e Semantica
m
Utilizzo dei Record (o “Strutture”)
ðSintassi e Semanticam
Nidificazione
ðNidificazione e Passaggio dei Parametri
Tipi Strutturati: Record >> Sommario
G. Mecca - Programmazione Procedurale in Linguaggio C++ 3
Introduzione
m
Record (o “Strutture”)
ðfunzionalità dei linguaggi di programmazione che consente di rappresentare in un prg.
oggetti attraverso varie componenti (variabili)
m
Differenze nell’uso
ðun array serve a rappresentare una collezione di dati tutti dello stesso tipo ðun record serve a rappresentare un unico
dato con struttura “complessa”
Tipi Strutturati: Record >> Introduzione
Introduzione
m
Differenze con gli array
ðin un record, le componenti possono non essere dello stesso tipo
ðogni componente ha un nome (identificatore) e non un indice intero
ðgli array sono una funzionalità essenziale dei linguaggi di programmazione procedurali ði record non sono essenziali (in alcuni
linguaggi, es: FORTRAN 77, non esistono)
Tipi Strutturati: Record >> Introduzione
G. Mecca - Programmazione Procedurale in Linguaggio C++ 5
Introduzione
m
Principale utilità dei record
ðsemplificazione del codice (dichiarazione di meno variabili, minor numero di parametri) ðmaggiore leggibilità del codice (le variabili
che rappresentano un oggetto sono raggruppate e quindi meglio identificabili)
m
Un esempio: equazioni di II grado
ðun’equazione di II grado richiede 3 numeri
Tipi Strutturati: Record >> Introduzione
>> equazioni4Lib.h
>> equazioni4Lib.cpp
>> equazioni4.cpp
Dichiarazione di Record
m
Processo a due passi
ðI passo: descrivo il “modello” del record che voglio utilizzare
ðII passo: utilizzo il modello come nuovo tipo di dato per dichiarare variabili
m
Modello del record
ðdescrizione della struttura del record
ðpuò essere utilizzato dovunque sia previsto un tipo di dato in aggiunta a quelli di base
Tipi Strutturati: Record >> Dichiarazione di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 7
Dichiarazione di Record: Esempi
struct equazione { float a, b, c;
};
equazione eq1, eq2;
struct partita {
string squadraCasa, squadraTrasferta;
int golCasa, golTrasferta;
char segno;
};
partita partite[N];
Tipi Strutturati: Record >> Dichiarazione di Record
descrizione del modello di record dichiarazione di 2 variabili secondo il modello
descrizione del modello di record dichiarazione di un array di variabili secondo il modello
Descrizione del Modello di Record
m
Sintassi
struct <nome> {<elencoAttributi>};
m
Dove
ð<nome> è un identificatore
ð<elencoAttributi> è l’elenco delle componenti del record, detti “attributi” (o “campi”)
ðuna lista di dichiarazioni del genere
<tipoAttributo> <nomeAttributo>;
Tipi Strutturati: Record >> Dichiarazione di Record
ATTENZIONE:
errore frequente
G. Mecca - Programmazione Procedurale in Linguaggio C++ 9
Descrizione del Modello di Record
m
Semantica
ðla descrizione del modello diventa un nuovo identificatore di tipo
ðsi aggiunge ai tipi di base (int, float, char, ecc.) e ai tipi predefiniti (string, ofstream ecc.)
m
Di conseguenza
ðpuò essere utilizzato per dichiarare variabili, costanti e parametri
Tipi Strutturati: Record >> Dichiarazione di Record
Dichiarazione delle Variabili
m
Sintassi ordinaria
<nomeModello> <nomeVar>;
m
Semantica
ðha l’effetto di dichiarare un numero di variabili pari agli attributi del modello ðpiù una variabile per il record nel suo
complesso
ðnome delle variabili costituito da due parti ðovvero: <nomeVar>.<nomeAttributo>
Tipi Strutturati: Record >> Dichiarazione di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 11
Dichiarazione delle Variabili
m Esempio
Tipi Strutturati: Record >> Dichiarazione di Record
struct equazione { float a, b, c;
};
equazione eq1, eq2;
eq2.a xxx
#103
eq2.b xxx
#104 eq2
eq2.c xxx
#105
xxx
#106
xxx
#99
eq1 eq1.c xxx
#102
eq1.b xxx
#101
eq1.a xxx
#100
in totale: 8 variabili
Dichiarazione di Record
m
Attenzione
ðin questo caso avrei potuto anche dichiarare due array (componenti dello stesso tipo)
m
Esempio
ðfloat eq1[3], eq2[3];
ða quale coefficiente corrisponde eq1[0] ? (a, b o c) ða quale coefficiente corrisponde eq1[1] ? (a, b o c) ða quale coefficiente corrisponde eq1[2] ? (a, b o c)
m E’ una soluzione metodologicam. inappropriata
Tipi Strutturati: Record >> Dichiarazione di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 13
Dichiarazione delle Variabili
m Esempio
Tipi Strutturati: Record >> Dichiarazione di Record
struct partita { string squadraCasa;
string squadraTrasferta;
int goalCasa;
int goalTrasferta;
char segno;
};
partita p;
xxx
#105
xxx
#99
p
p.segno xxx
#104
p.goalTrasferta xxx
#103
p.goalCasa xxx
#102
p.squadraTrasferta xxx
#101
p.squadraCasa xxx
#100
in totale: 6 variabili
Dichiarazione delle Variabili
Tipi Strutturati: Record >> Dichiarazione di Record
m
Un’annotazione importante
ðdifferenza fondamentale tra descrizione del modello e dichiarazione (di var. o param.) ðla descrizione del modello NON produce
effetti sulla memoria, la dichiarazione sì
ðla descrizione del modello ha solo l’effetto di rendere il modello un nuovo tipo di dato
m
ATTENZIONE: Errore frequente
ðla descrizione del modello deve finire con ;
G. Mecca - Programmazione Procedurale in Linguaggio C++ 15
Dichiarazione delle Variabili
Tipi Strutturati: Record >> Dichiarazione di Record
m
Inizializzazione
ðanche in questo caso è possibile inizializzare gli attributi alla dichiarazione
m
Sintassi
ð<modello> <nomeVar> = {<listaValori>};
m
Dove
ð<listaValori> è un elenco di valori di tipo opportuno, uno per ogni attributo del record, separati da virgole
Dichiarazione delle Variabili
Tipi Strutturati: Record >> Dichiarazione di Record
m
Esempio
equazione eq = {5, 2, 5};
partita p = {“Juventus”, “Inter”, 4, 0,
‘1’};
G. Mecca - Programmazione Procedurale in Linguaggio C++ 17
Utilizzo dei Record
m
Regola generale
ðcome gli array, di norma le operazioni sui record si effettuano attributo per attributo ðovvero lavorando singolarmente sulle
variabili che rappresentano gli attributi
m
Alcune eccezioni
ðistruzioni di assegnazione ðutilizzo nei sottoprogrammi
Tipi Strutturati: Record >> Utilizzo di Record
Utilizzo dei Record
m
Istruzioni di assegnazione
ðattributo per attributoðoppure tutto in una volta
m
Esempio
struct equazione { float a, b, c; };
void main() {
equazione eq1 = {5, 2, 5};
equazione eq2;
eq2 = eq1;
}
Tipi Strutturati: Record >> Utilizzo di Record
equivalente a:
eq2.a = eq1.a;
eq2.b = eq1.b;
eq2.c = eq1.c;
G. Mecca - Programmazione Procedurale in Linguaggio C++ 19
Utilizzo dei Record
m
Passaggio dei parametri
ðla variabile che rappresenta il record nel suo complesso può essere usata come
argomento per i sottoprogrammi
m
Parametro di tipo record
ðtanti parametri, uno per ciascun attributo
m
Differenza con gli array
ðpassaggio dei parametri avviene in modo ordinario, sia per valore che per riferimento
Tipi Strutturati: Record >> Utilizzo di Record
Utilizzo dei Record
m
Passaggio dei parametri standard
ðnello spazio di memoria del parametro viene copiato il valore del record argomento,
attributo per attributo
m
Passaggio dei parametri per riferimento
ðnello spazio di memoria del parametro vienecopiato l’indirizzo del primo registro del record utilizzato come argomento
Tipi Strutturati: Record >> Utilizzo di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 21
Esempio: Equazioni
void leggiDatiEquazione (equazione &eq) {
cout << "Inserisci i coefficienti dell'equazione \n";
cin >> eq.a;
cin >> eq.b;
cin >> eq.c;
return;
}
void stampaDatiEquazione (equazione eq) {
cout << "--- Equazione ---\n";
cout << eq.a << "x2+"<< eq.b <<"x+" << eq.c << "=0 \n";
return;
}
float discriminante (equazione eq) { return eq.b*eq.b-4*eq.a*eq.c;
}
Tipi Strutturati: Record >> Utilizzo di Record
parametro per riferimento
parametri standard
Esempio: Equazioni
Tipi Strutturati: Record >> Utilizzo di Record
eq2.a xxx
#103
eq2.b xxx eq2
#104
eq2.c xxx
#105
#106
#99 xxx
eq1 eq1.c xxx
#102
eq1.b xxx
#101
eq1.a xxx
#100 void leggiDatiEquazione
(equazione &eq) { cout << "Inserisci coeff.";
cin >> eq.a;
cin >> eq.b;
cin >> eq.c;
return;
}
void main() {
equazione eq1, eq2;
...
leggiDatiEquazione(eq1);
leggiDatiEquazione(eq2);
if (discriminante(eq1)>=0 &&
discriminante(eq2)>=0) { ...
}
eq #100
2 5 2
G. Mecca - Programmazione Procedurale in Linguaggio C++ 23
Esempio: Equazioni
Tipi Strutturati: Record >> Utilizzo di Record
xxx
#108
xxx
#107
xxx
#106
1 eq2.a
#103
2 eq2.b eq2
#104
1 eq2.c
#105
#99 xxx
eq1
2 eq1.c
#102
5 eq1.b
#101
2 eq1.a
#100 float discriminante
(equazione eq) { return eq.b*eq.b-4*eq.a*eq.c;
}
void main() {
equazione eq1, eq2;
...
leggiDatiEquazione(eq1);
leggiDatiEquazione(eq2);
if (discriminante(eq1)>=0 &&
discriminante(eq2)>=0) { ...
}
2 eq
eq.a eq.b eq.c
5 2
Utilizzo dei Record
m
Risultato delle funzioni
ðle funzioni possono restituire come risultato dei record (ulteriore differenza con gli array)
m
Esempio: calcolo delle radici reali
struct radiciReali { float x, y; };
radiciReali calcolaRadici (equazione eq) { radiciReali rr;
rr.x=(-eq.b+sqrt(discriminante(eq)))/(2*eq.a);
rr.y=(-eq.b-sqrt(discriminante(eq)))/(2*eq.a);
return rr;
Tipi Strutturati: Record >> Utilizzo di Record
NOTA: una funzione del genere può essere usata solo in una assegnazione del tipo:
radiciReali radici1;
radici1 = calcolaRadici(eq1)
G. Mecca - Programmazione Procedurale in Linguaggio C++ 25
Utilizzo dei Record
m
Per il resto
ðle operazioni sui record (lettura, stampa ecc.) vengono fatte attributo per attributo
m
Differenza rispetto agli array
ðnel caso degli array, è possibile utilizzare cicli per rendere più compatto il codice ðnel caso dei record questo vantaggio non
esiste; le istruzioni devono essere scritte per ciascun attributo separatamente
Tipi Strutturati: Record >> Utilizzo di Record
Utilizzo di Record
m
Record e array
ði record possono essere combinati con gli array per rappresentare collezioni di dati con struttura complessa
m
Esempio: Partite di Serie A
ðdati i risultati di una giornata di serie A, calcolare e stampare i segni in schedina ðun array di 9 partite
Tipi Strutturati: Record >> Utilizzo di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 27
Esempio: Partite di Serie A
Tipi Strutturati: Record >> Dichiarazione di Record
const int N=9;
struct partita { string squadraCasa;
string squadraTrasf;
int goalCasa;
int goalTrasferta;
char segno;
};
partita partite[N];
xxx ...
xxx partite[8].squadraCasa
#140
xxx partite[8].squadraTrasf
#141
xxx partite[8].goalCasa
partite[8]
#142
xxx partite[8].goalTrasferta
#143
xxx partite[8].segno
#144 ... xxx
#145 partite #100
#99
partite[0]
xxx partite[0].segno
#104
xxx partite[0].goalTrasferta
#103
xxx partite[0].goalCasa
#102
xxx partite[0].squadraTrasf
#101
xxx partite[0].squadraCasa
#100
in totale: 55 variabili -1 array
-9 componenti
-5 attributi per componente
Esempio: Partite di Serie A
m
Nota
ðla definizione del modello di record “partita”, così come la costante N, devono essere dichiarati a livello di file
ðvisibilità globale, perché vengono usati sostanzialmente in tutti i moduli del programma
ðquesto non contravviene all’indicazione di non usare variabili globali, visto che non si
Tipi Strutturati: Record >> Utilizzo di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 29
Esempio: Partite di Serie A
struct partita {
string squadraCasa, squadraTrasferta;
int goalCasa, goalTrasferta;
char segno;
};
const int N=9;
void leggiPartite(partita partite[N]);
void stampaPartite(partita partite[N]);
void calcolaSegni(partita partite[N]);
void main() {
partita partite[N];
leggiPartite(partite);
calcolaSegni(partite);
stampaPartite(partite);
}
Tipi Strutturati: Record >> Utilizzo di Record
Esempio: Partite di Serie A
void leggiPartite(partita partite[N]){
int i;
for (i=0; i<N; i++) {
leggiPartita(partite[i]);
} return;
}
void leggiPartita(partita &p){
cout << "Squadra in casa : ";
getline(cin, p.squadraCasa);
cout << "Squadra in trasferta : ";
getline(cin, p.squadraTrasferta);
cout << "Goal squadra in casa : ";
cin >> p.goalCasa;
cout << "Goal squadra in trasferta: ";
cin >> p.goalTrasferta;
cin.ignore();
return;
}
Tipi Strutturati: Record >> Utilizzo di Record
necessaria per rimuovere il carattere \n dal flusso prima della lettura della
ha l’effetto di chiamare N volte la procedura leggiPartita
i=0 – leggiPartita(partite[0]) i=1 – leggiPartita(partite[1]) ...
G. Mecca - Programmazione Procedurale in Linguaggio C++ 31
Esempio: Partite
Tipi Strutturati: Record >> Dichiarazione di Record
void leggiPartita(partita &p){
getline(cin, p.squadraCasa);
...
}
void leggiPartite
(partita partite[N]){
int i;
for (i=0; i<N; i++) {
leggiPartita(partite[i]);
} return;
}
void main() {
partita partite[N];
leggiPartite(partite);
...
}
xxx
#147
xxx
#146 ... ...
...
xxx partite[8].squadraCasa
#140
...
...
partite[8]
...
xxx partite[8].segno
#144
xxx
#145
#100 partite
#99
partite[0]
xxx partite[0].segno
#104
xxx partite[0].goalTrasferta
#103
xxx partite[0].goalCasa
#102
xxx partite[0].squadraTrasf
#101
xxx partite[0].squadraCasa
#100
partite i
#100 0
p #100
1
#105 Juve Inter 0 0
Esempio: Partite di Serie A
void calcolaSegni(partita partite[N]){
int i;
for (i=0; i<N; i++) {
if (partite[i].goalCasa > partite[i].goalTrasferta) { partite[i].segno='1';
} else {
if (partite[i].goalCasa<partite[i].goalTrasferta) { partite[i].segno='2';
} else {
partite[i].segno='X';
} } return;
}
Tipi Strutturati: Record >> Utilizzo di Record
G. Mecca - Programmazione Procedurale in Linguaggio C++ 33
Esempio: Partite di Serie A
void stampaPartite(partita partite[N]){
int i;
for (i=0; i<N; i++) {
stampaPartita(partite[i]);
}
return;
}
void stampaPartita(partita p){
cout << p.squadraCasa << "-“
<< p.squadraTrasferta << " \t";
cout << p.goalCasa << "-"
<< p.goalTrasferta << " \t"
<< p.segno << endl;
return;
}
Tipi Strutturati: Record >> Utilizzo di Record
ha l’effetto di chiamare N volte la procedura stampaPartita
i=0 – stampaPartita(partite[0]) i=1 – stampaPartita(partite[1]) ...
Esempio: Partite
Tipi Strutturati: Record >> Dichiarazione di Record
void stampaPartita(partita p){
...
}
void stampaPartite
(partita partite[N]){
int i;
for (i=0; i<N; i++) {
stampaPartita(partite[i]);
} return;
}
void main() {
partita partite[N];
...
stampaPartite(partite);
}
xxx
#150
xxx
#149
xxx
#148
xxx
#147
xxx
#146 ... ...
...
xxx partite[8].squadraCasa
#140
...
...
partite[8]
...
xxx partite[8].segno
#144
xxx
#145
#100 partite
#99
partite[0]
X partite[0].segno
#104
0 partite[0].goalTrasferta
#103
0 partite[0].goalCasa
#102
Inter partite[0].squadraTrasf
#101
Juve partite[0].squadraCasa
#100
partite i
#100
p
Juve Inter 0 0 p.squadraCasa p.squadraTrasf p.goalCasa p.goalTrasferta
0
G. Mecca - Programmazione Procedurale in Linguaggio C++ 35
Nidificazione
m
Due categorie di tipi di dato
ðtipi di base (int, float, double, char, bool) e assimilati (string, ifstream, ofstream)
ðtipi “strutturati”
m
Tipi strutturati
ðcostruiti utilizzando array e record
ðarray e record possono essere liberamente nidificati
Tipi Strutturati: Record >> Nidificazione
Nidificazione
m
Un esempio
ðsovrapposizione di rettangoli
m
Rettangolo
ðoggetto rappresentato da due punti nel piano cartesiano
m
Punto
ðoggetto rappresentato da due coordinate reali nel piano cartesiano
Tipi Strutturati: Record >> Nidificazione
G. Mecca - Programmazione Procedurale in Linguaggio C++ 37
Esempio: Sovrapp. di Rettangoli
struct punto { float x, y;
};
struct rettangolo { punto v1, v2;
};
rettangolo r1, r2;
Tipi Strutturati: Record >> Nidificazione
r2.v2 r2.v1 r1.v2 r1.v1
r2.v2.x xxx
#106
r1.v2.x xxx
#102
r2.v1.x xxx
#104
r2.v1.y xxx r2
#105
r2.v2.y xxx
#107
xxx
#108
xxx
#99
r1
r1.v2.y xxx
#103
r1.v1.y xxx
#101
r1.v1.x xxx
#100
record che contiene al suo interno due record
>> rettangoli2.cpp
Nidificazione
m
Nidificazioni profonde
ðsono possibili array e record che al loro interno contengono altri record ed altri array ðutile ad esempio per rappresentare collezioni
(array) di oggetti (record) i quali contengono al loro interno ulteriori oggetti (record) o collezioni (array) di valori
ðin questo caso l’unica attenzione da prestare è al meccanismo dei nomi delle variabili
Tipi Strutturati: Record >> Nidificazione
G. Mecca - Programmazione Procedurale in Linguaggio C++ 39
Nidificazione
m
In particolare
ðper i nomi delle componenti degli array: [ ] ðper i nomi degli attributi dei record: .
m
Esempio
ðpartite del campionato di serie A ðcon risultato
ðsquadre complete di formazioni ðdata della partita
Tipi Strutturati: Record >> Nidificazione
Nidificazione
struct giocatore { string nome;
int maglia;
};
struct squadra { string nome;
giocatore formazione[11];
};
struct data {
int giorno, mese, anno;
};
struct partita { squadra sq1, sq2;
int goal1, goal2;
data d;
};
Tipi Strutturati: Record >> Nidificazione
G. Mecca - Programmazione Procedurale in Linguaggio C++ 41 Tipi Strutturati: Record >> Nidificazione
...
...
#28
“Lazio”
p[1].sq1.nome p[1].sq1
p[1]
#27
2003 p[0].data.anno
#26
1 p[0].data.mese
p[0].data
#25
11 p[0].data.giorno
#24
0 p[0].goal2
#23
4 p[0].goal1
#22
p[0].sq2.formazione[10].maglia p[0].sq2.formazione[10].nome ...
p[0].sq2.formazione[0].maglia p[0].sq2.formazione[0].nome p[0].sq1.formazione[10].maglia p[0].sq1.formazione[10].nome ...
p[0].sq1.formazione[0].maglia p[0].sq1.formazione[0].nome
20
#21
“Recoba”
p[0].sq2.formazione[10]
#20
...
...
#19
1 p[0].sq2
p[0]
#18
“Toldo”
p[0].sq2.formazione[0]
#17
“Inter”
p[0].sq2.nome
#16
“Juventus”
p[0].sq1.nome
#10
...
...
#13
11
#15
“Nedved”
p[0].sq1.formazione[10]
#14
1 p[0].sq1
#12
“Buffon”
p[0].sq1.formazione[0]
#11
Nidificazione e Passaggio dei Param.
m
Attenzione
ðin questi casi NON conviene passare i dati per valore: la copia richiederebbe tempo
m
Nel caso degli array
ðil passaggio avviene comunque per riferimento
m
Nel caso dei record
ðpossono esserci problemi
Tipi Strutturati: Record >> Nidificazione
G. Mecca - Programmazione Procedurale in Linguaggio C++ 43
Nidificazione e Passaggio dei Param.
m Esempio: squadra
ðla variabile s non dovrebbe mai essere passata per valore ðper evitare che venga
effettuata la copia di tutte le componenti dell’array
Tipi Strutturati: Record >> Nidificazione
struct squadra { string nome;
string giocatori[30];
};
void main() { squadra s;
leggi (s);
stampa (s);
...
}
void leggi(squadra &s);
void stampa (squadra &s);
Nidificazione e Passaggio dei Param.
m
NOTA
ðquesto vale solo nel caso di record che contengono array
ðe solo se gli array hanno un numero alto di componenti
ðin tutti gli altri casi bisogna scegliere il tipo di parametro più appropriato (standard o per riferimento)
Tipi Strutturati: Record >> Nidificazione
G. Mecca - Programmazione Procedurale in Linguaggio C++ 45
Riassumendo
m Record
ðdichiarare oggetti con struttura complessa
m Dichiarazione
ðdescrizione del modello (ATTENZIONE) ðdichiarazione delle variabili
m Utilizzo
ði vantaggi principali: dichiarazioni e parametri
m Nidificazione profonda
ðPassaggio dei Parametri
Tipi Strutturati: Record >> Sommario
Termini 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.