Skip to content
This repository has been archived by the owner on Jun 16, 2023. It is now read-only.

Commit

Permalink
fine lezione 18
Browse files Browse the repository at this point in the history
  • Loading branch information
mc-cat-tty committed Nov 30, 2021
1 parent a46006b commit 0c4151b
Show file tree
Hide file tree
Showing 3 changed files with 337 additions and 0 deletions.
106 changes: 106 additions & 0 deletions 18_struct.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Struct
Problema: riuscire a rappresentare una entità del mondo reale e, successivamente, estendere questa soluzione per memorizzare molteplici entità del mondo reale.
Eg: idealmente array di persona, caratterizzata da altezza, età e peso

Vogliamo creare un nuovo tipo di dato che rappresenti una persona -> si utilizza la struct (struttura dati)
```
struct persona {
char nome[16]; // stringa di 15 caratteri
char cognome[21];
// ...
int altezza;
int peso;
int eta;
}
```

Da questo momento in poi posso dichiarare variabili di questo tipo di dato.
```
persona Mario;
```

Nota: in C++ non è necessario ripetere `struct`

## Definizione
Definizione: un oggetto di tipo struttura è una n-upla ordinata di n elementi ognuno dei quali viene detto campo o membro della struttura. A volte il tipo struttura viene chiamato _record_ (in linguaggi come l'SQL)

## Differenza con array
I tipi di dato contenuti possono essere eterogenei, non omogenei come negli array

Le struct a loro volta possono contenere oggetti strutturati come altre strutture o array.

## Sintassi
```
struct <nome_tipo> { <dichiarazione_membri> }; // il ; è necessario perchè potrei dichiarare direttamente un oggetto di tipo <nome_tipo>
```

Definizione di un oggetto strutturato: `<nome_tipo> <identificatore1> {, <identificatoren>}`

## Selezioni dei campi
`<nome_oggetto>.<nome_campo>`

Posso utizzare il campo come se fosse una normale variabile

// link: struttura.cpp

## Dimensione
=> numero di celle contigue tanto quanto sono i suoi campi. Attenzione all'ordine di definizione perchè conta (per gli accessi errati alla memoria).

## Passaggio a funzione
Le struct, di default, vengono passate alle funzioni per valori (deep copy = copia elemento per elemento)

Solitamente si passa ad una funzione un array di struct, così che venga passato per riferimento alla funzione

## Inizializzazione
```
struct coord {int x, y};
coord p1 = {3, 2}; // Attenzione: conta solo l'ordine dei campi
```

## Deep copy (assegnazione tra struct)
`coord p2 = p1` equivale a copiare campo per campo da p1 a p2

Non è consentito fare assegnamenti tra struct con nome tipo differente tra loro

Vale anche se se all'interno della struttura si trova un vettore, un vettore di vettori o qualsiasi altra cosa -> deep copy degli elementi una locazione alla volta

### Corretto e sbagliato
`struct frutto { char nome[20]; float peso, diametro; };`

`frutto mela = { "mela", 5, 2 };` // corretto
`mela.nome = "melarossa";` // sbagliato
`mela.nome = {'m', 'e', 'l'};` // sbagliato

## Array di struct
=> possibile come se fosse un array normale.

## Sort di array di struct
Gli algo visti fin'ora restano validi, perchè tra le struct è possibile usare l'operatore di assegnamento

Dato che copiare svariate struct da una locazione di memoria all'altra è un'operazione dispendiosa, si può ordinare un array di indici che rappresentano (associati univicamente) agli elementi del vettore di struct e ordinare questo array.

// TODO: implementa le estensioni di classifica_solo_elenco.pp

## Progettazione strutture dati
Eg: da triangolo estrarre area e perimetro
triangolo deve contenere:
- base min
- base mag
- h
- lato obl 1
- lato obl 2
Di tipo float/double (valori reali)

La stessa soluzione si potrebbe ottenere utilizzando un array, ma gli indici non sarebbero legati logicamente ad un univoco valore
=> maggiore leggibilità

Magic roule: se in una funzione utilizzo più di 7 parametri probabilmente mi perdo

Solitamente è più funzionale passare un intero oggeto al posto di passare ogni singolo elemnto di esso, nonostante la funzione operi solo su parte di essi
Se la funzione lavora su molti meno campi di quelli definiti nella struttura, allora è più vantaggioso passare solamente un membro della struct.

Si deve capire bene o male su quali elementi lavora la struttura senza leggerne l'implementazione

=> livello di astrazione appropriato

Utilizza modificatore const quando non modifichi i valori di una struttura
182 changes: 182 additions & 0 deletions esercitazioni/classifica_solo_elenco.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
Scrivere un programma che gestisca i tempi di una serie di sciatori identificati da nome, tempo in secondi.
Il programma deve mostrare a video il dato inserito espresso in minuti, secondi + la lunghezza del campo nome
*/

#include <iostream>
#include <cstring>

using namespace std;

const int MAX_DIM = 10;
const int MAX_NAME_LEN = 20;

struct sciatore_t {
char nome[21]; // len max = 20 caratteri
int secondi; // tempo in secondi
};

enum err_t { OK, NO_SPACE_LEFT, DUPLICATE_NAME, NAME_TOO_LONG, NAME_NOT_FOUND };

void log(err_t e) {
switch (e) {
case OK:
break;
case NO_SPACE_LEFT:
cout << "Spazio terminato" << endl;
break;
case DUPLICATE_NAME:
cout << "Nome esistente" << endl;
break;
case NAME_TOO_LONG:
cout << "Nome troppo lungo" << endl;
break;
case NAME_NOT_FOUND:
cout << "Nome non trovato" << endl;
break;
}
}

void sec_to_min_sec(const int sec_in, int &min, int &sec) {
min = sec_in/60;
sec = sec_in%60;
}

int cerca(const char name[], sciatore_t lista[], const int dim) {
for (int i=0; i<dim; i++) {
if (strcmp(name, lista[i].nome) == 0)
return i;
}
return -1;
}

err_t inserisci_sciatore(const char name[], sciatore_t lista[], int &dim, const int max_dim, const int max_name_len) {
if (dim >= max_dim)
return NO_SPACE_LEFT;
if (int(strlen(name)) >= max_name_len)
return NAME_TOO_LONG;
if (cerca(name, lista, dim) != -1)
return DUPLICATE_NAME;

strcpy(lista[dim++].nome, name);
return OK;
}

void stampa_elenco(const sciatore_t lista[], const int dim) {
for (int i=0; i<dim; i++) {
cout << "Nome: " << lista[i].nome << endl;
// << "Tempo: " << min << " minuti e " << sec << " secondi" << endl;
}
}

err_t inserisci_tempo(const char nome[], const int min, const int sec, sciatore_t lista[], const int dim) {
int index = cerca(nome, lista, dim);
if (index == -1)
return NAME_NOT_FOUND;
lista[index].secondi = min*60+sec;
return OK;
}

int primo_classificato(const sciatore_t lista[], const int dim) {
if (dim == 0)
return -1; // errore se non sono presenti partecipanti

int min_i = 0;
for (int i=1; i<dim; i++) {
min_i = lista[i].secondi < lista[min_i].secondi ? i : min_i;
}
return min_i;
}

/*
int main() {
sciatore_t sciatori[MAX_DIM];
int dim = 0;
while (!cin.eof()) {
}
dim--; // quando esco incremento dim, ma non è stato inserito l'oggetto
// cout << dim;
int min_tempo_i = 0;
for (int i=1; i<dim; i++) {
min_tempo_i = sciatori[i].secondi < sciatori[min_tempo_i].secondi ? i : min_tempo_i;
}
int min, sec;
sec_to_min_sec(sciatori[min_tempo_i].secondi, min, sec);
cout << "Il vincitore è " << sciatori[min_tempo_i].nome << " con "
<< min << " minuti e " << sec << " secondi" << endl
<< "Dimensione del nome: " << strlen(sciatori[min_tempo_i].nome) << endl;
return 0;
}
*/

int main()
{
int scelta ;

char tmp_name[MAX_NAME_LEN+1];
int tmp_min, tmp_sec;

err_t err;

sciatore_t sciatori[MAX_DIM];
int dim = 0;

int index_primo;

while (true) {
cout<<"Gestione classifica\n" ;
cout<<"Menu\n" ;
cout<<"1 Inserimento di un nuovo partecipante\n" ;
cout<<"2 Stampa elenco partecipanti\n" ;
cout<<"3 Gara\n" ;
cout<<"4 Stampa primo classificato\n" ;
cout<<"5 Uscita\n" ;

cin>>scelta ;
switch(scelta) {
case 1:
cout << "Nome: ";
cin >> tmp_name;
// cout << "Tempo [secondi]: ";
// cin >> tmp_sec;
if ( (err = inserisci_sciatore(tmp_name, sciatori, dim, MAX_DIM, MAX_NAME_LEN)) != OK) {
log(err);
}
break ;
case 2:
stampa_elenco(sciatori, dim);
break ;
case 3:
for (int i=0; i<dim; i++) {
cout << "Tempo di " << sciatori[i].nome << " [min, sec]: "; cin >> tmp_min >> tmp_sec;
err = inserisci_tempo(sciatori[i].nome, tmp_min, tmp_sec, sciatori, dim);
if (err != OK)
log(err);
}
break ;
case 4:
index_primo = primo_classificato(sciatori, dim);
if (index_primo == -1) {
cout << "Non sono presenti partecipanti" << endl;
break;
}
sec_to_min_sec(sciatori[index_primo].secondi, tmp_min, tmp_sec);
cout << "Il primo classificato è " << sciatori[index_primo].nome << " con "
<< tmp_min << " minuti e "
<< tmp_sec << " secondi"
<< endl;
break ;
case 5:
return 0 ;
default:
continue ;
} // Fine switch
fflush(stdin);
} // Fine while
return 0 ;
}
49 changes: 49 additions & 0 deletions esercitazioni/gara_sciatori.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Scrivere un programma che gestisca i tempi di una serie di sciatori identificati da nome, tempo in secondi.
Il programma deve mostrare a video il dato inserito espresso in minuti, secondi + la lunghezza del campo nome
*/

#include <iostream>
#include <cstring>

using namespace std;

const int MAX_DIM = 10;

struct sciatore_t {
char nome[21]; // len max = 20 caratteri
int secondi; // tempo in secondi
};

void sec_to_min_sec(const int sec_in, int &min, int &sec) {
min = sec_in/60;
sec = sec_in%60;
}

int main() {
sciatore_t sciatori[MAX_DIM];
int dim = 0;

while (!cin.eof()) {
cout << "Nome: ";
cin >> sciatori[dim].nome;
cout << "Tempo [secondi]: ";
cin >> sciatori[dim++].secondi;
}
dim--; // quando esco incremento dim, ma non è stato inserito l'oggetto
// cout << dim;

int min_tempo_i = 0;
for (int i=1; i<dim; i++) {
min_tempo_i = sciatori[i].secondi < sciatori[min_tempo_i].secondi ? i : min_tempo_i;
}

int min, sec;
sec_to_min_sec(sciatori[min_tempo_i].secondi, min, sec);
cout << "Il vincitore è " << sciatori[min_tempo_i].nome << " con "
<< min << " minuti e " << sec << " secondi" << endl
<< "Dimensione del nome: " << strlen(sciatori[min_tempo_i].nome) << endl;

return 0;
}

0 comments on commit 0c4151b

Please sign in to comment.