4-C-16-17-Istruzioni di ciclo - Università di Romasalza/FI-C/4-C-16-17.pdf · •Istruzione while...
Transcript of 4-C-16-17-Istruzioni di ciclo - Università di Romasalza/FI-C/4-C-16-17.pdf · •Istruzione while...
Corso di Fondamenti di InformaticaIngegneria delle Comunicazioni – BCORIngegneria Elettronica – BELR
Introduzione al C
Unità 4 – Istruzioni di ciclo
D. Bloisi, S. Peluso, A. Pennisi, S. Salza
Pagina 22016/2017Unità 4 - Istruzioni di ciclo
Sommario –Unità 4
• Ripetizione di istruzioni• Istruzione while• Ciclo di lettura• Schemi di ciclo• Istruzione for• Istruzione do• Cicli annidati• Istruzioni di controllo del flusso
Pagina 32016/2017Unità 4 - Istruzioni di ciclo
Istruzioni di controllo del flussoFinora abbiamo visto diversi tipi di istruzioni (senza contare le dichiarazioni):• Istruzioni semplici:
– invocazione di funzioni– istruzioni semplici, ovvero assegnazione o uso di un
operatore di incremento/decremento seguito da ";"– istruzioni di uscita (break e return)
• Istruzioni composte (o strutturate)– blocco di istruzioni ({})– istruzioni condizionali (if-else, if, switch)
Pagina 42016/2017Unità 4 - Istruzioni di ciclo
Ripetizione di istruzioni• Un altro costrutto fondamentale, presente in tutti i
linguaggi di programmazione, è costituito dalla ripetizione di singole istruzioni o di blocchi di istruzioni
• Si parla allora di cicli, e il blocco di istruzioni che viene ripetuto è detto corpo del ciclo
• L'esecuzione di un ciclo conta nella ripetizione dell'esecuzione del corpo del ciclo
• La ripetizione è governata da una condizione, che viene valutata ad ogni iterazione e che permette di stabilire quando terminarla
Pagina 52016/2017Unità 4 - Istruzioni di ciclo
Cicli definiti ed indefiniti• Solo in alcuni casi il numero di iterazioni (ripetizioni)
è noto a priori, cioè all'inizio del ciclo• In genere la terminazione dipende da una condizione
di uscita, che a sua volta dipende dai valori calcolati durante l'iterazione del ciclo
• In altri casi può dipende da eventi esterni, ad esempio un input fornita dall'utente
• Distinguiamo due tipi di ciclo:- cicli definiti nei quali il numero di iterazioni è noto
prima di iniziare l'esecuzione del ciclo- cicli indefiniti nei quali l'uscita dal ciclo dipende da
valori calcolati (o acquisiti) nel corpo del ciclo
Pagina 62016/2017Unità 4 - Istruzioni di ciclo
Esempi
CICLO DEFINITO- Ripeti per 10 volte un determinato blocco di
istruzioni
CICLO INDEFINITO- Continua a dividere n per 2 finché il quoziente q
diventa < 2- Continua a leggere da tastiera un numero intero
finché non viene fornito un valore > 0
Pagina 72016/2017Unità 4 - Istruzioni di ciclo
Ciclo while
L’istruzione while consente la ripetizione di una istruzione, controllandola con una condizione
SINTASSIwhile(condizione)
istruzione
• condizione è un’espressione• istruzione (detta anche il corpo del ciclo) è una
singola istruzione o un blocco di istruzioni
Pagina 82016/2017Unità 4 - Istruzioni di ciclo
Semantica del ciclo while
1. La condizione è valutata prima di ogni iterazione
2. Se la condizione è vera, allora l’istruzione è eseguita
3. Successivamente si ritorna sulla valutazione della condizione, procedendo così fino a quando la condizione risulta falsa
4. Si passa poi all'esecuzione dell’istruzione successiva al ciclo while
N.B. Il ciclo può anche non essere eseguito nemmeno una volta se la condizione risulta già falsa al primo giro
Pagina 92016/2017Unità 4 - Istruzioni di ciclo
Esempio
Stampa di 100 asterischi (ciclo definito)
int i = 0;while (i < 100) {
printf("*");i++;
}
N.B. Per garantire l'uscita dal ciclo, la condizione deve sempre dipendere da valori che vengono modificati durante l'esecuzione del corpo del ciclo (nell'esempio i)
Pagina 102016/2017Unità 4 - Istruzioni di ciclo
Diagramma di flusso
while(condizione){istruzione-1…istruzione-n
}istruzione-n+1
condizione
istruzione-n+1
istruzione-1...
istruzione-n
VERO
FALSO
Pagina 112016/2017Unità 4 - Istruzioni di ciclo
Esempio: ciclo while di lettura
#include <stdio.h>
int main() {int c;c = getchar();while (c != EOF) {
putchar(c);c = getchar();
}return 0;
}
Legge e stampa su video una sequenza di caratteri
CICLO INDEFINITO• Le iterazioni terminano solo
quando viene letto il carattere EOF (End Of File)
• Su Windows EOF è CTRL+Z• Su Mac EOF è CTRL+Z• Su Unix EOF è CTRL+D
Pagina 122016/2017Unità 4 - Istruzioni di ciclo
Funzione getchar• Legge il prossimo carattere dallo standard input
e lo restituisce come valore intero
int getchar(void);
• Il carattere letto è restituito come int
• Se si raggiunge la fine del file viene letto il carattere EOF (End Of File)
• Viene allora riscontrato un errore in lettura, la funzione ritorna il valore della costante simbolica di tipo int EOF (che generalmente vale -1) definita in stdio.h
Pagina 132016/2017Unità 4 - Istruzioni di ciclo
Funzione putchar
• Visualizza sullo standard output il carattere immagazzinato in c
int putchar(int c);
• Se non ci sono errori, lo stesso carattere c stampato viene restituito
• Se si verifica un errore, viene restituito EOF
Pagina 142016/2017Unità 4 - Istruzioni di ciclo
Esempio: ciclo while di lettura (bis)
#include <stdio.h>
int main() {int c;while ((c = getchar()) != EOF) {
putchar(c);}
return 0;}
Versione alternativa
N.B. Si noti il side-effect (chiamata della funzione nella condizione. Più compatto, ma meno chiaro.
Pagina 152016/2017Unità 4 - Istruzioni di ciclo
Esempio di esecuzione
Pagina 162016/2017Unità 4 - Istruzioni di ciclo
EsempioPerciascunaletturastampaildoppiodelvalorelettoininput
#include <stdio.h>
int main() {int c, dato;c = scanf("%d", &dato);while (c! = EOF) {
dato *= 2;printf("%d\n", dato);c = scanf("%d", &dato);
}return 0;
}
Pagina 172016/2017Unità 4 - Istruzioni di ciclo
Esempio: divisione con sottrazioni#include <stdio.h>int main() {
int dividendo, divisore, quoziente, resto;printf("dividendo: "); scanf("%d", ÷ndo);printf("divisore: "); scanf("%d", &divisore);quoziente = 0;resto = dividendo;while (resto >= divisore) {
resto -= divisore;quoziente++;
}printf("quoziente = %d\n", quoziente);printf("resto= %d\n", resto);return 0;
}
Pagina 182016/2017Unità 4 - Istruzioni di ciclo
Potenza con moltiplicazioni #include <stdio.h>
int main() {int base, esp, potenza, o_esp;printf("base: "); scanf("%d", &base);printf("esp: "); scanf("%d", &esp);o_esp = esp;potenza = 1;while (esp > 0) {
potenza *= base;esp--;
}printf("%d elevato a %d = %d\n", base, o_esp, potenza);return 0;
}
Pagina 192016/2017Unità 4 - Istruzioni di ciclo
Prodotto con somme#include <stdio.h>
int main() {int m_ando, m_tore, prodotto, o_tore;printf("moltiplicando: "); scanf("%d", &m_ando);printf("moltiplicatore: "); scanf("%d", &m_tore);o_tore = m_tore;prodotto = 0;while (m_tore > 0) {
prodotto += m_ando;m_tore--;
}printf("%d * %d = %d\n", m_ando, o_tore, prodotto);return 0;
}
Pagina 202016/2017Unità 4 - Istruzioni di ciclo
Elementi del ciclo whileAssegnazione del valore delle
variabili utilizzate nel ciclo prima dell’inizio del del ciclo
Espressione valutata prima di ogni iterazione, il cui valore di verità
determina l’esecuzione del corpo del ciclo o la fine del ciclo
Calcolo dei risultati parziali nel corpo del ciclo ad ogni iterazione
Incremento/decremento della variabile che controlla le ripetizioni
del ciclo (nel corpo del ciclo)
inizialiazzazionewhile(condizione) {
operazionepasso successivo
}
Pagina 212016/2017Unità 4 - Istruzioni di ciclo
Terminazione
• Una volta progettato il ciclo occorre verificarne la terminazione
• Occorre, cioè, verificare che l’esecuzione delle istruzioni del ciclo possa modificare il valoredella condizione in modo da renderla falsa
ESEMPIOL'istruzione m_tore--; garantisce che prima o poi la condizione (m_tore > 0) diventerà falsa
Pagina 222016/2017Unità 4 - Istruzioni di ciclo
Errori comuni nei cicli while 1/3
Mancata inizializzazione di una variabile che viene utilizzata nella condizione del cicloint i;while (i != 0) {
printf("%d\n", i);printf("%d\n", i*i);i--;
}
Il valore di i all'inizio del ciclo può essere qualsiasi cosa
Pagina 232016/2017Unità 4 - Istruzioni di ciclo
Errori comuni nei cicli while 2/3
Mancato aggiornamento delle variabili che compaiono nella condizione del ciclo
int i, num;printf("Digita un intero:"); i = scanf("%d", &num);while (i != EOF) {
printf("%d ^ 2 = %d\n", num, num * num);scanf("%d", num);
}
Il valore di i non cambia e non si esce mai dal ciclo
Pagina 242016/2017Unità 4 - Istruzioni di ciclo
Errori comuni nei cicli while 3/3
Numero di iterazioni errato (in genere di una unità)
// Stampa 10 asterischiint i = 0;while (i <= 10) {
printf("*");i++;
}
La condizione corretta sarebbe dovuta essere i < 10 ; così si stampano 11 asterischi
Pagina 252016/2017Unità 4 - Istruzioni di ciclo
Schemi tipici di ciclo
Molti cicli rientrano in uno di questi tre schemi
• contatore: conta il numero di valori in un insieme
• accumulatore: accumula i valori di un insieme• valore caratteristico : determina un valore
caratteristico tra i valori in un insieme (ad esempio, il massimo, quando sui valori dell'insieme e definito un ordinamento)
Pagina 262016/2017Unità 4 - Istruzioni di ciclo
Contatore: numero di interi in input
int n, i;int conta = 0;printf("Digita un intero: "); i = scanf("%d", &n);while (i != EOF) {
conta++;printf("ho letto %d\n", n);printf("Digita un intero: "); i = scanf("%d", &n);
}printf("\nHo letto in tutto %d interi\n", conta);
Pagina 272016/2017Unità 4 - Istruzioni di ciclo
Contatore: numero di interi positiviint n, i;int conta = 0;printf("Digita un intero: "); i = scanf("%d", &n);while (i != EOF) {
if (d > 0) conta++;printf("ho letto %d\n", n);printf("Digita un intero: "); i = scanf("%d", &n);
}printf("\nHo letto in tutto %d interi positivi\n",
conta);
Pagina 282016/2017Unità 4 - Istruzioni di ciclo
Accumulatore: somma di interiint n, i;int somma = 0;printf("Digita un intero: "); i = scanf("%d", &n);while (i != EOF) {
somma += n;printf("ho letto %d\n", n);printf("Digita un intero: "); i = scanf("%d", &n);
}printf("\nSomma totale = %d\n", somma);
Pagina 292016/2017Unità 4 - Istruzioni di ciclo
Accumulatore: prodotto di interiint n, i;int prodotto = 1;printf("Digita un intero: "); i = scanf("%d", &n);while (i != EOF) {
prodotto *= n;printf("ho letto %d\n", n);printf("Digita un intero: "); i = scanf("%d", &n);
}printf("\nProdotto totale = %d\n", prodotto);
Pagina 302016/2017Unità 4 - Istruzioni di ciclo
Massimo di un insieme delimitato
// Massimo di un insieme di interi positiviint max = 0, n, i; // massimo correnteprintf("Digita un intero: "); i = scanf("%d", &n);while (i != EOF) {
if (n > max) max = n;printf("Digita un intero: "); i = scanf("%d", &n);
}if (max = 0) printf("\nInsieme di valori vuoto\n");
else printf("\nMassimo valore letto =%d\n", max);
Pagina 312016/2017Unità 4 - Istruzioni di ciclo
Massimo di un insieme non vuoto
// Massimo di un insieme non vuoto di interiint max, n, i; // massimo correnteprintf("Digita un intero: "); i = scanf("%d", &n);max = n;while (i != EOF) {
if (n > max) max = n;printf("Digita un intero: "); i = scanf("%d", &n);
}printf("\nMassimo valore letto =%d\n", max);
Pagina 322016/2017Unità 4 - Istruzioni di ciclo
Massimo nel caso generale// Massimo di un insieme anche vuoto di interi + e -int max = 0, n, i; // massimo correnteprintf("Digita un intero: "); i = scanf("%d", &n);if (i == EOF) printf(\nInsieme di valori vuoto\n");else {
max = n;while (i != EOF) {
if (n > max) max = n;printf("Digita un intero: "); i = scanf("%d", &n);
}printf("\nMassimo =%d\n", max);
}
Pagina 332016/2017Unità 4 - Istruzioni di ciclo
Istruzioni di ciclo
• Il C offre tre forme diverse di istruzioni di ciclo
• istruzione while
• istruzione for
• istruzione do-while
• La struttura while è la più generale, e consente di esprimere qualsiasi ciclo esprimibile con for e do
• Ma in alcune situazioni è più conveniente codificare un algoritmo utilizzando gli altri tipi di ciclo, soprattutto per motivi di chiarezza e leggibilità
Pagina 342016/2017Unità 4 - Istruzioni di ciclo
Ciclo while controllato da un contatoreUna situazione comune di utilizzo dei cicli è quella in cui il ciclo fa uso di una variabile (detta di controllo) che ad ogni iterazione varia di un valore costante, ed il cui valore determina la fine del ciclo
int i = 1;while (i <= 10) {
printf("%d\n",i * i);i++;
}
variabile di controllo i
inizializzazione
incremento /decremento
verifica
Pagina 352016/2017Unità 4 - Istruzioni di ciclo
Ciclo for controllato da un contatore
int i;for(i = 1; i <= 10; i++ )printf("%d\n", i * i)
variabile di controllo i
inizializzazioneincremento /decremento
verifica
L’istruzione di ciclo for è particolarmente adatta ad esprimere situazioni in cui si controlla un ciclo con un contatore
Pagina 362016/2017Unità 4 - Istruzioni di ciclo
Istruzione for: sintassi
for (inizializzazione; condizione;incremento)istruzione ;
• inizializzazione è un’espressione con side-effect che inizializza una variabile di controllo (tipicamente un’assegnazione)
• condizione è un’espressione condizionale• incremento tipicamente consiste nell’incremento
della variabile di controllo• istruzione è una singola istruzione o un blocco di
isytruzioni (detta anche corpo del for)
Pagina 372016/2017Unità 4 - Istruzioni di ciclo
Istruzione for: semantica
for (inizializzazione; condizione; incremento) istruzione ;
è equivalente a:
inizializzazione ; while (condizione) {
istruzione ;incremento ;
}
Pagina 382016/2017Unità 4 - Istruzioni di ciclo
Diagramma di flusso
condizione
istruzione-n+1
istruzione-1...
istruzione-nincremento
VERO
FALSO
inizializzazione
for(inizializzazione;condizione;incremento){
istruzione-1;
...
instruzione-n;
}
istruzione-n+1
Pagina 392016/2017Unità 4 - Istruzioni di ciclo
Osservazioni sul ciclo for 1/3
• Ciascuna delle tre parti del for (inizializzazione,condizione e incremento ) può mancare
• In ogni caso i ; vanno comunque inseriti• Se manca condizione, viene assunta pari al valore 1
cioè è sempre vera
ESEMPIOfor(;i < 100;)
L'esempio ha senso a patto che i venga inizializzato prima di entrare nel for e venga modificato nel corpo del ciclo
Pagina 402016/2017Unità 4 - Istruzioni di ciclo
Osservazioni sul ciclo for 2/3
• La sintassi del for permette che le tre parti siano delle espressioni qualsiasi, purché inizializzazione e incremento siano istruzioni (in particolare, generino un side-effect)
• Nell’uso del ciclo for è però buona norma:– usare le tre parti del for in base al loro significato
originario– far riferimento ad una variabile di controllo– non modificare la variabile di controllo nel
corpo del ciclo
Pagina 412016/2017Unità 4 - Istruzioni di ciclo
Osservazioni sul ciclo for 3/3
• Nel caso generale, inizializzazione e incrementopossono anche essere una sequenza di espressionicon side-effect separate da ","
• Questo consente di inizializzare e/o incrementare più variabili contemporaneamente
• Tuttavia si raccomanda, come sempre, di tener conto della leggibilità del codice, e si sconsiglia il ricorso a numeri da circo
Pagina 422016/2017Unità 4 - Istruzioni di ciclo
Esempi di cicli forIl ciclo for è usato principalmente per realizzare cicli definiti
int i;
• for (i = 1; i <= 10; i++) ...valori assunti da i: 1, 2, 3, ..., 10
• for (i = 10; i >= 1; i--) ...valori assunti da i: 10, 9, 8, ..., 2, 1
• for (i = -4; i <= 4; i = i+2) ...valori assunti da i: -4, -2, 0, 2, 4
• for (i = 0; i >= -10; i = i-3) ...valori assunti da i: 0, -3, -6, -9
Pagina 432016/2017Unità 4 - Istruzioni di ciclo
Esempio: codici ASCII#include <stdio.h>
int main() {int i;printf("\nCarattere \t Codice\n");for (i = 33; i <= 62; i++) {
char c = (char) i;printf(" %c \t \t %d\n", c, i);
}return 0;
}
Stampa i caratteri ASCII con codici tra 33 e 62
Pagina 442016/2017Unità 4 - Istruzioni di ciclo
Esecuzione
Pagina 452016/2017Unità 4 - Istruzioni di ciclo
Istruzione do-while: sintassi
doistruzione
while (condizione);
• condizione è un’espressione che restituisce un valore vero (≠ 0) o falso (0)
• istruzione è un'istruzione (o un blocco di istruzioni) e si indica come corpo del ciclo
Pagina 462016/2017Unità 4 - Istruzioni di ciclo
Istruzione do-while: semantica
doistruzione
while(condizione);
è equivalente a:istruzione; while(condizione)
istruzione;
N.B. La condizione viene valutata alla fine del ciclo e l'istruzione eseguita almeno una volta
Pagina 472016/2017Unità 4 - Istruzioni di ciclo
Esempio
Stampa di 100 asterischi (ciclo definito)
int i = 0;do {
printf("*");i++;
} while (i < 100)
N.B. Per garantire l'uscita dal ciclo, la condizione deve sempre dipendere da valori che vengono modificati durante l'esecuzione del corpo del ciclo (nell'esempio i)
Pagina 482016/2017Unità 4 - Istruzioni di ciclo
Osservazioni sul ciclo do-while
• A differenza del while e del for, nel do-whileil corpo del ciclo viene eseguito almeno una volta.
• Non è, in generale, necessario inizializzare le variabili che compaiono nella condizione prima di iniziare l'esecuzione del ciclo.
• E’ sufficiente che tali variabili vengano inizializzate nel corpo del ciclo stesso.
Pagina 492016/2017Unità 4 - Istruzioni di ciclo
Esempio: somma di interiSomma una sequenza di interi letti da input, e termina quando viene immesso 0#include <stdio.h>int main() {
int i, somma = 0;do {
printf("Digita intero (0 termina):");scanf("%d", &i);somma = somma + i;
} while (i != 0);printf(\nTotale = %d\n\n", somma);return 0;
}
Pagina 502016/2017Unità 4 - Istruzioni di ciclo
Domanda
Cosa stampa il frammento di codice seguente?
int i; do {
i = 0;printf("*"); i++;
} while (i < 100);
Pagina 512016/2017Unità 4 - Istruzioni di ciclo
Buone abitudini• La sintassi del do-while richiede che ci sia un ; dopowhile(condizione)
• Questo evita la confusione con un while, perché nel while il ; dopo la condizione non c'è
• Però potrebbe essere un while con ciclo vuoto…• Quindi per migliorare la leggibilità, e togliere ogni
dubbio è meglio racchiudere il corpo del ciclo in un blocco, anche se è un'istruzione sola
do {istruzione;
} while(condizione);
Pagina 522016/2017Unità 4 - Istruzioni di ciclo
Diagramma di flusso
do {istruzione-1;...instruzione-n;
} while (condizione);istruzione-n+1
condizioneistruzione-n+1
istruzione-1...
istruzione-n
≠ 0 vero
= 0 falso
Pagina 532016/2017Unità 4 - Istruzioni di ciclo
Validazione dell’input
• Spesso è necessario effettuare un controllo dei dati immessi in input (in inglese validation)
• Nel caso in cui l’utente abbia immesso un dato non valido, occorre richiedere l'immissione
• Si insiste nella richiesta fino a che non viene immesso un dato valido
• L'istruzione do-while si presta molto bene a realizzare questo tipo di ciclo
Pagina 542016/2017Unità 4 - Istruzioni di ciclo
Esempio
Scrivere un frammento di programma che legga da input un intero, ripetendo la lettura fino a quando non venga immesso un intero positivo, e restituisca l’interopositivo letto
...int i;do {
printf("Digita un intero > 0:");scanf("%d", &i);
} while (i <= 0);// Ora i contiene un intero positivo
Pagina 552016/2017Unità 4 - Istruzioni di ciclo
Esecuzione
Pagina 562016/2017Unità 4 - Istruzioni di ciclo
Equivalenza tra while e do-whiledo {
printf("Digita un intero > 0:");scanf("%d", &i);
} while (i <= 0);
printf("Digita un intero > 0:");scanf("%d", &i);while (i < 0) {
printf("Digita un intero > 0:");scanf("%d", &i);
}
Equivale a
Pagina 572016/2017Unità 4 - Istruzioni di ciclo
Insieme completo di strutture di controllo
• Due programmi si dicono equivalenti se, eseguiti con gli stessi dati di ingresso:• non terminano entrambi, oppure• terminano entrambi e producono gli stessi risultati
in uscita
• Un insieme di strutture di controllo del flusso si dice completo se per ogni programma nel linguaggio neesiste uno equivalente scritto solo con le strutture di controllo contenute nell'insieme
Pagina 582016/2017Unità 4 - Istruzioni di ciclo
Teorema di Böhm-Jacopini
La sequenza, l'istruzione if-else e l'istruzionewhile formano un insieme di istruzioni completo
È possibile costruire un insieme completo con un numero molto limitato di istruzioni di controllo
N.B. Sequenza è l'elencazione di più istruzioni, una di seguito all'altra perché vengano eseguite in quell'ordine
Quindi con queste istruzioni è possibile scrivere (o riscrivere in modo equivalente) qualsiasi programma
Pagina 592016/2017Unità 4 - Istruzioni di ciclo
Calcolo del Massimo Comun DivisoreSPECIFICA• Si vuole realizzare un programma che, dati due interi
positivi x ed y, calcoli e restituisca il massimo comun divisore mcd(x, y)
• Il massimo comun divisore di due interi x ed y è il più grande intero che divide sia x che y senza resto
ESEMPIOmcd(12, 8) = 4mcd(12, 6) = 6mcd(12, 7) = 1
Pagina 602016/2017Unità 4 - Istruzioni di ciclo
Algoritmo basato sulla definizione
• Cerchiamo il massimo tra i divisori comuni di x ed y• Osservazione: 1 ≤ mcd(x, y) ≤ min(x, y)• Quindi, si devono provare ttutti i numeri compresi
tra 1 e min(x, y)• Conviene iniziare da min(x, y) e scendere verso 1.• Partendo dall'alto, appena si è trovato un divisore
comune di x ed y, lo si restituisce• Un divisore comune di x ed y di è un intero che
divide sia x che y con resto 0
Pagina 612016/2017Unità 4 - Istruzioni di ciclo
Algoritmo in pseudocodice
massimoComunDivisore di int x ed int y {int mcdinizializza mcd al minimo tra x ed ywhile ((mcd > 1) && (non si è trovato un divisore comune)) {
if (mcd divide sia x che y)si è trovato un divisore comune = vero
elsemcd--
}
Pagina 622016/2017Unità 4 - Istruzioni di ciclo
Osservazioni
• Il ciclo termina sempre perché ad ogni iterazione:– o si è trovato un divisore,– o si decrementa mcd di 1 (e alla fine si arriva ad 1)
• Per verificare se si è trovato il mcd si utilizza una variabileintera che rappresenta un valore booleano(usata nella condizione del ciclo).
• Per verificare se mcd è divisore di x (e di y) si usa l’operatore % (resto della divisione all'intero)
Pagina 632016/2017Unità 4 - Istruzioni di ciclo
Codifica in C dell'algoritmo base#include <stdio.h>
int main() {int x, y, mcd, resta = 1;printf("x = "); scanf("%d", &x);printf("x = "); scanf("%d", &y);mcd = x;if (y < mcd) mcd = y;while (mcd > 1 && resta) {
if ((x%mcd == 0) && (y%mcd == 0)) resta= 0;if (resta) mcd--;
}printf("\n MCD(%d,%d)= %d\n\n", x, y, mcd);return 0;
}
Pagina 642016/2017Unità 4 - Istruzioni di ciclo
Efficienza dell'algoritmo base• Quante volte viene eseguito il ciclo nel precedente
algoritmo?• CASO MIGLIORE: 1 volta, quando x divide y o
viceversa senza restoEs. mcd(500, 1000)
• CASO PEGGIORE: min(x,y) volte, nel caso in cui mcd(x,y) = 1 Es. mcd(500, 1001)
• Quindi, il precedente algoritmo si comporta male se xe y sono grandi e mcd(x, y) è piccolo.
Pagina 652016/2017Unità 4 - Istruzioni di ciclo
MCD usando il metodo di EuclideIl metodo di Euclide permette di ridurre sensibilmente il numero di iterazioni, sfruttando la seguente proprietà:
ESEMPIOmcd(12, 8) = mcd(12 – 8, 8) = mcd(4, 8 - 4) = 4
http://it.wikipedia.org/wiki/Algoritmo_di_Euclide
Pagina 662016/2017Unità 4 - Istruzioni di ciclo
Codifica in C del metodo di Euclide
#include <stdio.h>int main() {int x, y, ox, oy;printf("x = "); scanf("%d",&x);printf("y = "); scanf("%d", &y);ox = x; oy = y; // ricordare x e ywhile (x != y) {
if (x > y) x = x - y;else y = y - x; // allora è y > x
} printf("\n MCD(%d,%d)= %d\n\n", ox, oy, x); return 0;
}
Pagina 672016/2017Unità 4 - Istruzioni di ciclo
MCD: ammissibilità degli ingressi
• Bisogna sempre controllare il comportamento del programma con tutti i possibili ingressi
• Nel caso del MCD (con Euclide) cosa succede se:§ Se x = y = 0?
Il risultato è 0 (corretto)
§ Se x = 0 e y > 0 (o viceversa)?Il programma entra in un ciclo infinito
§ Se x < 0 e y qualunque (e viceversa)?Il programma entra in un ciclo infinito
Pagina 682016/2017Unità 4 - Istruzioni di ciclo
Raffinamento del programma#include <stdio.h>
int main() {int x, y, ox, oy;printf("x = "); scanf("%d",&x);printf("y = "); scanf("%d", &y);ox = x; oy = y; // ricordare x e yif ((x > 0) && (y > 0)) {
while (x != y) {if (x > y) x = x - y;else y = y - x; // allora è y > x
} printf("\n MCD(%d,%d)= %d\n\n", ox, oy, x);
else printf("\nDati non corretti\n\n");return 0;
}
Pagina 692016/2017Unità 4 - Istruzioni di ciclo
Metodo di Euclidecon i resti 1/2
Cosa succede col metodo di Euclide se x è molto maggiore di y (o viceversa)?
Pagina 702016/2017Unità 4 - Istruzioni di ciclo
Metodo di Euclide con i resti 2/2
Per comprimere questa lunga sequenza di sottrazioni è sufficiente osservare che quello che si calcola, in fondo è semplicemente il resto della divisione intera
METODO DI EUCLIDE CON I RESTI
Pagina 712016/2017Unità 4 - Istruzioni di ciclo
Codifica del Metodo di Euclide con i resti#include <stdio.h>
int main() {int x, y, ox, oy;printf("x = "); scanf("%d",&x);printf("y = "); scanf("%d", &y);ox = x; oy = y; // ricordare x e ywhile ((x != 0) && (y != 0)) {
if (x > y) x = x % y;else y = y % x; // allora è y > x
} printf("MCD(%d,%d)= %d\n",ox,oy,(x!=0) ? x : y);
return 0;}
Espressione con operatore condizionale: C ? e1 : e2 significa: se la condizione C è vera, allora vale e1 altrimenti vale e2
Pagina 722016/2017Unità 4 - Istruzioni di ciclo
Cicli annidatiIl corpo di un ciclo può contenere a sua volta un ciclo,e così via: si parla allora di cicli annidatiEs. Stampa della tavola pitagorica#include <stdio.h>int main() {
int const N = 10;int row, col;printf("\n");for (row= 1; row <= N; row++) {
for (col = 1; col <= N; col++)if (row * col < 10) printf(" %d", row * col);else printf("%d", row * col);
printf("\n");}return 0;
}
Pagina 732016/2017Unità 4 - Istruzioni di ciclo
Tavola pitagorica: esecuzione
Pagina 742016/2017Unità 4 - Istruzioni di ciclo
Esempio: piramide di asterischiIl numero di iterazioni di un ciclo più interno puòdipendere dall’iterazione del ciclo più esternoESEMPIOStampa di una piramide di asterischi
Nella piramide di altezza h nella generica riga r devo stampare:§ (h – r) spazi§ (2 * r – 1) asterischi
Pagina 752016/2017Unità 4 - Istruzioni di ciclo
Piramide di asterischi: codice C
Pagina 762016/2017Unità 4 - Istruzioni di ciclo
Piramide di asterischi: esecuzione
Pagina 772016/2017Unità 4 - Istruzioni di ciclo
Esempio: potenza con doppio ciclo#include <stdio.h>
int main() {int base, esp, ris = 1;printf("base = "); scanf("%d",&base);printf("esp = "); scanf("%d", &esp);while (esp > 0) {
esp--;int m_ando = ris, m_tore = base, prod = 0;while (m_tore > 0) {
m_tore--;prod = prod + m_ando;
}ris = prod;
}printf("risultato = %d\n", ris);return 0;
}
Pagina 782016/2017Unità 4 - Istruzioni di ciclo
Istruzioni di controllo del flusso
• Le istruzioni di controllo del flusso determinanola successiva istruzione da eseguire, cioè consentono di variare la sequenza di esecuzione
• Anche le istruzioni if-else, if, switch, while, for,do-while sono istruzioni di controllo del flusso diesecuzione
• Esse però lo fanno fornendo una strutturazione del programma che ne determina il flusso di esecuzione
• Esse non permettono invece di stabilire in modoarbitrario la prossima istruzione da eseguire
Pagina 792016/2017Unità 4 - Istruzioni di ciclo
Istruzioni di salto
Il trasferimento arbitrario del controllo può essere ottenuto tramite apposite istruzioni di salto
• break (salta all'istruzione successiva al ciclo o allo switch in cui essa compare)
• continue (salta alla condizione del ciclo)• goto (salta all'istruzione indicata tramite etichetta)
Anche l'istruzione return può essere usata nelle funzioni per modificare il flusso di esecuzione
Pagina 802016/2017Unità 4 - Istruzioni di ciclo
Uso di break per uscire da un ciclobreak permette di uscire prematuramente da un’istruzioneswitch, while, for o do-whiledouble a;for (i = 0; i < 10; i++)
printf("Digita un reale >= 0");scanf("%lf", &a);if (a >= 0)
printf("Radice di %f = %f\n", a, sqrt(a));else {
printf("Errore\n");break;
}}
N.B. Nel caso di cicli o switch annidati la break permette di uscire da un solo livello del nido
Pagina 812016/2017Unità 4 - Istruzioni di ciclo
Istruzione break in doppio ciclo#include <stdio.h>int main() {
int a, i, j;printf("\nDigita un intero >= 0 : "); scanf("%d",&a);for (i = 0; i < 10; i++) {
printf("*");for (j = 0; j < 10; j++) {
if (a == 2) break;printf("*");
}if (a >= 0) printf("%d\n", a);else {
printf("Errore\n");break;
}}return 0;
}
Pagina 822016/2017Unità 4 - Istruzioni di ciclo
Esecuzione
Pagina 832016/2017Unità 4 - Istruzioni di ciclo
Rimozione del break 1/3
• L’esecuzione di un’istruzione break altera il flusso delcontrollo
• Quando viene usata nei cicli:- si perde la strutturazione del programma- ma si guadagna in efficienza rispetto a una
realizzazione che evita l'uso del break• Per la pulizia del programma conviene mantenere la
strutturazione e evitare l'uso del break• In ogni caso è sempre possibile modificare la codifica
eliminando un'istruzione di break
Pagina 842016/2017Unità 4 - Istruzioni di ciclo
Rimozione del break 2/3
while (condizione){sequenza-istr-1;if (condizione-break) break;sequenza-istr-2;
}
int finito = 0; // La condizione finito è falsawhile (condizione && finito){
sequenza-istr-1;if (condizione-break)
finito = 1; // finito è veraelse {
sequenza-istr-2;}
}
Può essere riscritto come:
Pagina 852016/2017Unità 4 - Istruzioni di ciclo
Rimozione del break 3/3
double a;int errore = 0; // errore è falsoint i;for (i = 0; (i < 10) && !errore; i++) {
printf("Digita reale >= 0: "); scanf("%lf", &a);if (a > 0)
printf("Radice di %f = %f\n", a, sqrt(a));else {
printf("Errore\n");errore = 1; // errore diventa vero
}}
Confrontare con il codice nella slide 80
Pagina 862016/2017Unità 4 - Istruzioni di ciclo
Istruzione continueL’istruzione continue si applica solo ai cicli e comporta il passaggio alla successiva iterazione del ciclo, saltando le eventuali istruzioni che seguono nel corpo del ciclo.
// Stampa i soli multipli di 3int i;for (i = 1; i < n; i++) {
if (i % 3 != 0) continue;printf("%d\n", i);
}
N.B. La continue provoca il passaggio alla successiva iterazione del ciclo
Pagina 872016/2017Unità 4 - Istruzioni di ciclo
Uso errato di continueint n;printf("\nDigita un intero >= 0 : "); scanf("%d",&n);while (n != 0) {
if (n < 0) continue;printf("\nRadice di %d = %f", n, sqrt(n));printf("\nDigita un intero >= 0 : "); scanf("%d",&n);
}N.B. Bisogna sempre accertarsi che, quando si
esce da un'iterazione con una continue vengano comunque effettuate le azioni che garantiscono la terminazione del ciclo
Pagina 882016/2017Unità 4 - Istruzioni di ciclo
Esempio su continue
#include <stdio.h> int main() {
int i;for (i = 0;i < 5; i++) { if (i == 3) continue;printf("i = %d\n", i);}return 0;
}
Cosa stampa questo programma?
Pagina 892016/2017Unità 4 - Istruzioni di ciclo
Istruzione di salto goto• L’istruzione di salto deriva dal linguaggio macchina
dove è l'unica struttura di controllo e ha un ruolo fondamentale per consentire la realizzazione dei cicli
• Fino agli anni '70 anche tutti i linguaggi ad alto livello (es. il FORTRAN) erano pesantemente basati sul goto
• Il teorema di Böhm e Jacopini ha mostrato che essa non è necessaria ai fini della completezza dellinguaggio.
• L’istruzione di salto comporta una interruzione del flusso dell’esecuzione del programma, che prosegue con l’istruzione specificata nel goto
Pagina 902016/2017Unità 4 - Istruzioni di ciclo
Sintassi e semantica di gotoSINTASSI
goto etichetta
etichetta è un identificatore che deve individuare una istruzione del programma
SEMANTICAL'esecuzione del programma prosegue con l'istruzione specificata dall'etichetta
etichetta è un identificatore che viene associato a un istruzione; in C si usa la sintassi:
etichetta : istruzione;
Pagina 912016/2017Unità 4 - Istruzioni di ciclo
Esempio sul gotoint i = 0;int x;while (i < 100) {
printf("\nDigita un intero; scanf("%d", &x);if (x < 0) goto errore;...i++
}... errore: printf"\nTermina per errore nei dati\n");
Il grosso vantaggio del goto è di consentire l'uscita in una botta sola da nidi di cicli molto profondi (ma resta una mezza porcata)
Pagina 922016/2017Unità 4 - Istruzioni di ciclo
Nota sul goto• Il goto è comunque un'istruzione pericolosa, e può
provocare problemi soprattutto in sede di debugging• Usato pesantemente in passato, è oggi considerato
una cattiva pratica di programmazione• Il suo uso deve essere limitato a casi eccezionali• Circostanza tipica in cui si potrebbe volerlo usare è
l'abbandono (di una sezione) del programma a causa di una situazione di errore
• In questi casi può però essere egregiamente sostituito da un return, eventualmente preceduto dalla chiamata a una funzione che gestisce l'errore.
Pagina 932016/2017Unità 4 - Istruzioni di ciclo
Esempio su break e continue
#include <stdio.h>int main() {
int x, i;for (;;) {
printf("\nDigita un intero >= 0 : "); i = scanf("%d",&x);if (x < 0) { // Numero negativo
printf("Ho detto >= 0!");continue;
}else if (i != 1) { // Errore di formato o fine file
if (i == 0) printf("\nErrore lettura!\n\n");else if (i == EOF) printf("\n Ciao! Ciao!\n\n");break;
}printf("Ho letto %d\n", x);
}return 0;
}
Pagina 942016/2017Unità 4 - Istruzioni di ciclo
Esecuzione
Pagina 952016/2017Unità 4 - Istruzioni di ciclo
Valore di ritorno scanf
int scanf ( const char * format, ... );
• In caso di successo la funzione restituisce il numero di valori letti
• Eventualmente questo può essere inferiore al numero di argomenti, o anche 0 se c'è stato un errore
• L'errore può essere un errore di formato, un errore di lettura o il raggiungimento della fine del file
• Quando si raggiunge la fine del file prima di poter leggere qualcosa, viene restituito EOF
Pagina 962016/2017Unità 4 - Istruzioni di ciclo
Svuotamento del buffer 1/3
• La scanf acquisisce l'input una riga per volta • I caratteri letti restano in un buffer, come sequenza
terminata dal carattere EOL (End Of Line)• La scanf consuma questi caratteri leggendo
argomenti dalle sue liste fino a che incontra EOL• Se si incorre in un errore di formato, nessun carattere
viene consumato dalla scanf• Se si desidera ricominciare la lettura da una nuova
riga allora è necessario svuotare il buffer
Pagina 972016/2017Unità 4 - Istruzioni di ciclo
Svuotamento del buffer 2/3
#include <stdio.h>int main() {
int x;int i = 1;char c;while (i != EOF)
printf("\nDigita un intero : "); i = scanf("%d",&x);if (i != 1) { // Errore di formato o fine file
if (i == 0) { // Svuota il bufferdo c = getchar();while (c != '\n'); // '\n' è EOL
}}else printf("Ho letto %d\n", x);
}printf("\n\nRaggiunta la fine del file!\n\n");return 0;
}
Pagina 982016/2017Unità 4 - Istruzioni di ciclo
Svuotamento del buffer 3/3
Pagina 992016/2017Unità 4 - Istruzioni di ciclo
Esercizio su break econtinue
Realizzare un programma in grado di leggere da tastiera valori interi ed elaborarli in accordo con le seguenti condizioni:• Se il valore che viene letto è negativo, si vuole stampare
un messaggio di errore e terminare il programma• Se il valore letto è maggiore di 100, si vuole ignorarlo e
continuare con il successivo valore in input• Se il valore è 0, si vuole terminare il ciclo con un
messaggio di avvenuta terminazione corretta• Altrimenti si vuole stampare il doppio dell’intero letto
Pagina 1002016/2017Unità 4 - Istruzioni di ciclo
Soluzione#include <stdio.h>int main() {
int value;while (scanf("%d", &value) == 1 && value != 0) {
if (value < 0) {printf("Valore negativo. Termina\n\n");break; // Abbandona il loop
}if (value > 100) {
printf("Valore > 100\n");continue; // Vai alla prossima iterazione
}printf("Raddoppio: %d\n", 2 * value"); // Stampa il doppio
}if (value >= 0) printf("Terminato con successo\n\n");return 0;
}
Pagina 1012016/2017Unità 4 - Istruzioni di ciclo
Esecuzione