Fondamenti di informatica
Strutture dati composte: struct
Il sistema dei tipi del C++
• Uno degli obiettivi principali del C++ è
permettere al programmatore di creare tipi
personalizzati e usarli come se fossero offerti
dal linguaggio
• Il sistema dei tipi del C++ comprende
– Tipi predefiniti (predefined)
– Tipi composti (composite)
– Tipi definiti dall’utente (user defined)
– Tipi classe (class types)
I costruttori di tipi
• A partire dai tipi predefiniti si possono creare
nuovi tipi, che aggiungono proprietà speciali ai
tipi predefiniti
– Const (visto)
– Reference (visto)
– Pointer (ancora da vedere)

• A questi si aggiungono costruttori di tipi definiti
interamente dall'utente
– struct (eredità del C, poco usato in C++)
– Class
Tipi composti aggregati
• Variabili omogenee: sequenza finita /
indefinita
– ARRAY (sequenza predefinita), VECTOR (sequenza
indefinita)

• Variabili disomogenee: tipi classe
– STRUCT (record)
– CLASS (oggetti con dati e funzioni dichiarati e
definiti assieme)
4
Esigenza
• Nella progettazione dei dati, spesso capita di
prevedere informazioni connesse in gruppi logici:
– Parole in un testo e loro frequenza
– Indirizzo, composto da via n. civico città
– Dati dell'utente: username, password, email

• In questi casi, piuttosto che variabili separate, si
usa un costruttore di tipo che definisce un gruppo
logico di variabili correlate, detto "record"
(ovvero: scheda, registrazione)
Il costruttore di tipo record
• Record (o struct): memorizzano aggregazioni di
dati di diversa natura
• Ciascun dato è chiamato “campo” o dato membro
(member):
struct {
string via;
int numero;
int CAP;
string citta;
} indirizzo;

//
//
//
//

1o
2o
3o
4o

campo:
campo:
campo:
campo:

stringa
intero
intero
stringa

nome della variabile record

• indirizzo è un record formato da quattro
campi di vario tipo
Uso dei record
• Il record (o struct) è una sorta di “contenitore” di campi
di tipo disomogeneo
• Il record raggruppa dati più semplici
– Ne rende più ordinata la gestione, evitando confusioni

• I campi del record non sono accessibili individualmente
– L'accesso avviene mediante il record a cui appartengono
– Si utilizza l'operatore . come metodo di accesso ai campi
• indirizzo.citta

– Con gli iterator si usa l'operatore -> : iter->member
– I nomi dei campi sono identificatori “locali” all’interno di
una variabile di tipo record, da usarsi come suffissi
Operazioni su campi dei record
• Le operazioni che sono definite sono le stesse
applicabili sui tipi dei campi
• Assegnamento ai campi del record:
indirizzo.via = "Ponzio";
indirizzo.numero  34;
indirizzo.CAP  20133;
indirizzo.citta = "Milano";

• Accesso (leggere, scrivere…):
– cout << indirizzo.numero;
– cin >> indirizzo.CAP;
Assegnamento di record
• Dati due record identici (cioè dichiarati insieme) è lecito
assegnare globalmente il primo al secondo
struct  … / campi /  rec1, rec2;
•
è lecito scrivere:
rec2  rec1;
• tutti i campi di rec1 sono ordinatamente copiati nei campi
corrispondenti di rec2.
• Se i due record sono diversi (anche solo per l’ordine dei
campi) l’assegnamento è privo di senso !
• Memento: l’assegnamento “diretto” tra array è vietato
– deve avvenire elemento per elemento

• Ma…. Diventa possibile tra membri array di una struct!
Assegnamento di array nelle struct
int main() {
struct {
char via[20];
int numero;
int CAP;
string citta;
} indirizzo1, indirizzo2;
strcpy(indirizzo1.via, "Ponzio"); // non si può usare assegnamento
indirizzo1.numero = 35;
indirizzo1.CAP = 20133;
indirizzo1.citta = "Milano";
cout << "RECORD 1: " << endl << indirizzo1.via << endl << indirizzo1.numero
<< endl << indirizzo1.CAP << endl << indirizzo1.citta << endl;
indirizzo2 = indirizzo1; // copia anche l'array!!
cout << "RECORD 2: " << endl << indirizzo2.via << endl << indirizzo2.numero
<< endl << indirizzo2.CAP << endl << indirizzo2.citta << endl;
return 0;
}
Check this out
• http://stackoverflow.com/questions/8939090/
why-array-assignment-operation-doesnt-existbut-structure-assignment-does-in-c
Tipi definiti dall’utente
Tipi di dato astratti (TDA)

12
Tipi definiti dall'utente
• I record sono un caso esemplare in cui un tipo ha una
struttura definita dal programmatore
• Tuttavia è un tipo "anonimo"
• C e C++ forniscono un modo per dare un nome a un tipo
• Esempio:
• typedef int intero;
• intero numero;

•

è equivalente a:
• int numero;

• È la definizione di un sinonimo
– Il nuovo tipo intero eredita le caratteristiche (valori e
operazioni) del tipo di partenza int
Costruttore di record (struct)
•

•
•

Definizione di un tipo tipo data per le date:
typedef struct {
int giorno;
int mese;
int anno;
} data;
Dichiarazione di variabili di tipo data:
data oggi, domani, dopodomani;
Altro esempio:
typedef struct {
char nome[20];
char cognome[20];
data nato_il;
char nato_a[15];
char codice_fiscale[16];
int stipendio;
} dipendente;
dipendente piero;
Esempi d'uso
• Si possono dichiarare le variabili:
dipendente persona1, persona2;

• E modificare i dati membro:
persona1.stipendio + (persona1.stipendio  10)  100;
persona2.stipendio + (persona2.stipendio  10)  100;

• Anche innestati:
persona2.nato_il.giorno = 15; // NB: accede a campo
giorno del campo data di dipendente
Progettazione dei dati
• Esempio vendite di libri
– Si vuole costruire un programma che gestisca le vendite di
libri
• Ogni libro è caratterizzato da un codice ISBN

– Il programma deve gestire per ogni libro il numero totale di
copie vendute, il ricavo totale e medio
– L'utente inserisce sequenzialmente i dati di vendita per i
diversi libri, il programma aggrega i dati per ciascun codice
ISBN e stampa il dato aggregato
– Deve quindi essere possibile:
• Inserire e stampare i dati di un libro
• Sommare più dati di vendita relativi allo stesso libro
• Stampare i dati di vendita aggregati relativi a un libro
Suddivisione del programma
• Un file di libreria (Sales_item.h) conterrà la
definizione del tipo che rappresenta il dato di
vendita: Sales_item
• Definiamo ora Sales_item come struct, cioè un
tipo definito dall'utente che comprende dati, ma
non le operazioni relativi al dato di vendita
– Campi: codice ISBN, copie vendute, ricavo

• Il programma principale importa e usa Sales_item
come se fosse un tipo predefinito
– Sales_item item; // dichiara una var. di tipo Sales_item !
Sales_item.h
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
using namespace std;

struct Sales_data {
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
#endif
Programma principale
#include <iostream>
#include <string>
#include "Sales_data.h"
using namespace std;
int main()
{

Sales_data data1, data2;
// code to read into data1 and data2
double price = 0; // price per book, used to calculate total revenue
// read the first transactions: ISBN, number of books sold, price per book
cin >> data1.bookNo >> data1.units_sold >> price;
// calculate total revenue from price and units_sold
data1.revenue = data1.units_sold * price;
// read the second transaction
cin >> data2.bookNo >> data2.units_sold >> price;
data2.revenue = data2.units_sold * price;
// check whether data1 and data2 have the same ISBN, if so print the sum of data1 and data2
if (data1.bookNo == data2.bookNo) {
unsigned totalCnt = data1.units_sold + data2.units_sold;
double totalRevenue = data1.revenue + data2.revenue;
// print: ISBN, total sold, total revenue, average price per book
cout << data1.bookNo << " " << totalCnt << " " << totalRevenue << " ";
if (totalCnt != 0)
cout << totalRevenue/totalCnt << endl;
else
cout << "(no sales)" << endl;

} else {

}
}

return 0; // indicate success
cerr << "Data must refer to the same ISBN"
return -1; // indicate failure

<< endl; // transactions not for same ISBN

06 3 struct

  • 1.
  • 2.
    Il sistema deitipi del C++ • Uno degli obiettivi principali del C++ è permettere al programmatore di creare tipi personalizzati e usarli come se fossero offerti dal linguaggio • Il sistema dei tipi del C++ comprende – Tipi predefiniti (predefined) – Tipi composti (composite) – Tipi definiti dall’utente (user defined) – Tipi classe (class types)
  • 3.
    I costruttori ditipi • A partire dai tipi predefiniti si possono creare nuovi tipi, che aggiungono proprietà speciali ai tipi predefiniti – Const (visto) – Reference (visto) – Pointer (ancora da vedere) • A questi si aggiungono costruttori di tipi definiti interamente dall'utente – struct (eredità del C, poco usato in C++) – Class
  • 4.
    Tipi composti aggregati •Variabili omogenee: sequenza finita / indefinita – ARRAY (sequenza predefinita), VECTOR (sequenza indefinita) • Variabili disomogenee: tipi classe – STRUCT (record) – CLASS (oggetti con dati e funzioni dichiarati e definiti assieme) 4
  • 5.
    Esigenza • Nella progettazionedei dati, spesso capita di prevedere informazioni connesse in gruppi logici: – Parole in un testo e loro frequenza – Indirizzo, composto da via n. civico città – Dati dell'utente: username, password, email • In questi casi, piuttosto che variabili separate, si usa un costruttore di tipo che definisce un gruppo logico di variabili correlate, detto "record" (ovvero: scheda, registrazione)
  • 6.
    Il costruttore ditipo record • Record (o struct): memorizzano aggregazioni di dati di diversa natura • Ciascun dato è chiamato “campo” o dato membro (member): struct { string via; int numero; int CAP; string citta; } indirizzo; // // // // 1o 2o 3o 4o campo: campo: campo: campo: stringa intero intero stringa nome della variabile record • indirizzo è un record formato da quattro campi di vario tipo
  • 7.
    Uso dei record •Il record (o struct) è una sorta di “contenitore” di campi di tipo disomogeneo • Il record raggruppa dati più semplici – Ne rende più ordinata la gestione, evitando confusioni • I campi del record non sono accessibili individualmente – L'accesso avviene mediante il record a cui appartengono – Si utilizza l'operatore . come metodo di accesso ai campi • indirizzo.citta – Con gli iterator si usa l'operatore -> : iter->member – I nomi dei campi sono identificatori “locali” all’interno di una variabile di tipo record, da usarsi come suffissi
  • 8.
    Operazioni su campidei record • Le operazioni che sono definite sono le stesse applicabili sui tipi dei campi • Assegnamento ai campi del record: indirizzo.via = "Ponzio"; indirizzo.numero  34; indirizzo.CAP  20133; indirizzo.citta = "Milano"; • Accesso (leggere, scrivere…): – cout << indirizzo.numero; – cin >> indirizzo.CAP;
  • 9.
    Assegnamento di record •Dati due record identici (cioè dichiarati insieme) è lecito assegnare globalmente il primo al secondo struct  … / campi /  rec1, rec2; • è lecito scrivere: rec2  rec1; • tutti i campi di rec1 sono ordinatamente copiati nei campi corrispondenti di rec2. • Se i due record sono diversi (anche solo per l’ordine dei campi) l’assegnamento è privo di senso ! • Memento: l’assegnamento “diretto” tra array è vietato – deve avvenire elemento per elemento • Ma…. Diventa possibile tra membri array di una struct!
  • 10.
    Assegnamento di arraynelle struct int main() { struct { char via[20]; int numero; int CAP; string citta; } indirizzo1, indirizzo2; strcpy(indirizzo1.via, "Ponzio"); // non si può usare assegnamento indirizzo1.numero = 35; indirizzo1.CAP = 20133; indirizzo1.citta = "Milano"; cout << "RECORD 1: " << endl << indirizzo1.via << endl << indirizzo1.numero << endl << indirizzo1.CAP << endl << indirizzo1.citta << endl; indirizzo2 = indirizzo1; // copia anche l'array!! cout << "RECORD 2: " << endl << indirizzo2.via << endl << indirizzo2.numero << endl << indirizzo2.CAP << endl << indirizzo2.citta << endl; return 0; }
  • 11.
    Check this out •http://stackoverflow.com/questions/8939090/ why-array-assignment-operation-doesnt-existbut-structure-assignment-does-in-c
  • 12.
    Tipi definiti dall’utente Tipidi dato astratti (TDA) 12
  • 13.
    Tipi definiti dall'utente •I record sono un caso esemplare in cui un tipo ha una struttura definita dal programmatore • Tuttavia è un tipo "anonimo" • C e C++ forniscono un modo per dare un nome a un tipo • Esempio: • typedef int intero; • intero numero; • è equivalente a: • int numero; • È la definizione di un sinonimo – Il nuovo tipo intero eredita le caratteristiche (valori e operazioni) del tipo di partenza int
  • 14.
    Costruttore di record(struct) • • • Definizione di un tipo tipo data per le date: typedef struct { int giorno; int mese; int anno; } data; Dichiarazione di variabili di tipo data: data oggi, domani, dopodomani; Altro esempio: typedef struct { char nome[20]; char cognome[20]; data nato_il; char nato_a[15]; char codice_fiscale[16]; int stipendio; } dipendente; dipendente piero;
  • 15.
    Esempi d'uso • Sipossono dichiarare le variabili: dipendente persona1, persona2; • E modificare i dati membro: persona1.stipendio + (persona1.stipendio  10)  100; persona2.stipendio + (persona2.stipendio  10)  100; • Anche innestati: persona2.nato_il.giorno = 15; // NB: accede a campo giorno del campo data di dipendente
  • 16.
    Progettazione dei dati •Esempio vendite di libri – Si vuole costruire un programma che gestisca le vendite di libri • Ogni libro è caratterizzato da un codice ISBN – Il programma deve gestire per ogni libro il numero totale di copie vendute, il ricavo totale e medio – L'utente inserisce sequenzialmente i dati di vendita per i diversi libri, il programma aggrega i dati per ciascun codice ISBN e stampa il dato aggregato – Deve quindi essere possibile: • Inserire e stampare i dati di un libro • Sommare più dati di vendita relativi allo stesso libro • Stampare i dati di vendita aggregati relativi a un libro
  • 17.
    Suddivisione del programma •Un file di libreria (Sales_item.h) conterrà la definizione del tipo che rappresenta il dato di vendita: Sales_item • Definiamo ora Sales_item come struct, cioè un tipo definito dall'utente che comprende dati, ma non le operazioni relativi al dato di vendita – Campi: codice ISBN, copie vendute, ricavo • Il programma principale importa e usa Sales_item come se fosse un tipo predefinito – Sales_item item; // dichiara una var. di tipo Sales_item !
  • 18.
    Sales_item.h #ifndef SALES_DATA_H #define SALES_DATA_H #include<string> using namespace std; struct Sales_data { string bookNo; unsigned units_sold = 0; double revenue = 0.0; }; #endif
  • 19.
    Programma principale #include <iostream> #include<string> #include "Sales_data.h" using namespace std; int main() { Sales_data data1, data2; // code to read into data1 and data2 double price = 0; // price per book, used to calculate total revenue // read the first transactions: ISBN, number of books sold, price per book cin >> data1.bookNo >> data1.units_sold >> price; // calculate total revenue from price and units_sold data1.revenue = data1.units_sold * price; // read the second transaction cin >> data2.bookNo >> data2.units_sold >> price; data2.revenue = data2.units_sold * price; // check whether data1 and data2 have the same ISBN, if so print the sum of data1 and data2 if (data1.bookNo == data2.bookNo) { unsigned totalCnt = data1.units_sold + data2.units_sold; double totalRevenue = data1.revenue + data2.revenue; // print: ISBN, total sold, total revenue, average price per book cout << data1.bookNo << " " << totalCnt << " " << totalRevenue << " "; if (totalCnt != 0) cout << totalRevenue/totalCnt << endl; else cout << "(no sales)" << endl; } else { } } return 0; // indicate success cerr << "Data must refer to the same ISBN" return -1; // indicate failure << endl; // transactions not for same ISBN