Lezione 4: Equivalenza di Istruzioni Iterative

Soluzione di Esercizi

Esercizio 3.1 Scrivere un programma che prende in input n numeri in virgola mobile (float) e stampa la media di tali numeri.

#inlude <stdio.h>

//stampa la media di n numeri
int main() {    
    int n;
    printf("Quanti numeri? ");
    scanf("%d", &n);
    float somma = 0;
    for (int i = 1 ; i <= n ; i++) {
        printf("%2d: ", i);
        float x;
        scanf("%f", &x);
        somma += x;
    }
    printf("La media è %.2f\n", somma/n);
}

Esercizio 3.2 Scrivere un programma che legge un carattere c e un intero n e stampa un triangolo di altezza n fatto con caratteri c.

#inlude <stdio.h>

//stampa un triangolo di caratteri di altezza n
int main() {
    int n;
    char ch;
    printf("Altezza triangolo: ");
    scanf("%d", &n);
    printf("Carattere: ");
    scanf(" %c", &ch);
    for (int r = 1 ; r <= n ; r++) {
        for (int c = 1 ; c <= r ; c++)
            printf("%c", ch);
        printf("\n");
    }
}

Istruzioni iterative

Nella lezione precedente abbiamo introdotto l'istruzione iterativa for. Il C definisce altre due istruzioni iterative. La prima e' il ciclo while che e' usato per ripetere un blocco di istruzioni finche' una condizione e' vera.

while(<condizione>) {
    <istruzioni>
}

Il ciclo do-while ha semantica identica al ciclo while se non che' il blocco di istruzioni e' eseguito almeno una volta.

do {
    <istruzioni>
} while(<condizione>);

In pratica, il ciclo for e' il piu' usato in programmazione, seguito dal ciclo while, mentre si fa poco uso del ciclo do-while.

Equivalenza delle Istruzioni Iterative

In realta' i tre cicli introdotti sono equivalenti tante' che esistono linguaggi di programmazione che non li hanno tutti. Il C ne introduce tre per concedere al programmatore di usare il ciclo che e' sintatticamente piu' corto. In inglese si direbbe "syntactic sugar". Riportiamo di seguito le equivalenze tra i cicli for e while.

while (C) { B } for (; C; ) { B }
for (I; C; E) { B } I; while (C) { B E }
do { B } while(C); B; while (C) { B }
while (C) { B } if (C) { do { B } while (C); }

Esempi

Programma che prende in input un intero n e stampa il numero di cifre di n.

#include <stdio.h>

// stampa il numero di cifre di un intero non negativo
int main() {    
    long long n;
    printf("Digita un intero non negativo: ");
    scanf("%lld", &n);
    int nc = 1;
    while (n > 9) {
        nc++;
        n /= 10;
    }
    printf("Il numero di cifre è %d\n", nc);
}

Programma che determina se un numero intero è un numero primo (diverse versioni).

#include <stdio.h>

// determina se l'intero di input è un numero primo
int main() {    
    long long n;
    printf("Digita un intero positivo: ");
    scanf("%lld", &n);
    long long k = 2;
    while (k < n && (n % k) != 0) k++;
    if (n == 2 || (n % k) != 0) 
        printf("È un numero primo\n");
    else 
        printf("Non è un numero primo\n");
}

/* 1000000007 (10 cifre) circa 10 secondi
 * 10000000033 (11 cifre) circa 100 secondi
 * 100000000003 (12 cifre) circa 15 minuti (stimato)
 * 1000000000039 (13 cifre) più di 2 ore e mezza (stimato)
 * 10000000000000061 (17 cifre) più di 3 anni (stimato) */

Anche se miglioriamo la condizione del while sostituendo k < n con k < n/2, su numeri di 17 cifre impiegherà un anno e mezzo! Un miglioramento molto più significativo si ottiene osservando che se n è un numero composto (cioè non è primo) allora n = pq con 2 ≤ p ≤ q, allora p2 ≤ pq = n. Perciò, esiste un divisore "piccolo" p di n con p ≤ √n. Sostituendo il while con il seguente:

while (k*k < n && (n % k) != 0) k++;

Su numeri di 17 cifre impiega circa un secondo. Un miglioramento pari ad un fattore 108 (cento milioni di volte più veloce).

Programma che legge una linea di testo (una sequenza di caratteri terminata dal carattere '\n') e conta il numero di vocali e di consonanti:

#include <stdio.h>

//conta il numero di vocali e consonanti in una linea di testo
int main() {    
    printf("Inserire una linea di testo: ");
    char c;
    int vocali = 0, cons = 0;
    do {
        scanf("%c", &c);
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
            vocali++;
        else if (c > 'a' && c <= 'z') cons++;
    } while (c != '\n');
    printf("vocali: %d   consonanti: %d\n", vocali, cons);
}

Programma che legge una linea di testo e conta il numero di parole. Per parola si intende una sequenza di caratteri alfabetici di lunghezza massimale:

#include <stdio.h>

int main() {    //conta il numero di parole in una linea di testo
    printf("Inserire una linea di testo: ");
    char c;
    int parole = 0, iniziata = 0;
    do {
        scanf("%c", &c);
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            if (!iniziata) {
                iniziata = 1;
                parole++;
            }
        } else iniziata = 0;
    } while (c != '\n');
    printf("Numero parole: %d\n", parole);
}

Esercizi

Esercizio 4.1 Scrivere un programma che prende in input un intero n e stampa la somma delle cifre di n. Ad esempio, se n = 1205 allora il programma stampa 8.

Esercizio 4.2 Scrivere un programma che legge una linea di testo e stampa la lunghezza della più lunga parola contenuta nella linea di testo. Ad esempio, se la linea di testo è "Qual e' la parola piu' lunga? allora il programma stampa 6 se invece la linea di testo è "Una parola lunghissima", stampa 11.

Esercizio 4.3 Scrivere un programma che legge una linea di testo e stampa la somma dei numeri contenuti nella linea. Ad esempio se la linea è "L'appuntamento è alle 18:40 del 2/11/2010", allora il programma stampa 2081 (2081 = 18+40+2+11+2010).