Esercitazione n. 4 Tipi di dati Puntatori Queste slide sono distribuite con licenza Creative Commons Attribuzione-Non commerciale-Condividi allo stesso modo 2.5 Italia C/1: intersezione - Problema Si vuole realizzare in linguaggio C lo stesso programma già realizzato in linguaggio assembler (un software che trovi gli elementi di intersezione di due sequenze [non ordinate] di numeri interi positivi e dove ogni sequenza è terminata dal numero 0). Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 2 C/1: intersezione - Pseudocodice C main() { \\ memorizza \\ memorizza \\ memorizza \\ memorizza il numero di gli elementi il numero di gli elementi elementi del primo insieme del primo insieme nell'array ins1 elementi del secondo insieme del primo insieme nell'array ins2 while (non ho finito di scandire ins1) { while (non ho finito di scandire ins2 e non ho già trovato l'elemento corrente di ins1 in ins2) { if (elemento corrente di ins1 == elemento corrente di ins2) { \\ aggiungi l'elemento corrente all'array ins_int \\ incrementa il contatore degli elementi di ins_int } } } } \\ passa all'elemento successivo di ins2 \\ passa all'elemento successivo di ins1 \\ stampa gli elementi di ins_int Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 3 C/1: intersezione - Nuovi tipi di dati Si introduce un tipo di dato strutturato: ➢ array: per rappresentare una sequenza di celle di memoria consecutive e omogenee (cioè formata da elementi dello stesso tipo semplice) Es: int lista[20] identifica i 20 valori interi da lista[0] a lista[19] Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 4 C/1: intersezione - Codice sorgente /1 /* Dati 2 insiemi di numeri interi, il programma calcola l'intersezione di questi due insiemi. Gli insiemi sono memorizzati negli array 'ins1' e 'ins2', mentre l'insieme intersezione è contenuto nell'array 'ins_int'. Input: numero di elementi dell'insieme 1 elementi dell'insieme 1 numero di elementi dell'insieme 2 elementi dell'insieme 2 Output: elementi dell'insieme intersezione */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 5 C/1: intersezione - Codice sorgente /2 #include <stdio.h> #define MAX_EL 100 typedef enum {false, true} bool; main() { /* All'utente viene prima chiesto di inserire il numero di elementi dell'insieme 1 (che non deve superare il numero massimo consentito MAX_EL), e solo dopo di inserire gli elementi dell'insieme. Per leggere il numero degli elementi del primo insieme si usa un ciclo while, che viene ripetuto finché l'utente non inserisce un numero di elementi valido. La variabile n_el1 (che contiene il numero di elementi del primo insieme) viene inizializzata al valore MAX_EL+1, in modo che la prima volta che il ciclo while viene eseguito la condizione sia vera, per cui il ciclo venga eseguito almeno una volta. */ int ins1[MAX_EL], ins2[MAX_EL], ins_int[MAX_EL]; unsigned int i, j, k, n_el1 = MAX_EL+1, n_el2 = MAX_EL+1; bool trovato; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 6 C/1: intersezione - Codice sorgente /3 while (n_el1 > MAX_EL) { printf ("Inserisci il numero di elementi del primo insieme (minore di %u): ", MAX_EL); scanf ("%u", &n_el1); } for (i=0 ; i<n_el1 ; i++) { printf ("Inserisci l'elemento numero %u di %u: ", i+1, n_el1); scanf ("%d", &ins1[i]); } while (n_el2 > MAX_EL) { printf ("Inserisci il numero di elementi del secondo insieme (minore di %u): ", MAX_EL); scanf ("%u", &n_el2); } for (i=0 ; i<n_el2 ; i++) { printf ("Inserisci l'elemento numero %u di %u: ", i+1, n_el2); scanf ("%d", &ins2[i]); } /* Come si nota, i pezzi di codice relativi alla lettura degli elementi dei due array sono molto simili, cambiano solo per il nome delle variabili coinvolte. Si vedrà in seguito un metodo per 'fattorizzare' il codice comune, e scriverlo una sola volta. */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 7 C/1: intersezione - Codice sorgente /4 /* Scorrere uno ad uno gli elementi del primo insieme, e controllare se nell'insieme 2 c'è un elemento uguale. Se si trova un elemento comune agli insiemi 1 e 2, lo si inserisce nell'array 'ins_int'. k è un contatore che indica quanti elementi sono stati memorizzati nell'array 'ins_int'. Una volta trovato un elemento comune tra ins1 ed ins2, non serve più continuare la ricerca, per cui è possibile uscire dal ciclo di scansione dell'insieme 2. Quest'ultima condizione è rappresentata dal fatto che la variabile (di tipo bool, definita dall'utente) sia uguale a true. */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 8 C/1: intersezione - Codice sorgente /5 k = 0; for (i=0 ; i<n_el1 ; i++) { j = 0; trovato = false; /* Notare che in realtà esiste un modo per uscire dal ciclo senza dover ricorrere al check di una variabile 'trovato', e questo modo è tramite il 'break'. Questo è in effetti pratica comune, però in questo modo (senza break) è molto più chiara la condizione di uscita (ancora una volta, il programma è più leggibile) La condizione su 'trovato' si potrebbe anche scrivere, in modo più compatto, come while (j<n_el2 && !trovato) e così in effetti assomiglia molto di più a una formula logica */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 9 C/1: intersezione - Codice sorgente /6 while (j<n_el2 && trovato == false) { if (ins1[i] == ins2[j]) { ins_int[k] = ins1[i]; k++; /* le due istruzioni precedenti possono, volendo, essere compattate in una sola, sfruttando il significato del ++ ins_int[k++] = ins1[i]; */ } E' evidente sia la compattezza, sia la minor leggibilità della seconda forma. trovato = true; } j++; /* In realtà il ciclo interno si può anche scrivere come: for (j=0 ; j<n_el2 && trovato == false ; j++) */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 10 C/1: intersezione - Codice sorgente /7 /* anche qui, per uscire dal ciclo interno quando si è trovato un elemento comune, si potrebbe, invece che ricorrere alla variabile 'trovato', sfruttare il comando 'break'. Questo comando, quando incontrato, fa uscire dal ciclo, per cui si potrebbe scrivere il ciclo interno come: while (j<n_el2) { if (ins1[i] == ins2[j]) { ins_int[k] = ins1[i]; k++; break; } j++; } */ peraltro, la scrittura con il 'break' è SCONSIGLIATA, perchè rende più difficile capire quale è la condizione di uscita dal ciclo (che non è più interamente contenuta nella condizione dopo la parola chiave 'while'). Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 11 C/1: intersezione - Codice sorgente /8 } } printf ("Sono stati trovati %u elementi comuni\n", k); for (i=0 ; i<k ; i++) { printf ("Elemento comune numero %u: %d\n", i, ins_int[i]); } /* Notare che se in ins1 c'è un elemento ripetuto (per esempio 3 volte) che è anche in ins2, questo elemento apparirà in ins_int 3 volte, cioè tante volte quante esso compare in ins1. Se invece un elemento compare 1 sola volta in ins1 e, per esempio 5 volte in ins2, questo apparirà in ins_int una sola volta. */ Nota: da svolgere in autonomia /* */ ESERCIZIO: provare a modificare questo programma in modo che gli elementi ripetuti vengano scartati. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 12 C/2: battaglia navale - Problema Si vuole realizzare in linguaggio C una semplice simulazione del gioco classico della battaglia navale. Lo schema è prefissato, non cambia da partita a partita... I simboli usati sulla “griglia” sono: 'x' 'o' '*' '.' = = = = elemento di una nave "mancato" "colpito" casella sulla quale non è stato effettuato nessun colpo Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 13 C/2: battaglia navale - Codice sorgente /1 /* Un esempio molto semplice di battaglia navale. Lo schema è prefissato, non cambia da partita a partita, per il resto è il normale gioco della battaglia navale. Si distinguono due campi di battaglia: "schema" contiene la disposizione delle navi sul campo di battaglia; "battaglia" tiene traccia dei colpi effettuati dall'utente (se il colpo ha dato come risultato 'mancato' o 'colpito'). I simboli usati sulla “griglia” sono: 'x' = elemento di una nave 'o' = "mancato" '*' = "colpito" '.' = casella sulla quale non è stato effettuato nessun colpo Nota: l'esempio mostra come sfruttare il fatto che in C in realtà i char sono degli interi. */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 14 C/2: battaglia navale - Codice sorgente /2 #include <stdio.h> #define DIM_OR 6 #define DIM_VERT 6 main() { /* gli array (doppi) "schema" e "battaglia" vengono inizializzati al momento della dichiarazione. Essendo questi degli array doppi di caratteri, la sintassi per l'inizializzazione è quella vista sotto, con stringhe di caratteri (comprese tra "") separate da virgole e racchiuse tra parentesi graffe. */ char schema[DIM_OR][DIM_VERT] = {" 12345", "Axx...", "B...x.", "Cx....", "D.xx..", "E....x"}; char battaglia[DIM_OR][DIM_VERT] = {" 12345", "A.....", "B.....", "C.....", "D.....", "E....."}; char c1, c2; int i, j; int pz_rim = 7; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 15 C/2: battaglia navale - Codice sorgente /3 printf ("\n"); do { for (i=0 ; i<DIM_OR ; i++) { for (j=0 ; j<DIM_VERT ; j++) { printf ("%c", battaglia[i][j]); } printf ("\n"); } printf ("\n* = colpito, o = mancato, . = acqua\n"); printf ("Composizione navi: xx xx x x x\n"); printf ("Scegli coordinate (lettera, numero) a cui sparare: "); scanf ("%c%c%*c", &c1, &c2); /* La scanf legge 2 caratteri (le coordinate sono formate da una parte letterale e da una parte numerica, per esempio B5), per questo il codice contiene 2 %c, e a destra devo mettere 2 variabili. */ printf ("\n"); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 16 C/2: battaglia navale - Codice sorgente /4 /* Nel fare tutte le operazioni di verifica della cella su cui l'utente ha sparato si sfrutta il fatto che i char siano degli interi (per cui 'A' corrisponde in realtà al codice ASCII del carattere A) */ if (c1>='A' && c1<='E' && c2>='1' && c2<='5' && battaglia[c1-'A'+1][c2-'1'+1] == '.') { if (schema[c1-'A'+1][c2-'1'+1] == 'x') { battaglia[c1-'A'+1][c2-'1'+1] = '*'; /* Ogni volta che l'utente colpisce una nave, il valore della variabile "pz_rim" (che contiene quanti sono i pezzi di nave ancora da colpire) viene decrementato. Quando pz_rim arriva a 0 vuol dire che l'utente ha colpito tutti i pezzi di nave e il gioco è finito. */ pz_rim--; printf ("\n***COLPITO!***\n\n"); } else { battaglia[c1-'A'+1][c2-'1'+1] = 'o'; printf ("\nMANCATO!\n\n"); } } } while (pz_rim > 0); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 17 C/2: battaglia navale - Codice sorgente /5 printf printf printf printf ("\n"); ("******************\n"); ("***HAI VINTO!!!***\n"); ("******************\n"); } Nota: da svolgere in autonomia Realizzare una variante a questo programma che consenta l'inserimento da parte di un utente dei pezzi nell'array schema Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 18 C/3: concatenazione - Problema Si vuole realizzare in linguaggio C un programma in grado di concatenare due stringhe di caratteri date in input mettendo prima quella che, in ordine lessicografico, viene prima. Ma cos'è una stringa? Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 19 C/3: concatenazione - Codice sorgente /1 /* Il programma chiede all'utente di inserire 2 stringhe di caratteri e le concatena, mettendo prima quella che, in ordine lessicografico, viene prima. L'acquisizione delle stringhe non avviene carattere per carattere ma utilizzando la funzione “gets” fornita dalla libreria “stdio.h” */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 20 C/3: concatenazione - Codice sorgente /2 #include <stdio.h> #define MAX_LUNGH 50 main() { int i, j, k; int l_a1, l_a2; char tempCar; char array1[MAX_LUNGH+1], array2[MAX_LUNGH+1], array_conc[MAX_LUNGH*2+1]; printf ("Inserisci la prima sequenza di caratteri (max %d caratteri): ", MAX_LUNGH); gets (&array1[0]); printf ("Inserisci la seconda sequenza di caratteri (max %d caratteri): ", MAX_LUNGH); gets (&array2[0]); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 21 C/3: concatenazione - Codice sorgente /3 l_a1 = 0; while (array1[l_a1] != '\000') { l_a1++; } l_a2 = 0; while (array2[l_a2] != '\000') { l_a2++; } i = 0; while (i<l_a1 && i<l_a2 && array1[i] == array2[i]) { i++; } /*Invece dei 3 cicli while precedenti si possono scrivere i seguenti cicli for (molto più compatti): for (l_a1=0; array1[l_a1]!= '\000'; l_a1++); for (l_a2=0; array2[l_a2]!= '\000'; l_a2++); for (i=0; i<l_a1 && i<l_a2 && array1[i] == array2[i]; i++); */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 22 C/3: concatenazione - Codice sorgente /4 if (i==l_a1 || array1[i]<array2[i]) { k = 0; for (j=0 ; j<l_a1 ; j++) { array_conc[k] = array1[j]; k++; } for (j=0 ; j<l_a2 ; j++) { array_conc[k] = array2[j]; k++; } } else { k = 0; for (j=0 ; j<l_a2 ; j++) { array_conc[k] = array2[j]; k++; } for (j=0 ; j<l_a1 ; j++) { array_conc[k] = array1[j]; k++; } } array_conc[k] = '\000'; /* Chiudo la stringa concatenata con il carattere nullo '\0' */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 23 C/3: concatenazione - Codice sorgente /5 printf ("La stringa concatenata è:\n"); for ( k=0 ; k<l_a1+l_a2 ; k++) { printf ("%c", array_conc[k]); } printf ("\n"); /*Per le stringhe terminate dal carattere '\0' si può usare, invece del ciclo for sopra scritto, il comando 'printf' con il carattere di controllo '%s' (che indica le stringhe) Es: printf ("La stringa concatenata è:\n%s\n", array_conc); */ } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 24 C/4: conversione basi - Problema Si vuole realizzare in linguaggio C un programma in grado di convertire un numero in base 10 in un'altra base compresa tra 2 e 9. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 25 C/4: conversione basi - Pseudo codice main() { [memorizzare il numero, verificando che sia > 0] [memorizzare la base in cui convertire, verificando che sia <10 e >1] num_tmp = numero; while (num_tmp>0) { [dividere num_tmp per la base; il resto aggiungerlo all'array conv, il risultato metterlo in num_tmp] } [stampare l'array conv, a partire dal fondo (cifra più significativa)] } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 26 C/4: conversione basi - Codice sorgente /1 /* Il programma prende un numero in base 10, e lo converte in una base scelta dall'utente (la nuova base deve essere compresa tra 2 e 9) */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 27 C/4: conversione basi - Codice sorgente /2 #include <stdio.h> main() { int num, base, num_tmp; int conv[50]; int i, n_el; do { printf ("Inserire numero (>0) da convertire: "); scanf ("%d", &num); } while (num<=0); num_tmp = num; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 28 C/4: conversione basi - Codice sorgente /3 do { printf ("Inserire base (compresa tra 2 e 10) in cui convertire il numero: "); scanf ("%d", &base); } while (base < 2 || base > 9); /* Calcolo le singole cifre del numero rappresentato nella nuova base; le singole cifre vengono messe, dalla MENO significativa alla PIU' significativa, nell'array 'conv' */ /* Ad ogni ciclo, il numero num_tmp viene diviso (divisione intera) per la base. Il resto della divisione è la prossima cifra nella nuova base, mentre il risultato verrà ulteriormente diviso nei cicli successivi */ for (i=0 ; num_tmp>0 ; i++) { conv[i] = num_tmp % base; num_tmp = num_tmp / base; } n_el = i; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 29 C/4: conversione basi - Codice sorgente /4 /* Il nuovo numero viene stampato, dalla cifra PIU' significativa alla MENO significativa (quindi occorre scorrere l'array in senso inverso) */ printf ("Il numero %u convertito in base %d è: ", num, base); for (i=n_el-1 ; i>=0 ; i--) { printf ("%d", conv[i]); } printf ("\n"); } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 30 C/5: Bubblesort - Problema Si vuole realizzare in linguaggio C un programma in grado di ordinare un array di interi usando l'algoritmo di bubblesort. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 31 C/5: Bubblesort - Codice sorgente /1 /* Ordina un array di interi usando l'algoritmo di bubblesort */ #include <stdio.h> typedef enum {false, true} bool; #define MAX_DATI 100 Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 32 C/5: Bubblesort - Codice sorgente /2 main() { int dati[MAX_DATI]; int i, n_dati, temp, dato_corr; bool ordinato = false; /* Leggo i dati dallo standard input; la lettura termina quando l'utente inserisce uno 0. */ i = 0; do { printf ("Inserire dato intero n. %d (max %d dati, 0 per terminare): ", i+1, MAX_DATI); scanf ("%d", &dato_corr); if (dato_corr != 0) { dati[i] = dato_corr; i++; } } while (i<MAX_DATI && dato_corr != 0); n_dati = i; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 33 C/5: Bubblesort - Codice sorgente /3 /* Si continua a scorrere l'array finché non è ordinato. */ /* Attenzione a non scrivere ordinato = false al posto di ordinato == false perché sono 2 cose profondamente DIVERSE! Nel primo caso viene effettuato l'assegnamento, e viene ritornato il valore 'false'; il ciclo while valuta la condizione 'false', e quindi esce! */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 34 C/5: Bubblesort - Codice sorgente /4 while (ordinato == false) { /* Si comincia con il presupporre che l'array sia ordinato. */ ordinato = true; /* Ad ogni scansione dell'array, se si trova che ci sono due elementi adiacenti dati[i] e dati[i+1] per cui dati[i] > dati [i+1] allora si scambiano i due elementi. Se si scambiano due elementi, vuol dire che l'array non era ancora ordinato, e quindi che sarà necessario fare almeno un'altra scansione dell'array. Quando si ottiene alla fine un array ordinato, non ci sono più elementi da scambiare, il valore di 'ordinato' rimane 'true', e l'algoritmo si ferma. for (i=0 ; i<n_dati-1 ; i++) { if (dati[i] > dati[i+1]) { temp = dati[i]; dati[i] = dati[i+1]; dati[i+1] = temp; ordinato = false; } } } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 35 */ C/5: Bubblesort - Codice sorgente /5 /* Stampa dell'array ordinato */ printf ("I valori ordinati in ordine crescente sono:\n"); for (i=0 ; i<n_dati ; i++) { printf ("%d ", dati[i]); } printf("\n"); } Nota: è possibile ottimizzare il programma? (Come funzionava l'algoritmo implementato in assembler?) Da svolgere in autonomia Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 36 C/ripasso – Nuova struttura di controllo: switch Si introduce, per gli esercizi seguenti, uno nuovo tipo di struttura di controllo: l'istruzione switch. E' costituita da: ➢ ➢ ➢ la parola chiave switch seguita da un'espressione tra () seguita da una sequenza di istruzioni case racchiuse tra “{}” ognuna delle quali è costituita dalla parola chiave case seguita da un'espressione costante, seguita dai “:”, seguita da una serie di istruzioni e terminata da una istruzione break. In genere viene fornito un case di default indicato appunto dalla keyword default. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 37 C/6: promozioni - Problema Si vuole realizzare in linguaggio C un programma in grado di chiedere all'utente di inserire una serie di nomi di persone, i quali vengono considerati ufficiali dell'esercito. Le persone partono tutte dal grado minimo di “sottotenente”, e l'utente può poi scegliere se promuoverli (fino al grado massimo di “tenente generale”) o degradarli. Se l'utente chiede di degradare una persona che è sottotenente, o di promuovere una persona che è tenente generale, viene segnalato un errore, perché si è arrivati ai limiti della scala gerarchica. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 38 C/6: promozioni - Codice sorgente /1 /* Il programma chiede all'utente di inserire una serie di nomi di persone, i quali vengono considerati ufficiali dell'esercito. Le persone partono tutte dal grado minimo di "sottotenente", e l'utente può poi scegliere se promuoverli (fino al grado massimo di "tenente generale") o degradarli. Se l'utente chiede di degradare una persona che è sottotenente, o di promuovere una persona che è tenente generale, viene segnalato un errore, perché si è arrivati ai limiti della scala gerarchica. */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 39 C/6: promozioni - Codice sorgente /2 #include <stdio.h> /* L'elenco dei gradi possibili viene rappresentato da un tipo 'enum', i cui identificatori sono le abbreviazioni dei gradi. Definendo un tipo 'enum' si definisce automaticamente anche l'ORDINAMENTO dei gradi (grazie alla corrispondenza enum <-> int), per cui 'sten' è minore di 'ten' (in effetti 'sten' corrisponde al numero 0, 'ten' al numero 1, etc.) */ typedef enum{sten, ten, cap, magg, ten_col, col, brig_gen, magg_gen, ten_gen} tipo_gradi; #define N_GRADI 9 #define MAX_LUNGH_NOMI 100 #define MAX_N_PERSONE 50 Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 40 C/6: promozioni - Codice sorgente /3 main() { /* L'array 'nome_gradi' è un array di stringhe di caratteri (quindi un array doppio di char) che contiene il nome per esteso dei gradi possibili. Poiché i nomi per esteso sono fissi, l'array è definito costante (grazie alla parola chiave 'const' prima della dichiarazione), e viene inizializzato con i nomi (costanti) alla dichiarazione (l'unico punto in cui è possibile assegnare dei valori a una variabile dichiarata 'const'). La corrispondenza tra identificatore del tipo 'enum' e nome per esteso viene fatta ancora una volta sfruttando la corrispondenza tra enum e int. Per esempio, 'sten', come detto in precedenza, corrisponde al numero 0, e la parola contenuta nell'elemento 0 dell'array 'nome_gradi' è in effetti "sottotenente". E' per esempio possibile scrivere direttamente nome_gradi[sten], che restituisce il valore "sottotenente". */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 41 C/6: promozioni - Codice sorgente /4 const char nome_gradi[N_GRADI][30] = { "sottotenente", "tenente", "capitano", "maggiore", "tenente colonnello", "colonnello", "brigadier generale", "maggior generale", "tenente generale"}; tipo_gradi gradi[MAX_N_PERSONE]; char persone[MAX_N_PERSONE][MAX_LUNGH_NOMI]; char op; int n_pers, i, pers_corr; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 42 C/6: promozioni - Codice sorgente /5 do { printf ("Inserire il numero di persone graduate (max %d): ", MAX_N_PERSONE); scanf ("%d", &n_pers); } while (n_pers<1 || n_pers>MAX_N_PERSONE); /* Leggere uno per volta, da standard input, i nomi delle persone, e inizializzare man mano il grado di tutte le persone inserite al grado di sottotenente */ for (i=0 ; i<n_pers ; i++) { printf ("Persona n. %d (senza spazi): ", i+1); scanf ("%s", &persone[i][0]); gradi[i] = sten; } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 43 C/6: promozioni - Codice sorgente /6 do { /* Stampare tutte le persone inserite con a fianco il grado */ printf ("\n********************************************\n"); for (i=0 ; i<n_pers ; i++) { printf ("%d) %s: %s\n", i+1, persone[i], nome_gradi[gradi[i]]); } printf ("\nScegliere la persona da promuovere/degradare\n"); printf ("(da 1 a %d, 0 per terminare): ", n_pers); scanf ("%d", &pers_corr); /* Se è stata selezionata una persona valida, chiedere prima se deve essere promossa o degradata, e quindi eseguire l'operazione, verificando che sia possibile (per esempio non è possibile degradare un sottotenente e non è possibile promuovere un tenente generale) */ if (pers_corr >= 1 && pers_corr <= n_pers) { printf ("Scegliere P per promuovere o D per degradare: "); scanf (" %c", &op); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 44 C/6: promozioni - Codice sorgente /7 switch (op) { case 'P': if (gradi[pers_corr-1] != ten_gen) { gradi[pers_corr-1] = gradi[pers_corr-1] + 1; } else { printf ("\n####Non è possibile promuovere un tenente generale!!!!!####\n"); } break; case 'D': if (gradi[pers_corr-1] != sten) { gradi[pers_corr-1] = gradi[pers_corr-1] - 1; } else { printf ("\n####Non è possibile degradare un sottotenente!!!!!####\n"); } break; default: printf ("\n####Operazione richiesta errata!!!!!!####\n"); break; } } } while (pers_corr != 0); } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 45 C/6.1: promozioni – Versione alternativa Si vuole realizzare in linguaggio C lo stesso programma realizzato in precedenza, utilizzando un array di struct invece che 2 array separati per contenere i dati delle persone. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 46 C/6.1: promozioni - Codice sorgente /1 /* Questa versione del programma 'promozioni' usa un array di di struct invece che 2 array separati per contenere i dati delle persone. */ #include <stdio.h> typedef enum {sten, ten, cap, magg, ten_col, col, brig_gen, magg_gen, ten_gen} tipo_gradi; #define N_GRADI 9 #define MAX_LUNGH_NOMI 100 #define MAX_N_PERSONE 50 Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 47 C/6.1: promozioni - Codice sorgente /2 /* Invece di utilizzare 2 array separati per rappresentare i dati delle persone, in questa versione del programma useremo un array di struct. Ogni struct conterrà i dati (nome, grado) di una singola persona. */ typedef struct { char nome[MAX_LUNGH_NOMI]; tipo_gradi grado; } dati_uff; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 48 C/6.1: promozioni - Codice sorgente /3 main() { const char nome_gradi[N_GRADI][30] = { "sottotenente", "tenente", "capitano", "maggiore", "tenente colonnello", "colonnello", "brigadier generale", "maggior generale", "tenente generale"}; /* Invece di avere due array separati "gradi" e "persone" si utilizzerà un solo array "persone", che è un array di struct. */ dati_uff persone[MAX_N_PERSONE]; char op; int n_pers, i, pers_corr; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 49 C/6.1: promozioni - Codice sorgente /4 do { printf ("Inserire il numero di persone graduate (max %d): ", MAX_N_PERSONE); scanf ("%d", &n_pers); } while (n_pers<1 || n_pers>MAX_N_PERSONE); /* Leggere uno per volta, da standard input, i nomi delle persone, e inizializzare il grado di tutte le persone inserite a sottotenente */ for (i=0 ; i<n_pers ; i++) { printf ("Persona n. %d (senza spazi): ", i+1); scanf ("%s", &persone[i].nome[0]); persone[i].grado = sten; /* laddove in promozioni.c si usava 'gradi[i]', qui occorre fare riferimento al campo 'grado' dell'elemento 'i', e quindi scrivere persone[i].grado Allo stresso modo il nome di ogni persona è contenuto nel campo 'nome' di ogni elemento i dell'array "persone": persone[i].nome */ } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 50 C/6.1: promozioni - Codice sorgente /5 do { /* Stampare tutte le persone inserite con a fianco il grado */ printf ("\n********************************************\n"); for (i=0 ; i<n_pers ; i++) { printf ("%d) %s: %s\n", i+1, persone[i].nome, nome_gradi[persone[i].grado]); } printf ("\nScegliere la persona da promuovere/degradare\n"); printf ("(da 1 a %d, 0 per terminare): ", n_pers); scanf ("%d", &pers_corr); /* Se è stata selezionata una persona valida, chiedere prima se si deve promuovere o degradare, e quindi eseguire l'operazione, verificando che sia possibile (per esempio non è possibile degradare un sottotenente e non è possibile promuovere un tenente generale) */ if (pers_corr >= 1 && pers_corr <= n_pers) { printf ("Scegliere P per promuovere o D per degradare: "); scanf (" %c", &op); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 51 C/6.1: promozioni - Codice sorgente /6 switch (op) { case 'P': if (persone[pers_corr-1].grado != ten_gen) { persone[pers_corr-1].grado += 1; } else { printf ("\n####Non puoi promuovere un tenente generale!!!!!####\n"); } break; case 'D': if (persone[pers_corr-1].grado != sten) { persone[pers_corr-1].grado -= 1; } else { printf ("\n####Non puoi degradare un sottotenente!!!!!####\n"); } break; default: printf ("\n####Operazione richiesta errata!!!!!!####\n"); break; } } } while (pers_corr != 0); } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 52 C/FAQ + feedback /1 ➢ Formattazione/indentazione del codice Si sottolinea ancora una volta che è importantissimo scrivere il codice sorgente ben formattato e ben indentato al fine di facilitarne la comprensione e il debugging for (espr1; espr2; espr3) { istruzione; istruzione; istruzione; } if (espressione) { istruzione; istruzione; istruzione; } else { istruzione; istruzione; istruzione; } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 53 C/FAQ + feedback /2 ➢ Formattazione/indentazione del codice Fare molta attenzione ai casi di ambiguità... if (n >= 0) if (n >= 0) for (i=0; i<n; i++) for (i=0; i<n; i++) if (s[i] > 0) { if (s[i] > 0) { printf (“....”); printf (“....”); } } else else printf (“n è negativo”); printf (“n è negativo”); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 54 C/FAQ + feedback /3 ➢ ➢ ➢ ➢ Chiusura delle parentesi Verificare che tutte le parentesi aperte siano anche chiuse... Chiusura del file sorgente Verificare che alla fine del codice sorgente (dopo l'ultima riga) sia inserito un “new line” (è comunque un warning...) Inizializzazione variabili Assicurarsi che le variabili, prima del loro utilizzo, abbiano un valore congruente all'uso che se ne intende fare Confronti corretti No: if ( a < b < c ) No: if ( a = b ) Si: Si: if ( a < b && b < c ) if ( a == b ) Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 55 C/FAQ + feedback /4 ➢ Utilizzo corretto della struttura di controllo IF ELSE Utilizzare correttamente i controlli in cascata Utilizzo SBAGLIATO Utilizzo CORRETTO if (espressione) { istruzione; istruzione; istruzione; } else { istruzione; istruzione; istruzione; } else { istruzione; istruzione; istruzione; } if (espressione) { istruzione; istruzione; istruzione; } else if (espressione) { istruzione; istruzione; istruzione; } else { istruzione; istruzione; istruzione; } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 56 C/7: bubblesort 2 – ordinamento di date - Problema Si vuole realizzare in linguaggio C un programma in grado di ordinare un array di date (invece che, come nell'esempio svolto in aula, un array di interi). Ogni data dovrà essere rappresentata da un'apposita struttura con giorno, mese e anno Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 57 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /1 /* Questa versione del 'bubblesort' invece che ordinare un array di interi, ordina un array di date. Ogni data è rappresentata da una struttura con giorno, mese e anno */ #include <stdio.h> typedef enum {false, true} bool; /* Consideriamo solo gli anni DOPO CRISTO, per questo il campo anno è unsigned e non c'è nessuna specifica AC o BC. */ typedef struct { unsigned short giorno; unsigned short mese; unsigned int anno; } tipo_data; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 58 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /2 /* Si sarebbe potuto anche definire il campo mese in modo diverso, con un enum del tipo typedef enum { gen, feb, mar, apr, mag, giu, lug, ago, set, ott, nov, dic } tipo_mese; e poi dichiarando nella struct tipo_mese mese; */ non sarebbe cambiato molto, perché questo tipo di formulazione sarebbe stata equivalente a dichiarare, per come il C tratta i tipi enum, che 'tipo_mese' in realtà assumeva valori tra 0 e 11 (NON tra 1 e 12, ATTENZIONE! ci sarebbe stato un problema di disallineamento con il senso comune con cui vengono rappresentati i mesi) Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 59 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /3 #define MAX_DATI 100 main() { tipo_data dati[MAX_DATI]; tipo_data dato_corr, temp; int i, n_dati; bool ordinato = false; /* Leggo i dati dallo standard input; la lettura termina quando l'utente inserisce uno 0. */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 60 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /4 i = 0; do { printf ("Inserire data n. %d nel formato \"gg/mm/aaaa\"\n", i+1); printf ("(max %d dati, 0 per terminare): ", MAX_DATI); scanf (" %hu/%hu/%u", &dato_corr.giorno, &dato_corr.mese, &dato_corr.anno); /* Alla scanf viene data una sequenza di caratteri che identifica il formato in cui la scanf si aspetta che l'utente immetta i dati. In questo caso la scanf si aspetta che l'utente immetta: */ <unsigned short>/<unsigned short>/<unsigned int> if (dato_corr.giorno != 0) { dati[i].giorno = dato_corr.giorno; dati[i].mese = dato_corr.mese; dati[i].anno = dato_corr.anno; i++; } } while (i<MAX_DATI && dato_corr.giorno != 0); n_dati = i; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 61 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /5 /* Si noti che non viene fatta nessuna verifica che la data sia valida (anche una data chiaramente sbagliata come 45/23/2000 viene accettata: per esercizio si aggiunga una parte di codice in grado di eseguire questo tipo di controllo) */ Nota: da svolgere in autonomia while (ordinato == false) { ordinato = true; for ( i=0 ; i<n_dati-1 ; i++ ) { /* Per verificare che una data sia maggiore/minore di un'altra occorre fare una verifica campo per campo, prima sugli anni poi, se gli anni sono uguali, sui mesi e, se sia gli anni che i mesi sono uguali, sui giorni. */ if ( dati[i].anno > dati[i+1].anno || (dati[i].anno == dati[i+1].anno && dati[i].mese > dati[i+1].mese) || (dati[i].anno == dati[i+1].anno && dati[i].mese == dati[i+1].mese && dati[i].giorno > dati[i+1].giorno) ) { Nota: da svolgere in autonomia (gestione di date uguali) Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 62 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /6 /* Si assegnano le variabili (di tipo struttura) campo per campo. */ temp.giorno = dati[i].giorno; temp.mese = dati[i].mese; temp.anno = dati[i].anno; dati[i].giorno = dati[i+1].giorno; dati[i].mese = dati[i+1].mese; dati[i].anno = dati[i+1].anno; dati[i+1].giorno = temp.giorno; dati[i+1].mese = temp.mese; dati[i+1].anno = temp.anno; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 63 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /7 /* Notare che è possibile, con le strutture, scrivere assegnamenti tra le strutture intere e non serve, come per gli array, farlo elemento per elemento. L'assegnamento precedente si può dunque scrivere, in modo più compatto (ed anche più leggibile; tra l'altro non si rischia, con l'assegnamento globale, di dimenticare di assegnare dei campi): dati[i] = dato_corr; */ Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 64 C/7: bubblesort 2 – ordinamento di date – Codice sorgente /8 ordinato = false; } } } /* Stampo l'array ordinato */ printf ("I valori ordinati in ordine crescente sono:\n\n"); for (i=0 ; i<n_dati ; i++) { printf ("%hu/%hu/%u\n", dati[i].giorno, dati[i].mese, dati[i].anno); } printf ("\n"); } /* Variante: come esercizio si può provare a fare l'ordinamento di elementi che rappresentano il gruppo data/ora */ Nota: da svolgere in autonomia Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 65 C/8: Numeri complessi - Problema Si vuole realizzare un programma che acquisisca in input due numeri complessi (definiti da parte reale e parte immaginaria) e ne faccia somma, sottrazione, moltiplicazione e divisione. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 66 C/8: Numeri complessi – Codice sorgente/1 /* Il programma prende in input due numeri complessi (definiti da parte reale e parte immaginaria) e ne fa somma, sottrazione, moltiplicazione e divisione */ #include <stdio.h> /* In modo molto naturale un tipo "numero complesso" è definito tramite una struttura che contiene 2 campi, uno per la parte reale e uno per la parte immaginaria del numero */ typedef struct { double re; double im; } complex; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 67 C/8: Numeri complessi – Codice sorgente/2 main() { complex n1, n2, sum, sub, mul, div; printf ("Primo numero, parte reale: "); scanf ("%lf", &n1.re); printf ("Primo numero, parte immaginaria: "); scanf ("%lf", &n1.im); printf ("Secondo numero, parte reale: "); scanf ("%lf", &n2.re); printf ("Secondo numero, parte immaginaria: "); scanf ("%lf", &n2.im); sum.re = n1.re + n2.re; sum.im = n1.im + n2.im; sub.re = n1.re - n2.re; sub.im = n1.im - n2.im; mul.re = n1.re*n2.re - n1.im*n2.im; mul.im = n1.im*n2.re + n1.re*n2.im; div.re = (n1.re*n2.re + n1.im*n2.im)/(n2.re*n2.re + n2.im*n2.im); div.im = (n1.im*n2.re - n1.re*n2.im)/(n2.re*n2.re + n2.im*n2.im); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 68 C/8: Numeri complessi – Codice sorgente/3 /* Per stampare i risultati a video uso una serie di 'if' perché devo stampare il carattere '+' nel caso in cui la parte immaginaria sia positiva (il carattere '-' di un numero negativo viene automaticamente stampato, ma il '+' di un numero positivo no!) printf ("\n"); if (sum.im < 0) printf ("Somma = %lf %lfi\n", sum.re, sum.im); else printf ("Somma = %lf +%lfi\n", sum.re, sum.im); if (sub.im < 0) printf ("Sottrazione = %lf %lfi\n", sub.re, sub.im); else printf ("Sottrazione = %lf +%lfi\n", sub.re, sub.im); if (mul.im < 0) printf ("Moltiplica else printf ("Moltiplica } if (div.im < 0) printf ("Divisione else printf ("Divisione = %lf %lfi\n", mul.re, mul.im); = %lf +%lfi\n", mul.re, mul.im); = %lf %lfi\n", div.re, div.im); = %lf +%lfi\n", div.re, div.im); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 69 */ C/ripasso: Il costrutto “?:” Si tratta di una versione molto compatta del costrutto IF-ELSE. Nel costrutto <condizione> ? <ramo then> : <ramo else> viene valutata la condizione, e poi viene restituito il valore del ramo then o del ramo else a seconda del risultato della condizione. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 70 C/8.1: Numeri complessi con “?:” - Problema Si vuole realizzare un programma che acquisisca in input due numeri complessi (definiti da parte reale e parte immaginaria) e ne faccia somma, sottrazione, moltiplicazione e divisione. Rispetto alla versione precedente utilizzare il costrutto “?:” al posto degli if Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 71 C/8.1: Numeri complessi con “?:” – Codice sorgente /1 /* Il programma prende in input due numeri complessi (definiti da parte reale e parte immaginaria) e ne fa somma, sottrazione, moltiplicazione e divisione L'unica differenza con la versione precedente del programma è nel modo in cui vengono stampati i numeri alla fine, per i quali viene usata, invece che la catena di if vista in precedenza, una forma più compatta, basata sul costrutto '?:' */ #include <stdio.h> /* In modo molto naturale un tipo "numero complesso" è definito tramite una struttura che contiene 2 campi, uno per la parte reale e uno per la parte immaginaria del numero */ typedef struct { double re; double im; } complex; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 72 C/8.1: Numeri complessi con “?:” – Codice sorgente /2 main() { complex n1, n2, sum, sub, mul, div; printf ("Primo numero, parte reale: "); scanf ("%lf", &n1.re); printf ("Primo numero, parte immaginaria: "); scanf ("%lf", &n1.im); printf ("Secondo numero, parte reale: "); scanf ("%lf", &n2.re); printf ("Secondo numero, parte immaginaria: "); scanf ("%lf", &n2.im); sum.re = n1.re + n2.re; sum.im = n1.im + n2.im; sub.re = n1.re - n2.re; sub.im = n1.im - n2.im; mul.re = n1.re*n2.re - n1.im*n2.im; mul.im = n1.im*n2.re + n1.re*n2.im; div.re = (n1.re*n2.re + n1.im*n2.im)/(n2.re*n2.re + n2.im*n2.im); div.im = (n1.im*n2.re - n1.re*n2.im)/(n2.re*n2.re + n2.im*n2.im); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 73 C/8.1: Numeri complessi con “?:” – Codice sorgente /3 /* La parte di scrittura a video dei risultati si può anche scrivere in questo modo molto compatto (il carattere '\000' è il carattere nullo, di fatto non si stampa niente, neanche lo spazio) Nel costrutto <condizione> ? <ramo then> : <ramo else> */ viene valutata la condizione, e poi viene restituito il valore del ramo then o del ramo else a seconda del risultato della condizione. printf printf printf printf printf ("\n"); ("Somma ("Sottr. ("Molt. ("Divis. = = = = %lf %lf %lf %lf %c%lfi\n", %c%lfi\n", %c%lfi\n", %c%lfi\n", sum.re, sub.re, mul.re, div.re, sum.im sub.im mul.im div.im < < < < 0 0 0 0 ? ? ? ? '\000' '\000' '\000' '\000' : : : : '+', '+', '+', '+', sum.im); sub.im); mul.im); div.im); } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 74 C/9: assegnamento array - Problema Si vuole realizzare un programma che dati due array copi l'intero contenuto di un array nell'altro. Nota: si vuole verificare una incongruenza del linguaggio C che permette questo tipo di operazione solo se gli array sono contenuti in una struttura ma non permette un assegnamento diretto tra gli array. Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 75 C/9: assegnamento array – Codice sorgente/1 /* Questo programma mostra come sia possibile assegnare strutture intere anche se queste contengono degli array, mentre non sia possibile assegnare array interi che non siano dentro strutture. */ #include <stdio.h> typedef int tipo_arr[10]; typedef struct { tipo_arr a; } tipo_s; main() { int i; tipo_arr a1, a2; tipo_s s1, s2; for (i=0 ; i<10 ; i++) { a1[i] = i; a2[i] = 2*i; s1.a[i] = -i; s2.a[i] = -i*2; } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 76 C/9: assegnamento array – Codice sorgente/2 /* Prima dell'assegnamento */ printf ("\nPrima dell'assegnamento:\n"); printf ("s1.a s2.a\n"); for ( i=0 ; i<10 ; i++ ) { printf ("%d %d\n", s1.a[i], s2.a[i]); } /* Non valido!!!! a1 = a2; */ /* Questo però è valido!!!! */ s1 = s2; /* Dopo l'assegnamento */ printf ("\nDopo l'assegnamento:\n"); printf ("s1.a s2.a\n"); for ( i=0 ; i<10 ; i++ ) { printf ("%d %d\n", s1.a[i], s2.a[i]); } } Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 77 C/ripasso: i puntatori /1 Si è già visto che a una variabile corrisponde un nome, una locazione di memoria e l'indirizzo della locazione di memoria L'operatore &, già utilizzato con la scanf, ritorna l'indirizzo di memoria di una variabile (&b è un'espressione il cui valore è l'indirizzo di memoria della variabile b) Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 78 C/ripasso: i puntatori /2 Un indirizzo può essere assegnato solo a un particolare tipo di variabile (detta variabile derivata): i puntatori. I puntatori vengono definiti nel seguente modo: tipoVariabile *variabilePuntatore; in pratica variabilePuntatore viene utilizzata per memorizzare l'indirizzo di variabili di tipo tipoVariabile Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 79 C/ripasso: i puntatori /3 L'operatore unario *, detto operatore di indirezione, viene applicato a una variabile di tipo puntatore per accedere al contenuto dell'oggetto puntato. int a; int *pi; // a è definita come intero // pi è definita come puntatore a // intero pi = &a; // il valore di pi è l'indirizzo di // memoria in cui è memorizzata a // Nota: a e *pi sono ora “legati” a = 10; printf (“Valore di a = %d\n”, a); printf (“Valore di *pi = %d\n”, *pi); Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 80 C/ripasso: i puntatori /4 Esempi: int x = 1; y = 2; z[10]; int *ip; // ip è un puntatore a un intero ip = &x; y = *ip; // ora ip punta a x // ora y vale... // 1 // ora x vale... // 0 // ora ip punta a... // z[0] *ip = 0; ip = &z[0]; Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 81 C/nota: il primo compitino si avvicina... ✔ ✔ ✔ Testare tutti gli esempi fatti nelle esercitazioni e inserire delle varianti Provare i compitini degli anni precedenti http://www.cremona.polimi.it/info1 Per problemi/dubbi/chiarimenti: [email protected] Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected] 82