Sei sulla pagina 1di 12

2

Strutture iterative
 Problema:
Visualizzare i numeri interi da 0 a 1000
Strutture iterative Soluzione
printf("0\n");
printf("1\n");
printf("2\n");
Ver. 2.4 printf("3\n");
printf("4\n");
...
Non è davvero una buona idea… ma con le
conoscenze attuali non c’è alternativa

© 2010 - Claudio Fornaro - Corso di programmazione in C

3 4

Strutture iterative I cicli in C


 Vorremmo scrivere:  Per “tornare indietro” si potrebbe utilizzare
“Esegui l’istruzione: un’istruzione apposita, ma per questioni di
printf("%d\n", i); chiarezza si utilizzano strutture sintattiche che
con i che assume i valori da 0 a 1000 ” fanno “tornare indietro” solo se la condizione
i=0 di ripetizione è vera
 Le strutture iterative sono comunemente dette
stampa i cicli o loop
i=i+1
 In C i cicli sono controllati da una condizione di
percorso chiuso, permanenza nel ciclo: fintantoché la
detto “anello”, V
“loop” o “ciclo” i<=1000 condizione è vera, si esegue il corpo del ciclo
(il blocco di codice da eseguire più volte)
F
5 6

Ciclo WHILE Ciclo WHILE


 Fa eseguire un blocco di codice fintantoché  while (condizione)  senza il ‘;’
una certa condizione è vera blocco
 Valuta la condizione prima di eseguire il  Viene valutata la condizione:
blocco  se è vera
 esegue il blocco
F  torna su a valutare nuovamente la condizione
condizione
V  se è falsa
blocco  passa ad eseguire le istruzioni successive al
blocco
 La condizione può essere un’espressione
 Se la condizione è inizialmente falsa, qualsiasi (come nel costrutto if)
il blocco non viene eseguito neppure una volta

7 8

Ciclo WHILE Ciclo FOR


 Esempio  Come il ciclo WHILE fa eseguire il blocco
Il seguente codice somma i valori introdotti fintantoché la condizione è vera
finché non viene dato il valore 0 for (espr1;condizione;espr2)  senza il ‘;’
somma = 0; blocco
scanf("%d", &v);
 Viene calcolata espr1 (soltanto la prima volta)
while (v != 0)
{  Viene valutata la condizione:
somma += v;  se è vera:
scanf("%d", &v);  esegue il blocco
}  esegue expr2
printf("Somma: %d", somma);  torna su a valutare nuovamente la condizione

 altrimenti (se è falsa):


 passa ad eseguire le istruzioni successive a blocco
9 10

Ciclo FOR Ciclo FOR


 Il flow-chart corrispondente è il seguente:  La condizione può essere un’espressione
qualsiasi, se manca viene considerata pari a 1
expr1  expr1 e/o expr2 possono mancare (ma i
separatori ‘;’ devono esserci ugualmente)
F  Esempio
condizione Stampa i numeri interi da 0 a 1000
V
for (i=0; i<=1000; i++)
blocco printf("%d", i);
expr2  Una variabile come i nell’esempio precedente
che tiene conto del numero di iterazioni viene
detta variabile di conteggio o indice
 Notare che, nell’esempio, dopo che il ciclo è
stato eseguito completamente, i vale 1001

11 12

Ciclo FOR Ciclo FOR


 Il ciclo FOR è un ciclo WHILE riscritto in modo  Esempio
tale da raggruppare tra le parentesi tutto ciò Questo ciclo WHILE:
che gestisce l’indice: inizializzazione (espr1), i=0;
controllo (condizione) e aggiornamento (espr2) while (i<=1000)
 for (espr1;condizione;espr2) {
blocco printf("%d", i);
 Il ciclo FOR precedente equivale a: i++;
expr1;  fuori dal corpo del ciclo! }
while (condizione) e questo ciclo FOR:
{ for (i=0; i<=1000; i++)
blocco printf("%d", i);
expr2;
} sono equivalenti, ma il secondo è più compatto
13 14

La variabile di conteggio Scelta tra ciclo FOR e WHILE


 Talvolta è conveniente che il nome della  Quando il numero di iterazioni è noto a priori
variabile di conteggio sia corto per questioni di (e quindi il ciclo è controllato da un indice),
leggibilità del codice è preferibile (per chiarezza e stilisticamente)
 Esempio utilizzare un ciclo FOR che raggruppa in un
for (i=0; scanf("%d",&v[i])!=EOF; i++)
tot += v[i]*v[i-1]*v[i+1]; punto solo l’inizializzazione, il controllo e
totValoriLetti = i; l’aggiornamento dell’indice
Qui v[i] viene usata nel corpo del ciclo più
volte, quindi è conveniente usare come indice
i e non la variabile totValoriLetti che
invece viene assegnata alla fine del ciclo
 La modifica della variabile di conteggio dentro
il ciclo for viene considerata pratica da evitare
in quanto può rendere il codice complesso

15 16

Ciclo DO-WHILE Ciclo DO-WHILE


 Fa eseguire un blocco di codice fintantoché  Nella letteratura questo ciclo viene detto ciclo
una certa condizione è vera Repeat-Until (dove però se la condizione è
 Valuta la condizione dopo aver eseguito il vera si esce dal ciclo: non è di permanenza)
blocco  do
{
blocco
blocco }while (condizione);  con il ‘;’
V  La condizione può essere un’espressione
condizione
qualsiasi che produce un valore
F  Le graffe sono opzionali, ma consigliabili
(proprio con la graffa di chiusura subito prima
 Anche se la condizione è inizialmente falsa, della keyword while) per distinguere
il blocco viene eseguito almeno una volta facilmente il ciclo WHILE dal ciclo DO-WHILE
17 18

Ciclo DO-WHILE Scelta tra ciclo WHILE e DO


 Esempio  Si può sempre passare da un tipo di ciclo ad
Somma i valori dati finché non viene un’altro modificando (poco) il programma
introdotto il valore particolare 0  La scelta tra ciclo WHILE e ciclo DO-WHILE è
somma = 0; spesso ovvia e questione di preferenze
do personali
{
scanf("%d", &v);
somma += v;
}while (v != 0);
Notare che il valore v viene comunque
addizionato a somma (ma in questo esempio
non causa problemi: somma uno 0)

19 20

Programmazione strutturata Programmazione strutturata


 Nasce dalla necessità di regolamentare e  Le strutture di un linguaggio strutturato
standardizzare le metodologie di devono avere le seguenti caratteristiche:
programmazione  ogni struttura (compresi i blocchi controllati) deve
avere un unico punto di ingresso e un unico punto
 Un linguaggio strutturato deve avere almeno i
di uscita (così da non avere altre interazioni con
seguenti 3 tipi di strutture: l’esterno e poter essere considerata come un’unica
 La sequenza: ossia la possibilità di definire un macro-istruzione)
blocco di istruzioni (le graffe in C, ma anche il  ogni struttura può avere nel blocco controllato altre
semplice elenco di istruzioni) strutture (di ogni tipo)
 L’ alternativa: costrutti di selezione (if e switch)  Un programma è strutturato se usa solo le
 L’ iterazione: costrutti per ripetere uno stesso strutture indicate nei modi indicati sopra
blocco di istruzioni (for, while, do-while)
 Il linguaggio C è strutturato, ma permette
anche di scrivere codice non strutturato
21 22

Programmazione strutturata Break


 In Linguaggio C si ha programmazione non  Per uscire da un ciclo immediatamente, senza
strutturata quando si usano le istruzioni: aspettare la valutazione della condizione, si
può utilizzare l’istruz. non strutturata break
 goto
 break
 Dopo il break, l’esecuzione continua dalla
prima riga successiva al blocco
 continue
 while (condizione)
 return multipli in una funzione { istruzioni...
 Quando si richiede una programmazione if (condizione_particolare)
strutturata le istruzioni precedenti sono tutte break;
istruzioni...
vietate }
 Dette istruzioni possono talvolta dare  Il break può essere usato per gestire condizioni
vantaggi anche non marginali per chiarezza e particolari e infrequenti (non deve essere il
velocità di esecuzione, ma non se ne abusi metodo normale di terminazione del ciclo)

23 24

Break Break
 Esempio  La formulazione equivalente strutturata è:
Somma fino a 10 valori dati in input. Per esci = NO;
introdurre meno valori, introdurre 0 somma = 0;
somma = 0; for (i=0; i<10 && esci==NO; i++)
for (i=0; i<10; i++) {
{ scanf("%d", &v);
scanf("%d", &v); if (v == 0)
if (v == 0) esci=SI;
break; else
somma += v; somma += v;
} }
printf("Somma = %d\n",somma); printf("Somma = %d\n",somma); i++
25 26

Continue Continue
 Per passare immediatamente all’iterazione  Schema con ciclo while
successiva, si può utilizzare l’istruzione while (condizione)
non strutturata continue {
 Per effetto dell’istruzione continue: istruzioni...
 vengono saltate tutte le istruzioni dalla continue if (condizione_particolare)
fino alla parentesi di terminazione del corpo del ciclo continue;
 se si tratta di un ciclo for, viene eseguita expr2
 l’esecuzione riprende dalla valutazione della istruzioni saltate se eseguito continue
condizione
}

27 28

Continue Continue
 Schema con ciclo do-while  Esempio
do Somma i valori dati finché non viene
{ introdotto il valore 0, ignorando i negativi.
istruzioni... somma = 0;
do
if (condizione_particolare) {
continue; scanf("%d", &v);
if (v < 0)
istruzioni saltate se eseguito continue continue;
somma += v;
}while (condizione); }while(v != 0);
29 30

Continue Lettura di valori


 La formulazione equivalente strutturata è in  Quando non si può sapere a priori il numero
questo caso più chiara: di valori che verranno introdotti dall’utente si
deve trovare un modo per stabilire la fine
somma = 0; dell’input:
do
{  Si chiede all’utente quanti valori verranno introdotti
scanf("%d", &v);  Si prevede un valore particolare che quando
if (v >= 0) introdotto indica la fine dell’input, tale valore è
somma += v; detto sentinella (es. lo 0 degli esempi precedenti)
}while(v != 0);  Si chiede all’utente di segnalare la fine dell’input
mediante l’immissione di un codice di controllo
detto End Of File (EOF) che viene riconosciuto e
segnalato dalle stesse funzioni di input (mentre la
sentinella viene riconosciuta dopo l’input)

31 32

Lettura di valori Lettura di valori


 La costante EOF è un valore intero definito in  Esempio di lettura di sequenza di lunghezza
stdio.h (in genere vale –1) ignota di valori dalla tastiera, la lettura
 Viene prodotto dall’utente premendo: termina con l’introduzione di un EOF
 Windows  Control-Z e poi INVIO printf("Terminare con EOF\n");
 Linux/Unix  Control-D while (scanf("%d", &a) != EOF)
 Le funzioni scanf e getchar restituiscono somma += a;
EOF quando l’utente indica la fine dell’input printf("Somma=%d\n", somma);
 In modo analogo gets restituisce NULL  Esempio di input:
 N.B. Le combinazioni di tasti Control-Z e 12
Control-D spesso vengono scritte ^Z e ^D, ma 22
34
NON si ottengono con il carattere ^ : si deve
^Z
invece premere il tasto Control e poi la lettera Somma=68
33 34

Cicli annidati Cicli annidati


 Un ciclo può essere collocato  Esempio Ciclo esterno
(completamente) nel corpo di un altro ciclo for (i=1; i<=7; i+=3)
Ciclo interno
{
 In genere, nel caso di cicli FOR ogni ciclo
for (j=2; j<5; j++)
deve avere una variabile di conteggio diversa
printf("%d,%d ", i, j);
 Il ciclo esterno controlla quello interno printf("\n");
 Il ciclo interno ricomincia sempre da capo (ad } Blocco ciclo
esempio l’inizializzazione dell’indice di un ciclo printf("%d,%d ", i, j); interno
FOR interno ad un altro ciclo viene eseguita produce il seguente output:
ogni volta) 1,2 1,3 1,4 Blocco ciclo
4,2 4,3 4,4 esterno
7,2 7,3 7,4
10,5  notare i valori di uscita

35 36

Uscita da cicli annidati Uscita da cicli annidati


 Nel caso di cicli annidati, break fa uscire solo  Per evitare di avere codice non strutturato e a
da un livello; per uscire contemporaneamente scapito di un po’ di efficienza si può scrivere:
da tutti i cicli annidati si può usare una goto esci = NO;
for (i=0; i<10; i++) for (i=0; i<10 && esci==NO; i++)
for (j=0; j<10; j++) for (j=0; j<10 && esci==NO; j++)
{ scanf("%d", &v); { scanf("%d", &v);
if (v == 0) if (v == 0)
goto fuori; esci = SI;
somma += v; else
} somma += v;
fuori: }
printf("Somma = %d\n",somma); printf("Somma = %d\n",somma);
37 38

Etichette Salti
 Una label (etichetta) viene usata per dare un  Un “salto” fa continuare l’esecuzione di un
nome ad una riga, viene in genere posizionata programma da un altro punto del codice
all’inizio della riga stessa senza indentazione  Il salto incondizionato goto ha sintassi:
ed è terminata da un carattere ‘:’, esempio: goto label;  label senza il carattere ‘:’
fuori: Quando viene eseguita, il programma salta
 Tutte le label devono avere nomi diversi alla riga con quella label e continua da lì
(stesse regole sintattiche degli identificatori)  Una label può essere collocata in una riga
precedente o successiva quella con il goto
 Una label è visibile in ogni punto della
(salto indietro o avanti), ma nell’uso accettato
funzione dove è definita, ma non al di fuori di
sarà sempre avanti e in posizioni ben precise
essa
 Una label può essere usata da più goto, ma
nell’uso accettato non si presenta mai il caso

39 40

Salti Salti
 L’utilizzo di goto produce sempre codice non  In alcuni (pochi) casi il goto può essere utile
strutturato e quindi potenzialmente più difficile per questioni di efficienza e chiarezza
da comprendere e da manutenere  La liceità di utilizzo del goto è oggetto di
 I vecchi linguaggi di programmazione non diatribe, con ferventi e autorevoli sostenitori
disponevano di costrutti strutturati e l’uso del in entrambe le parti (Dijkstra vs. Knuth)
goto era indispensabile, i frequentissimi  Con il goto sono “condannati” anche break,
rimandi da una parte all’altra del codice lo continue e return multipli
rendevano molto intricato (“spaghetti code”)
 Se il linguaggio dispone di adeguati costrutti
strutturati si può sempre evitare di usare i
goto. Il linguaggio C ha questi costrutti.
41 42

Salti Salti
 E’ utile l’uso del goto per uscire da due o più  Si eviti il goto in tutti gli altri casi
cicli annidati, in questo caso l’etichetta DEVE  Alcuni linguaggi moderni (es. Java) non hanno
essere collocata subito sotto il corpo del ciclo goto, ma dispongono di costrutti aggiuntivi
più esterno (senza istruzioni intermedie) ed è (es. break con etichetta) proprio per uscire
preferibile che sia allineata verticalmente con da cicli annidati
la keyword del ciclo più esterno da cui uscire
for (… Allineati verticalmente
{
for (…
{ … if (condizione speciale)
goto fuori;…
} Etichetta subito sotto il corpo
}
del ciclo più esterno
fuori:

43 44

Esercizi Esercizi
1. Scrivere un programma che calcoli la media 4. Scrivere un programma che richieda N numeri
(con parte frazionaria) di 100 valori introdotti da tastiera e ne calcoli il valore massimo.
dalla tastiera.
5. Scrivere un programma che richieda N numeri
2. Scrivere un programma che chieda quanti
siano i valori che verranno introdotti dalla da tastiera e ne calcoli il valore massimo, il
tastiera, li chieda tutti e ne stampi la somma valore minimo, la somma e la media.
e la media. 6. Si scriva un programma che calcoli il fattoriale
3. Scrivere un programma che calcoli la media di di un numero intero N dato dalla tastiera. Si
tutti i valori introdotti dalla tastiera finché non ricordi che il fattoriale di un numero n (simbolo
ne viene introdotto uno non compreso tra 18
e 30, ad esempio 9999 (provare proprio n!) viene calcolato con la seguente formula:
questo valore!). La visualizzazione della media n! = n ·(n–1)·(n–2)· ... ·2 ·1.
deve avvenire solo alla fine (ossia non ogni
volta che un valore viene introdotto).
45 46

Esercizi Esercizi
7. Scrivere un programma che calcola i primi N 9. Si scriva un programma per calcolare ex
numeri di Fibonacci, con N introdotto dalla mediante il suo sviluppo in serie:
tastiera. I numeri di Fibonacci sono una
sequenza di valori interi che inizia con i due x x2 x3
valori fissi 1 e 1 e ogni successivo valore è la
e  1 
x
  ...
1! 2! 3!
somma dei due precedenti.
Ad esempio i primi 10 numeri di Fibonacci Ogni frazione aggiunge precisione al risultato,
sono: 1 1 2 3 5 8 13 21 34 55. per cui conviene usare valori di n
8. Scrivere un programma che calcoli i primi adeguatamente elevati, ad esempio compresi
numeri di Fibonacci minori o uguali a N, con N tra 30 e 40. Si verifichi che i risultati calcolati
introdotto dalla tastiera. in questo modo siano coerenti con quelli
Ad esempio i primi numeri di Fibonacci minori forniti dalla funzione intrinseca exp
o uguali a 10 sono: 1 1 2 3 5 8. calcolando la differenza dei valori.

47 48

Esercizi Esercizi
10. Si scriva un programma dove il calcolatore (Continuazione)
determini casualmente un numero intero Dato il valore A, se ne vuole calcolare la
compreso tra 0 e 99 e chieda all’utente di radice quadrata x. La formula data calcola
trovare il numero stesso. Ad ogni input valori di x sempre più precisi.
dell’utente il calcolatore risponde con “troppo Inizialmente si considera x i=0 = A, ricavando
alto” o “troppo basso”, finché non viene un valore x1 che approssima molto
trovato il valore corretto. Per generare valori grossolanamente il valore della radice
casuali si utilizza la funzione rand. quadrata.
Si riinserisce x1 nella formula (al posto di xi)
11. Si scriva un programma per calcolare la radice
ottenendo un x2 che è un’approssimazione
quadrata mediante la formula
1 A migliore della precedente.
iterativa di Newton: xi 1   xi  
2  xi  Si continua in questo modo finché il risultato
non varia più (cioè xi = xi +1).