S tr u ttu r e d i r ip e tiz io n e : w h ile , f o r e d ...busi/lsbioinfo/5.while.pdf · 1 S tr...

70
1 Strutture di ripetizione: while, for e do-while • cicli controllati da contatore e istruzione while • calcolo della somma e del prodotto di un insieme di numeri mediante un ciclo • istruzione for • cicli condizionali • cicli controllati da sentinella • cicli annidati • istruzione do-while • cicli controllati da flag • debugging

Transcript of S tr u ttu r e d i r ip e tiz io n e : w h ile , f o r e d ...busi/lsbioinfo/5.while.pdf · 1 S tr...

1

Strutture di ripetizione:while, for e do-while

• cicli controllati da contatore e istruzione while• calcolo della somma e del prodotto di un insieme di numeri mediante un ciclo• istruzione for• cicli condizionali• cicli controllati da sentinella• cicli annidati• istruzione do-while• cicli controllati da flag• debugging

2

Strutture di ripetizione

ciclostruttura di controllo che permette di ripetere ungruppo di istruzioni

corpo del ciclole istruzioni che vengono ripetute all’interno delciclo

3

Ciclo controllato da contatore

ciclo il cui numero di iterazioni è conosciuto primadell’inizio dell’esecuzione del ciclo

la ripetizione del ciclo è gestita da una variabile dicontrollo, il cui valore rappresenta un contatore

setta la variabile_di_controllo al valore iniziale 0finchè variabile_di_controllo < valore finale

. . .incrementa di 1 la variabile_di_controllo

4

Esempio: stipendio di 7 impiegaticount_emp = 0; /* no employees processed yet */while (count_emp < 7) { /* test value of count_emp */ printf("Hours> "); scanf("%d", &hours); printf("Rate> "); scanf("%lf", &rate); pay = hours * rate; printf("Pay is $%6.2f\n", pay); count_emp = count_emp + 1; /* increment count_emp */}printf("\nAll employees processed\n");

5

count_emp < 7

prendi i daticalcola lo stipendiovisualizza lo stipendioincrementa count_emp

T

F

6

Differenza tra while e ifwhile (count_emp < 7) {

...}

if (count_emp < 7) {...

}

il corpo del while può essere eseguito zero, una o piùvolte

il corpo dell’if viene eseguito al più una volta

7

Variabile di controllo del ciclovariabile il cui valore determina se il ciclo deve essereripetuto.La variabile di controllo del ciclo deve essere:• inizializzata count_emp viene posta a 0 prima dell’inizio del while• testata il valore di count_emp viene testato prima di ogni iterazione del while• aggiornata durante ogni iterazione, il valore di count_emp viene aggiornato

8

Istruzione whilesintassi

while (loop_repetition_condition)statement

esempiocount_stars = 0;while (count_stars < N) {

printf(“*”);count_stars = count_stars + 1;

}

9

Istruzione whileLa loop_repetition_condition viene testata; se è vera,viene eseguita l’istruzione statement (corpo del ciclo)e la loop_repetition_condition viene testata di nuovo.L’istruzione statement viene ripetuta fino a quando laloop_repetition_condition rimane vera. Quando la condizione diventa falsa, si esce dal while e l’esecuzionecontinua con l’istruzione successiva al while.

10

Istruzione while

Se la loop_repetition_condition è falsa la prima volta che viene testata, l’istruzione statement non viene mai eseguita.

Se la loop_repetition_condition rimane sempre vera,il ciclo non termina (ciclo infinito).

11

Calcolare una somma di datiin un ciclo

Calcolare il totale degli stipendi degli impiegati.

Accumulatorevariabile utilizzata per memorizzare una somma divalori; viene incrementata ad ogni iterazione del ciclo.

12

total_pay = 0.0;count_emp = 0;while (count_emp < number_emp) {

printf("Hours> ");scanf("%lf", &hours);printf("Rate > $");scanf("%lf", &rate);pay = hours * rate;printf("Pay is $%6.2f\n\n", pay);total_pay = total_pay + pay; count_emp = count_emp + 1;

}printf("All employees processed\n");printf("Total payroll is $%8.2f\n", total_pay);

13

Calcolare un prodotto in un ciclo

/* Multiply data while product remains less than 10000 */product = 1;while (product < 10000) {

printf(“%d\n”, product); printf(“Enter next item> “);scanf(“%d”, &item);product = product * item;

}

14

Calcolare un prodotto in un ciclo

il ciclo termina quando product contiene un valoremaggiore o uguale a 10000

Ciclo condizionale generale:

1. inizializza la variabile di controllo del ciclo2. finchè la condizione di uscita non è verificata

3. continua l’elaborazione

15

Operatore di assegnamentocomposto

variable = variable op expr;

se op è +, -, *, /, %

può essere espresso nella forma abbreviata

variable op = expr;

16

Op. di assegnamento compostoassegnamento normale assegnamento abbreviato

count_emp = count_emp + 1; count_emp += 1;

time = time - 1; time -= 1;

total_time = total_time + time; total_time += time;

product = product * item; product *= item;

n = n * (x + 1); n *= x + 1;

17

Istruzione forLa maggior parte dei cicli è costituita da 3 componentiaggiunti al corpo del ciclo:• inizializzazione della variabile di controllo del ciclo• test della condizione di ripetizione del ciclo• aggiornamento della variabile di controllo del ciclo

L’istruzione for permette di raggruppare tutte e tre lecomponenti in un’unica posizione.

18

total_pay = 0.0;for (count_emp = 0; /* initialization */ count_emp < number_emp;/* loop rep. cond.*/ count_emp += 1) { /* update */ printf("Hours> "); scanf("%lf", &hours); printf("Rate > $"); scanf("%lf", &rate); pay = hours * rate; printf("Pay is $%6.2f\n\n", pay); total_pay = total_pay + pay;}printf("All employees processed\n");printf("Total payroll is $%8.2f\n", total_pay);

19

Istruzione for

sintassi

for (initialization_expression; loop_repetition_condition; update_expression)

statement

esempio

for (count_stars = 0; count_stars < N; count_stars += 1)

printf(“*”);

20

Istruzione forViene eseguita la initialization_expression.Poi viene testata la loop_repetition_condition: se è vera,viene eseguito statement, seguito da update_expression.Viene testata di nuovo la loop_repetition_condition e sicontinua con l’esecuzione delle istruzioni finchè laloop_repetition_condition non diventa falsa.Quando la loop_repetition_condition diventa falsa, siesce dal for e si continua l’esecuzione con l’istruzioneseguente.

21

Istruzione for - stile

for (count_emp = 0; count_emp < num_emp; count_emp += 1) {

statements}

for (i = 0; i < max; i += 1) {statements

}

utilizzata principalmente quando le fasi di inizializzazionee aggiornamento sono semplici (es. azzeramento eincremento).

Formati:

22

Operatori di incremento edecremento

Gli assegnamenti

counter = counter + 1;e

counter += 1;

possono essere rimpiazzati da

counter ++;

23

Operatori di incremento edecremento

++ è un operatore di incremento unario, il cui operandodeve essere una variabile;++ provoca un effetto collaterale sulla variabile operando:il contenuto della variabile viene incrementato di 1

Effetto collaterale (side effect): modifica del contenutodi una variabile provocata dall’esecuzione di un’operazione.

-- è l’operatore di decremento: il contenuto della variabileoperando viene decrementato di 1

24

Operatori di incremento edecremento

il valore dell’espressione contenente l’operatore ++ dipende dalla posizione dell’operatore:• incremento prefisso ++i il valore dell’espressione è il valore contenuto nella variabile dopo aver effettuato l’incremento• incremento postfisso i++ il valore dell’espressione è il valore contenuto nella variabile prima di effettuare l’incremento

25

Operatore di incremento - esempio

2 ??

3 3

j = ++ i;

3 2

j = i++;

i j

i j i j

26

/** Computes n!* Pre: n is greater than or equal to zero*/intfactorial(int n){ int i, /* local variables */ product; /* accumulator for product computation */

product = 1; /* Computes product n x (n-1) x (n-2) x ... x 2 x 1 */ for (i = n; i > 1; --i) { product = product * i; }

/* Returns function result */ return (product);}

27

/* Conversion of Celsius to Fahrenheit temperatures */

#include <stdio.h>

/* Constant macros */#define CBEGIN 10#define CLIMIT -5#define CSTEP 5

intmain(void){ /* Variable declarations */ int celsius; double fahrenheit;

/* Display the table heading */ printf(" Celsius Fahrenheit\n");

Incrementi/decrementi maggiori di 1

28

/* Display the table */1 for (celsius = CBEGIN;2 celsius >= CLIMIT;3 celsius -= CSTEP) {4 fahrenheit = 1.8 * celsius + 32.0;5 printf("%6c%3d%8c%7.2f\n", ' ', celsius, ' ', fahrenheit); }

return (0);}

29

istr. celsius fahrenheit1 10 ? inizializza celsius a 102 10 >= -5 è vero4 50.0 assegna 50.0 a fahrenheit5 stampa 10 e 50.03 5 sottrae 5 a celsius2 5 >= -5 è vero4 41.0 assegna 41.0 a fahrenheit5 stampa 5 e 41.03 0 sottrae 5 a celsius2 0 >= -5 è vero4 32.0 assegna 32.0 a fahrenheit5 stampa 0 e 32.03 -5 sottrae 5 a celsius

30

2 -5 >= -5 è vero4 23.0 assegna 23.0 a fahrenheit5 stampa -5 e 23.03 -10 sottrae 5 a celsius2 -10 >= -5 è falso, esce

31

Cicli condizionaliIn alcuni casi non siamo in grado di determinare il numerodi ripetizioni che verrano eseguite prima di cominciarel’esecuzione del ciclo.

Es.: elaborazione di un insieme di valori; viene richiestoall’utente il numero di dati da elaborare; se l’utente inserisce un numero non valido (es. negativo), si chiededi inserire nuovamente il numero, e si continua finche’non viene inserito un numero valido.

32

visualizza prompt e prendi in input num_obsfinchè num_obs è negativo

visualizza avvertimento e prendi in input num_obs

printf(“Enter number of observed values> “);scanf(“%d”, &num_obs); /* initialization */while (num_obs < 0) {

printf(“Negative number invalid; “);printf(“try again> “);scanf(“%d”, &num_obs); /* update */

}

Esempio - num. di osservazioni

33

Esempio

Controllo della benzina contenuta in una cisterna.Ad ogni pieno, il contenuto della cisterna viene decrementato.Quando la quantità di benzina scende al di sotto del10% della capacità della cisterna, non è possibile prelevarealtra benzina e viene visualizzato un avvertimento.

Non è possibile determinare in anticipo il numero diripetizioni del ciclo, perchè dipende dal contenuto inizialedella cisterna e dai quantitativi prelevati ad ogni pieno.

34

/* * Monitor gasoline supply in storage tank. Issue warning * when supply falls below MIN_PCT % of tank capacity. */

#include <stdio.h>

/* constant macros */#define CAPACITY 80000.0 /* number of barrels tank can hold */#define MIN_PCT 10 /* warn when supply falls below this percent of capacity */#define GALS_PER_BRL 42.0 /* number of gallons in one barrel */

/* Function prototype */double monitor_gas(double min_supply, double start_supply);

35

intmain(void){ double start_supply, /* input - initial supply in barrels */ min_supply, /* minimum number of barrels left without warning */ current; /* output - current supply in barrels */ /* Compute minimum supply without warning */ min_supply = MIN_PCT / 100.0 * CAPACITY;

/* Get initial supply */ printf("Number of barrels currently in tank> "); scanf("%lf", &start_supply);

/* Subtract amounts removed and display amount remaining as long as minimum supply remains. */ current = monitor_gas(min_supply, start_supply);

36

/* Issue warning */ printf("only %.2f barrels are left.\n\n", current); printf("*** WARNING ***\n"); printf("Available supply is less than %d percent of ”, MIN_PCT); printf("tank’s %.2f-barrel capacity.\n", CAPACITY);

return (0);}

/* * Computes and displays amount of gas remaining after each delivery * Pre : min_supply and start_supply are defined. * Post: Returns the supply available (in barrels) after * all permitted removals. The value returned is the * first supply amount that is less than min_supply. */doublemonitor_gas(double min_supply, double start_supply)

37

{ double remov_gals, /* input - amount of current delivery in gallons */ remov_brls, /* and in barrels */ current; /* output - current supply in barrels */ current = start_supply; while (current >= min_supply) { printf("%.2f barrels are available.\n\n", current); printf("Enter number of gallons removed> "); scanf("%lf", &remov_gals); remov_brls = remov_gals / GALS_PER_BRL;

printf("After removal of %.2f gallons (%.2f barrels),\n", remov_gals, remov_brls);

current -= remov_brls; }

return (current);}

38

TestNumber of barrels currently in tank> 8500.58500.50 barrels are available.

Enter number of gallons removed> 5859.0After removal of 5859.00 gallons (139.50 barrels),8361.00 barrels are available.

Enter number of gallons removed> 7568.4After removal of 7568.40 gallons (180.20 barrels),8180.80 barrels are available.

Enter number of gallons removed> 8400.0After removal of 8400.00 gallons (200.00 barrels),only 7980.80 barrels are left.

*** WARNING ***Available supply is less than 10 percent of tank's80000.00-barrel capacity.

39

Cicli controllati da sentinella

Alcuni programmi prendono in input uno o più dati ad ogni iterazione di un ciclo.Se non conosco il numero esatto di dati da prendere in input, occorre un meccanismo per segnalare al programma che i dati sono finiti.

valore sentinella: valore utilizzato per indicare la terminazione dei dati in input; deve essere un valore diverso dai possibili valori dei dati in input.

40

Cicli controllati da sentinella

1. prendi in input il primo dato2. finchè non trovi il valore sentinella

3. elabora il dato corrente4. prendi in input il prossimo dato

Esempio

Programma che calcola la somma dei voti di un gruppo di studenti.

SENTINEL -99int sum /* somma dei voti */int score /* voto corrente */

41

Prima soluzione

1. inizializza sum a 02. finchè score è diverso da SENTINEL

3. prendi in input score 4. somma score a sum

Problemi:• quando si esegue il primo confronto, score non è inizializzata• nella penultima iterazione, viene inserito un voto valido che viene sommato a sum; la condizione 2 è soddisfatta, quindi si entra di nuovo nel corpo del ciclo; nell’ultima iterazione viene inserito il valore sentinella, che viene erroneamente sommato a sum!

42

Soluzione

1. inizializza sum a 02. prendi in input il primo score3. finchè score è diverso da SENTINEL

4. somma score a sum5. prendi in input il prossimo score

43

/* * Compute the sum of a list of exam scores. */#include <stdio.h>#define SENTINEL -99

intmain(void){ int sum = 0, /* output - sum of scores input so far */ score; /* input - current score */

/* Accumulate sum of all scores. */ printf("Enter first score (or %d to quit)> ", SENTINEL); scanf("%d", &score); /* Get first score. */ while (score != SENTINEL) { sum += score; printf("Enter next score (%d to quit)> ", SENTINEL); scanf("%d", &score); /* Get next score. */ } printf("\nSum of exam scores is %d\n", sum);

return (0);}

44

Test

Enter first score (or -99 to quit)> 25Enter next score (-99 to quit)> 30Enter next score (-99 to quit)> 21Enter next score (-99 to quit)> -99

Sum of exam scores is 76

Casi particolari:cosa succede se non ci sono dati da elaborare?

Enter first score (or -99 to quit)> -99

Sum of exam scores is 0

45

Cicli annidati#include <stdio.h>

intmain(void){ int i, j; /* loop control variables */

printf(" I J\n"); /* prints column labels */ for (i = 1; i < 4; ++i) { /* heading of outer for loop */

printf("Outer %6d\n", i); for (j = 0; j < i; ++j) { /* heading of inner loop */ printf(" Inner%9d\n", j); } /* end of inner loop */

} /* end of outer loop */

return (0);}

46

Cicli annidati - test I J

Outer 1 Inner 0Outer 2 Inner 0 Inner 1Outer 3 Inner 0 Inner 1 Inner 2

47

Cicli annidati - esempioScrivere un programma che stampa un triangolo isoscele dell’altezza desiderata,

Es. altezza 4

* *** ************

48

Analisi

stampo una riga per voltafor (curr_line = 1; curr_line <= NUMLINES; curr_line ++) {

stampa una riga}

ogni riga sarà costituita da spazi iniziali seguiti da asterischi

quanti spazi iniziali? NUMLINES - curr_line

quanti asterischi? 2 * curr_line - 1

49

#include <stdio.h>#define NUMLINES 4 /* number of lines in the triangle */

void print_spaces(int n);void print_stars(int n);

int main(void) { int curr_line; /* line to be printed */ for (curr_line = 1; curr_line <= NUMLINES; curr_line ++) { /* draw a line */ print_spaces(NUMLINES - curr_line); print_stars( 2 * curr_line - 1); printf("\n"); }

return (0);}

50

/* * Prints n spaces. * Pre: n is defined. */voidprint_spaces(int n){ int i;

for (i=1; i <= n; i++) printf(" ");}

/* * Prints n asterisks. * Pre: n is defined. */voidprint_stars(int n){ int i;

for (i=1; i <= n; i++) printf("*");}

51

/* Improved version */

#include <stdio.h>#define NUMLINES 4 /* number of lines in the triangle */#define SPACE ' '#define STAR '*'

void print_chars(char ch, int n);

int main(void) { int curr_line; /* line to be printed */ for (curr_line = 1; curr_line <= NUMLINES; curr_line ++) { /* draw a line */ print_chars(SPACE, NUMLINES - curr_line); print_chars(STAR, 2 * curr_line - 1); printf("\n"); }

return (0);}

52

/* * Prints the character ch n times. * Pre: n and ch are defined. */

voidprint_chars(char ch, int n){ int i;

for (i=1; i <= n; i++) printf("%c", ch);}

53

istruzione do-while

1. prendi in input un valore2. se il valore non è nell’intervallo specificato, torna al passo 1

For e while testano la condizione prima di eseguire il corpo del cicloInput interattivo: il corpo del ciclo deve essere eseguitoalmeno una volta

do { printf(“Enter a letter from A through E>“); scanf(“%c”, &choice);} while (choice < ‘A’ || choice > ‘E’);

54

do-whilesintassi

do statementwhile (condition)

esempio

/* Find first even number */do scanf(“%d”, &num);while (num % 2 != 0);

Si esegue statement. Poi, condition viene testata: se è vera,si esegue di nuovo statement e si testa condition. Quando iltest di condition produce false, si esce dal ciclo e si eseguel’istruzione successiva.Nota: se il corpo contiene più istruzioni, quete devono essere racchiuse tra parentesi graffe.

55

Cicli controllati da flagSe la condizione di ripetizione di un ciclo è molto complessa, viene sostituita da un flag.flag: variabile intera utilizzata per indicare se un eventoè accaduto (1) oppure no (0).

Esempio:

int get_int (int n_min, int n_max)

prende in input un numero intero compreso fran_min e n_max

56

funzione scanfscanf restituisce come valore di ritorno il numero diargomenti effettivamente letti.Se la scanf trova dati non validi, es. o al posto di 0,ritorna il numero di dati letti prima di trovare l’errore.

input_status = scanf(“%d%d%lf”, &n1, &n2, &x);

se inserisco @3 15 5.3la scanf ritorna 0

57

/* * Returns the first integer between n_min and n_max entered * as data. * Pre : n_min <= n_max * Post: Result is in the range n_min through n_max. */intget_int (int n_min, int n_max){ int in_val, /* input - number entered by user */ status; /* status value returned by scanf */ char skip_ch; /* character to skip */ int error; /* error flag for bad input */

/* Get data from user until in_val is in the range. */ do { /* No errors detected yet. */ error = 0;

/* Get a number from the user. */ printf("Enter an integer in the range from %d ", n_min); printf("to %d inclusive> ", n_max); status = scanf("%d", &in_val);

58

/* Validate the number. */ if (status != 1) { /* in_val didn't get a number */ error = 1; scanf("%c", &skip_ch);

printf("Invalid character >>%c>>. ", skip_ch); printf("Skipping rest of line.\n"); } else if (in_val < n_min || in_val > n_max) { error = 1; printf("Number %d is not in range.\n", in_val); }

/* Skip rest of data line. */ do scanf("%c", &skip_ch); while (skip_ch != '\n'); } while (error);

return (in_val);}

59

Debuggingosservare l’output per capire in quale parte del programmaviene generato l’errore, quindi concentrarsi su tale sezione di programma.

• utilizzo di programmi debugger• debugging “a mano”

60

programmi debugger - tracingpermettono di eseguire un’istruzione alla volta (tracing)e osservare il contenuto di alcune variabili (selezionatedal programmatore) dopo l’esecuzione di ogni istruzione.

• contenuto delle variabili di input dopo la scanf• aggiornamento delle variabili di controllo e degli accumulatori ad ogni iterazione di un ciclo

E’ possibile controllare:

61

programmi debugger - breakpoints

Se il programma è molto lungo, posso inserire dei breakpoint dopo ogni passo dell’algoritmo.Il debugger esegue il programma fino al prossimo breakpoint: a questo punto posso esaminare il contenutodelle variabili.

Se la parte di programma compresa tra due breakpointnon è corretta, posso suddividerla ulteriormente aggiungendo breakpoint, oppure farne il tracing.

62

debugging “a mano”inserire chiamate a printf per visualizzare il contenuto delle variabili nei punti critici del programma.

while (score != SENTINEL) { sum += score; if (DEBUG) printf(“***** score is %d, sum is %d\n”, score, sum); printf("Enter next score (%d to quit)> ", SENTINEL); scanf("%d", &score); /* Get next score. */}

63

debugging “a mano”per fare il debugging di una sezione di programmainserire prima di tale sezione la direttiva

#define DEBUG 1

per escludere una sezione dal debugging utilizzare

#define DEBUG 0

• inserire \n alla fine delle printf utilizzate per il debugging• l’aggiunta di printf all’interno di un ciclo può rendere necessaria l’aggiunta di parentesi graffe per racchiudere il corpo del ciclo

64

Erroripuò accadere di progettare cicli il cui corpo viene eseguito una volta in più o una volta in meno.

for (count = 0; count <= n; count++)sum += count;

il ciclo viene eseguito n+1 volte!

65

Errorigli errori nei cicli controllati da contatore spesso si verificano sui “confini” (i.e. sui valori iniziale e finale) della variabile di controllo

• testare il corpo del ciclo con la variabile di controllo settata al valore iniziale• scegliere un valore per la variabile di controllo tale che la condizione di ripetizione sia vera, ma diventi falsa dopo un’iterazione, ed eseguire il ciclo fino alla terminazione

66

Esempio

for (n = 1; n <= 5; n++);printf(“ciao\n”);

stampa “ciao” una sola volta (e non 5 volte)il corpo del for è l’istruzione vuota

67

Esempio

x = 0;while (x < 10)

printf(“x e’ %d\n”, x);x = x +1;

stampax e’ 0x e’ 0...

mancano le graffe attorno al corpo del ciclo

68

printf(“Experiment successful? (Y/N)> “);scanf(“%c”, &ans);if (ans == ‘Y’) { printf(“Enter one number per line (%d to quit)\n> ”, SENT); scanf(“%d”, &data); while (data != SENT) { sum += data; printf(“> “);

scanf(“%d, &data);

} else { printf(“Try again tomorrow\n”);}

manca la } per il corpo del while;viene segnalato un errore sull’else

69

Esempioscanf(“%lf”, &amount);while (balance != 0.0); {

...scanf(“%lf”, &amount);

}

voglio eseguire transazioni finchè il bilancio è positivo;se il bilancio da positivo diventa negativo senza diventare0, il while esegue all’infinito

sostituire la condizione di controllo con

(balance > 0.0)

70

Esempiodo { ... printf(“One more time? “); printf(“(1 to continue, 0 to quit)> “); scanf(“%d”, &again);} while (again = 1);

la condizione di controllo esegue un assegnamento,quindi il ciclo non termina.Sostituire la condizione di controllo con

(again == 1)