Informatica B Esercitazione 6 18 ottobre 2018 Struct, typedef, enum 6.1 Si scriva un programma C per gestire una rubrica telefonica. Un contatto della rubrica è composto da un nome di persona e dal rispettivo numero di telefono. Il programma permette di inserire quattro contatti. Una volta che l'inserimento è terminato, il programma permette di cercare un contatto per nome. Se il nome inserito da tastiera è memorizzato nella rubrica, stampa il numero corrispondente, altrimenti stampa "Non trovato". In ogni caso, permette di cercare un altro contatto. In questa soluzione, dichiariamo le variabili struct direttamente nel main. Potremmo anche usare typedef, come nell'esercizio 6.2, per denire un tipo stringa_t e un tipo contatto_t. Altri possibili miglioramenti (lasciati per esercizio) sono: Usare una stringa anche per il numero di telefono (per gestire numeri molto lunghi e zeri iniziali). Permettere l'inserimento di un numero arbitrario di contatti (ssando solo il massimo). Permettere all'utente di passare dalla fase di ricerca a quella di inserimento, e viceversa, ogni volta che lo desidera. Permettere all'utente di eliminare dei contatti. Gestire nomi ripetuti. 1 #i n c l u d e <s t d i o. h> 2 #i n c l u d e <s t r i n g. h> 3 4 5 /* 6 Es. 6.1 7 Rubrica telefonica 1
8 */ 9 10 #d e f i n e NUM_CONTATTI 4 11 #d e f i n e MAX_LEN 20 12 13 int main ( ) 14 { 15 16 struct { 17 char nome [MAX_LEN] ; // il primo campo e' una stringa 18 long int numero ; // il secondo campo e' un numero 19 } c o n t a t t i [NUM_CONTATTI] ; // array di struct 20 21 int i, t r o v a t o ; 22 char nome_in [MAX_LEN] ; 23 24 25 p r i n t f ( " INSERIMENTO \n" ) ; 26 for ( i =0; i <NUM_CONTATTI; i ++) 27 { 28 p r i n t f ( "\ ninserisci nome\n" ) ; 29 g e t s ( c o n t a t t i [ i ]. nome ) ; 30 p r i n t f ( " Insersci numero \n" ) ; 31 s c a n f ( "%ld", &( c o n t a t t i [ i ]. numero ) ) ; 32 s c a n f ( "%*c" ) ; // consuma newline (per gets successiva ) 33 } 34 35 p r i n t f ( "\ nricerca \n" ) ; 36 while ( 1 ) 37 { 38 p r i n t f ( "\ ninserisci nome da cercare \n" ) ; 39 g e t s ( nome_in ) ; 40 41 t r o v a t o =0; 42 for ( i =0; i <NUM_CONTATTI; i ++) 43 { 44 i f ( strcmp ( nome_in, c o n t a t t i [ i ]. nome)==0) 45 { 46 p r i n t f ( "Il suo numero e' %ld\n", c o n t a t t i [ i ]. numero ) ; 47 t r o v a t o = 1 ; 48 break ; 49 } 50 } 51 i f (! t r o v a t o ) 52 { 53 p r i n t f ( "Non trovato!\n" ) ; 2
54 } 55 } 56 } 3
6.2 Utilizzando il C, denire le strutture dati necesssarie per la gestione di un aeroporto: L'aeroporto ha associato un nome (massimo 20 caratteri), un elenco di terminal (massimo 5) e il numero eettivo di terminal. Ciascun terminal ha associato un numero identicativo, un elenco di piste (massimo 10) e il numero eettivo di piste. Ciascuna pista ha associato un numero identicativo, uno stato (libera o impegnata), l'aereo che la sta eventualmente impegnando (per un decollo o un atterraggio), una lista di aerei in coda per il decollo (massimo 3, eventualmente vuota) e il numero di aerei eettivamente in coda. Ciascun aereo ha associato un codice identicativo del velivolo e uno stato (attesa, decollo o atterraggio). Scrivere un frammento di codice C che inizializza un aeroporto in questo modo: l'aeroporto si chiama "Malpensa" e ha 2 terminal (numerati 1,2). Ogni terminal ha 5 piste (numerate globalmente da 1 a 10), tutte libere, senza aerei in coda per decollare. Di fronte ad un esercizio di questa complessità, è importante fare le cose con ordine. Prima deniamo tutti i tipi necessari, poi scriviamo il codice che li utilizza. Nel denire i tipi, seguiamo l'approccio "bottom-up": deniamo prima i tipi più semplici. 1 #i n c l u d e <s t d i o. h> 2 #i n c l u d e <s t r i n g. h> 3 4 /* 5 Es. 6.2 6 Aeroporto 7 */ 8 9 #d e f i n e MAX_LEN_NOME 21 10 #d e f i n e MAX_LEN_CODA 3 11 #d e f i n e MAX_PISTE 10 12 #d e f i n e MAX_TERMINAL 5 13 14 // Definizione tipi 15 // Stato aereo 16 typedef enum { a t t e s a, d e c o l l o, a t t e r r a g g i o } stato_aereo_t ; 17 // Stato pista 18 typedef enum { l i b e r a, impegnata } stato_pista_t ; 19 // Nome (e.g. " Malpensa ") 20 typedef char nome_t [MAX_LEN_NOME] ; 21 // Aereo 4
22 typedef struct { 23 int i d ; 24 stato_aereo_t s t a t o ; 25 } aereo_ t ; 26 // Pista 27 typedef struct { 28 int i d ; 29 stato_pista_t s t a t o ; 30 aereo_t a e r e o ; 31 aereo_ t coda [MAX_LEN_CODA] ; 32 int len_coda ; 33 } p ista_t ; 34 // Terminal 35 typedef struct { 36 int i d ; 37 p ista_t p i s t e [MAX_PISTE ] ; 38 int num_piste ; 39 } terminal_t ; 40 41 typedef struct { 42 nome_t nome ; 43 int num_terminal ; 44 terminal_t t e r m i n a l [MAX_TERMINAL] ; 45 } aeroporto_t ; 46 47 48 int main ( ) 49 { 50 // Dichiarazione variabili 51 aeroporto_t a e r o p o r t o ; 52 /* La dichiarazione qui sopra prepara la memoria necessaria 53 per un aeroporto delle massime dimensioni possibili : 5 terminal e 54 10 piste per terminal */ 55 int i, j ; 56 int k = 1 ; // contatore globale piste 57 58 // Inizializzazione 59 // campi di aeroporto_t 60 s t r c p y ( a e r o p o r t o. nome, " Malpensa " ) ; 61 /* L' assegnamento a stringa e' consentito solo in fase 62 di dichiarazione. In ogni altro caso e' necessario 63 usare strcpy o un ciclo.*/ 64 a e r o p o r t o. num_terminal = 2 ; 65 66 for ( i =0; i <a e r o p o r t o. num_terminal ; i ++) 67 { 5
68 // campi di terminal_t 69 a e r o p o r t o. t e r m i n a l [ i ]. i d = i +1; 70 a e r o p o r t o. t e r m i n a l [ i ]. num_piste = 5 ; 71 72 for ( j =0; j<a e r o p o r t o. t e r m i n a l [ i ]. num_piste ; j++) 73 { 74 // campi di pista_t 75 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. i d = k ; 76 k++; 77 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. s t a t o = l i b e r a ; 78 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. len_coda = 0 ; 79 } 80 } 81 82 return 0 ; 83 } 6
6.3 Assumere che l'aeroporto "Malpensa" denito nell'es. 6.2 si trovi ora in uno stato qualsiasi (ottenuto, ad esempio, tramite inserimento di ulteriori dati). Questo signica che potrebbero esserci delle piste impegnate e degli aerei in attesa di decollare. 1. Scrivere un frammento di codice C che, dato l'identicativo di un aereo in volo e un numero di terminal, seleziona una pista per l'atterraggio. La pista deve appartenere al terminal specicato, deve essere libera e non deve avere aerei in attesa di decollare. Se queste condizioni sono rispettate, la pista viene impegnata dall'aereo per l'atterraggio. Inserire/modicare tutti i dati rilevanti. 1 int id_aereo, id_terminal ; // dati di input 2 int s u c c e s s o ; // flag 3 pista_t p i s t a ; // variabile temporanea 4 5 p r i n t f ( " Inserire codice aereo per atterraggio \n" ) ; 6 s c a n f ( "%d", &id_aereo ) ; 7 p r i n t f ( " Inserire terminal \n" ) ; 8 s c a n f ( "%d", &id_terminal ) ; 9 10 for ( i =0; i <a e r o p o r t o. t e r m i n a l [ id_terminal 1]. num_piste ; i ++) 11 { 12 // creiamo una copia della pista corrente 13 p i s t a = a e r o p o r t o. t e r m i n a l [ id_terminal 1]. p i s t e [ i ] ; 14 i f ( p i s t a. s t a t o==l i b e r a && p i s t a. len_coda==0) 15 { 16 s u c c e s s o = 1 ; 17 p r i n t f ( " Aereo %d atterra su pista %d\n", id_aereo, p i s t a. i d ) ; 18 p i s t a. a e r e o. i d = id_aereo ; 19 p i s t a. a e r e o. s t a t o = a t t e r r a g g i o ; 20 p i s t a. s t a t o = impegnata ; 21 // abbiamo modificato la copia! 22 // ora aggiorniamo l' originale : 23 a e r o p o r t o. t e r m i n a l [ id_terminal 1]. p i s t e [ i ] = p i s t a ; 24 break ; 25 } 26 27 } 28 i f (! s u c c e s s o ) 29 { 30 p r i n t f ( "Non ci sono piste libere in questo terminal!\n" ) ; 31 } 2. Scrivere un frammento di codice C che, dato l'identicativo di un aereo in fase di decollo: 7
Ricerca l'aereo nel sistema e verica che abbia eettivamente lo stato 'decollo', altrimenti stampa un errore; Se non ci sono aerei in attesa sulla pista corrispondente, la pista diventa libera. Altrimenti, la pista viene impegnata dall'aereo che occupa la prima posizione della coda di attesa. Modicare opportunamente la coda di attesa e tutti i dati rilevanti. 1 int id_aereo ; // dati di input 2 int s u c c e s s o ; // flag 3 pista_t p i s t a ; // variabile temporanea 4 5 p r i n t f ( " Inserire codice aereo per decollo \n" ) ; 6 s c a n f ( "%d", &id_aereo ) ; 7 8 for ( i =0; i <a e r o p o r t o. num_terminal ; i ++) 9 { 10 for ( j =0; j<a e r o p o r t o. t e r m i n a l [ i ]. num_piste ; j++) 11 { 12 // copia 13 p i s t a = a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ] ; 14 i f ( p i s t a. s t a t o==impegnata && p i s t a. a e r e o. i d==id_aereo ) 15 { 16 s u c c e s s o = 1 ; 17 p r i n t f ( " Aereo %d decolla da pista %d\n", id_aereo, p i s t a. i d ) ; 18 i f ( p i s t a. len_coda==0) 19 { 20 p i s t a. s t a t o = l i b e r a ; 21 } 22 else { 23 // almeno un aereo in coda 24 // promuovi primo aereo della coda 25 p i s t a. a e r e o = p i s t a. coda [ 0 ] ; 26 p i s t a. a e r e o. s t a t o = d e c o l l o ; 27 // aggiorna coda 28 for ( k=1;k<p i s t a. len_coda ; k++) 29 { 30 p i s t a. coda [ k 1] = p i s t a. coda [ k ] ; 31 } 32 p i s t a. len_coda ; 33 34 } 35 36 // aggiorna originale 37 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ] = p i s t a ; 38 break ; 39 } 8
40 } 41 } 42 43 i f (! s u c c e s s o ) 44 { 45 p r i n t f ( " Aereo non trovato!\n" ) ; 46 } Le soluzioni fornite sono solo frammenti di codice: danno per scontato il codice scritto nell'esercizio 6.2 e non sono compilabili. Segue un possibile programma "completo" (non richiesto) che mostra il codice in azione. Aggiungiamo anche delle istruzioni che portano l'aeroporto in uno stato più interessante e stampano lo stato nale dell'aeroporto. 1 #i n c l u d e <s t d i o. h> 2 #i n c l u d e <s t r i n g. h> 3 4 /* 5 Es. 6.2 6 Aeroporto 7 */ 8 9 #d e f i n e MAX_LEN_NOME 21 10 #d e f i n e MAX_LEN_CODA 3 11 #d e f i n e MAX_PISTE 10 12 #d e f i n e MAX_TERMINAL 5 13 14 typedef enum { a t t e s a, d e c o l l o, a t t e r r a g g i o } stato_aereo_t ; 15 16 typedef enum { l i b e r a, impegnata } stato_pista_t ; 17 18 typedef char nome_t [MAX_LEN_NOME] ; 19 20 typedef struct { 21 int i d ; 22 stato_aereo_t s t a t o ; 23 } aereo_ t ; 24 25 typedef struct { 26 int i d ; 27 stato_pista_t s t a t o ; 28 aereo_t a e r e o ; 29 aereo_ t coda [MAX_LEN_CODA] ; 30 int len_coda ; 31 } p ista_t ; 32 9
33 typedef struct { 34 int i d ; 35 p ista_t p i s t e [MAX_PISTE ] ; 36 int num_piste ; 37 } terminal_t ; 38 39 typedef struct { 40 nome_t nome ; 41 int num_terminal ; 42 terminal_t t e r m i n a l [MAX_TERMINAL] ; 43 } aeroporto_t ; 44 45 46 int main ( ) 47 { 48 p r i n t f ( " AEROPORTO \n" ) ; 49 aeroporto_t a e r o p o r t o ; 50 int i, j ; 51 int k = 1 ; // contatore globale piste 52 int id_aereo, id_terminal ; // dati di input 53 int s u c c e s s o ; // flag 54 pista_t p i s t a ; // variabile temporanea 55 int id_temp ; 56 57 // Inizializzazione 58 s t r c p y ( a e r o p o r t o. nome, " Malpensa " ) ; 59 a e r o p o r t o. num_terminal = 2 ; 60 61 for ( i =0; i <a e r o p o r t o. num_terminal ; i ++) 62 { 63 a e r o p o r t o. t e r m i n a l [ i ]. i d = i +1; 64 a e r o p o r t o. t e r m i n a l [ i ]. num_piste = 5 ; 65 66 for ( j =0; j<a e r o p o r t o. t e r m i n a l [ i ]. num_piste ; j++) 67 { 68 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. i d = k ; 69 k++; 70 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. s t a t o = l i b e r a ; 71 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. len_coda = 0 ; 72 } 73 } 74 75 // Portiamo l' aeroporto in uno stato piu ' interessante 76 // La pista 1 ha un aereo in fase di decollo 77 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 0 ]. s t a t o = impegnata ; 78 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 0 ]. a e r e o = ( aereo_t ) { 5 1 2, d e c o l l o } ; 10
79 // La pista 2 ha un aereo in fase di decollo e due aerei in attesa 80 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 1 ]. s t a t o = impegnata ; 81 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 1 ]. a e r e o = ( aereo_t ) { 9 8 2, d e c o l l o } ; 82 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 1 ]. len_coda = 2 ; 83 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 1 ]. coda [ 0 ] = ( aereo_t ) { 8 8 8, a t t e s a } ; 84 a e r o p o r t o. t e r m i n a l [ 0 ]. p i s t e [ 1 ]. coda [ 1 ] = ( aereo_t ) { 3 4 1, a t t e s a } ; 85 86 // 6.3.1: atterraggio ( provare a inserire 123, 1)--------------------- 87 p r i n t f ( "\ natterraggio \n" ) ; 88 p r i n t f ( " Inserire codice aereo per atterraggio \n" ) ; 89 s c a n f ( "%d", &id_aereo ) ; 90 p r i n t f ( " Inserire terminal \n" ) ; 91 s c a n f ( "%d", &id_terminal ) ; 92 93 for ( i =0; i <a e r o p o r t o. t e r m i n a l [ id_terminal 1]. num_piste ; i ++) 94 { 95 p i s t a = a e r o p o r t o. t e r m i n a l [ id_terminal 1]. p i s t e [ i ] ; 96 i f ( p i s t a. s t a t o==l i b e r a && p i s t a. len_coda==0) 97 { 98 s u c c e s s o = 1 ; 99 p r i n t f ( " Aereo %d atterra su pista %d\n", id_aereo, p i s t a. i d ) ; 100 p i s t a. a e r e o. i d = id_aereo ; 101 p i s t a. a e r e o. s t a t o = a t t e r r a g g i o ; 102 p i s t a. s t a t o = impegnata ; 103 a e r o p o r t o. t e r m i n a l [ id_terminal 1]. p i s t e [ i ] = p i s t a ; 104 break ; 105 } 106 107 } 108 i f (! s u c c e s s o ) 109 { 110 p r i n t f ( "Non ci sono piste libere in questo terminal!\n" ) ; 111 } 112 // ------------------------------------------------------------------- 113 114 // 6.3.1: decollo ( provare a inserire 512 o 982) --------------------- 115 p r i n t f ( "\ ndecollo \n" ) ; 116 s u c c e s s o = 0 ; 117 p r i n t f ( " Inserire codice aereo per decollo \n" ) ; 118 s c a n f ( "%d", &id_aereo ) ; 119 120 for ( i =0; i <a e r o p o r t o. num_terminal ; i ++) 121 { 122 for ( j =0; j<a e r o p o r t o. t e r m i n a l [ i ]. num_piste ; j++) 123 { 124 p i s t a = a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ] ; 11
125 i f ( p i s t a. s t a t o==impegnata && p i s t a. a e r e o. i d==id_aereo ) 126 { 127 s u c c e s s o = 1 ; 128 p r i n t f ( " Aereo %d decolla da pista %d\n", id_aereo, p i s t a. i d ) ; 129 i f ( p i s t a. len_coda==0) 130 { 131 p i s t a. s t a t o = l i b e r a ; 132 } 133 else { 134 p i s t a. a e r e o = p i s t a. coda [ 0 ] ; 135 p i s t a. a e r e o. s t a t o = d e c o l l o ; 136 for ( k=1;k<p i s t a. len_coda ; k++) 137 { 138 p i s t a. coda [ k 1] = p i s t a. coda [ k ] ; 139 } 140 p i s t a. len_coda ; 141 142 } 143 144 a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ] = p i s t a ; 145 break ; 146 } 147 } 148 } 149 150 i f (! s u c c e s s o ) 151 { 152 p r i n t f ( " Aereo non trovato!\n" ) ; 153 } 154 // ------------------------------------------------------------------- 155 156 // Stampa ( per verifica ) 157 p r i n t f ( "\ naeroporto di %s\n", a e r o p o r t o. nome ) ; 158 159 for ( i =0; i <a e r o p o r t o. num_terminal ; i ++) 160 { 161 p r i n t f ( "\ nterminal %d\n", a e r o p o r t o. t e r m i n a l [ i ]. i d ) ; 162 for ( j =0; j<a e r o p o r t o. t e r m i n a l [ i ]. num_piste ; j++) 163 { 164 p r i n t f ( " Pista %2d: ", a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. i d ) ; 165 i f ( a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. s t a t o==impegnata ) 166 { 167 id_temp = a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. a e r e o. i d ; 168 p r i n t f ( " aereo %d in fase di ", id_temp ) ; 169 switch ( a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. a e r e o. s t a t o ) 170 { 12
171 case d e c o l l o : 172 p r i n t f ( " decollo \n" ) ; 173 break ; 174 case a t t e r r a g g i o : 175 p r i n t f ( " atterraggio \n" ) ; 176 break ; 177 default : 178 p r i n t f ( " ERRORE \n" ) ; 179 break ; 180 } 181 } 182 else 183 { 184 p r i n t f ( " libera \n" ) ; 185 } 186 187 188 for ( k=a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. len_coda 1;k>=0;k ) 189 { 190 id_temp = a e r o p o r t o. t e r m i n a l [ i ]. p i s t e [ j ]. coda [ k ]. i d ; 191 p r i n t f ( "\t%d e' in attesa di decollare \n", id_temp ) ; 192 } 193 } 194 } 195 } 13