Vai al contenuto
Appunti di InformaticaUniTo · 2026/27

Canale B · Laboratorio 02 · Programmazione I

Laboratorio 02: operatori e tipi

Il secondo laboratorio mette alla prova le lezioni 02B, 02C, 03A e 03B: si leggono programmi già scritti, si indovina che cosa stampano, si cercano gli errori e si scrivono programmi piccoli. Qui trovi ogni esercizio con la soluzione provata, e il perché di ogni risultato strano.

Slide
Lab02 «Operatori e Tipi», laboratorio canale B · 18 pagine, con la tabella dei tipi e il codice di partenza
Laboratorio
Elisa Marengo (turno B2, lun 12/10) e Valerio Basile (turno B1, mar 13/10) · 14–17 · laboratorio Turing
Tempo di studio
2–3 ore, davanti a un computer
  • Definizione o risultato da sapere
  • Trappola / errore tipico
  • Conta all'esame
  • Oltre le slide
  • L'idea e il metodo, passo per passo
  • Da ricordare

La lezione in 8 punti

  • Il laboratorio usa sei programmi già pronti, il codice di partenza: si leggono, si provano, si completano o si correggono. Poi si scrivono tre programmi nuovi.
  • Divisione: tra due interi / dà la parte intera, % il resto. Basta un reale per avere la divisione con la virgola: 99 / 50 fa 1, 99 / 50.0 fa 1.98.
  • Un int che supera il massimo, 2 147 483 647, va in overflow e ricomincia dai negativi: il compilatore non avvisa.
  • Le espressioni seguono le precedenze: *, /, % prima di + e -, da sinistra a destra. Le parentesi cambiano l'ordine.
  • const dichiara una costante: un valore che il programma non può cambiare.
  • Una media si calcola dividendo per 3.0, non per 3. Per arrotondare ci sono floor, ceil e round, mentre il cast a int taglia.
  • I numeri con la virgola sono approssimati: 8.136 * 1000 convertito in int dà 8135.
  • Tutti i puntatori hanno la stessa dimensione, 8 byte su un computer a 64 bit: contengono un indirizzo, qualunque sia il tipo puntato.

Canali A, B e C

Canale B. È il secondo laboratorio, al laboratorio Turing, dalle 14 alle 17: turno B2 lunedì 12/10 con Elisa Marengo, turno B1 martedì 13/10 con Valerio Basile. Gli esercizi riprendono la teoria delle lezioni 02B (tipi, operatori, precedenze), 02C (scanf, puntatori), 03A (scambio) e 03B (reali e conversioni).

Canali A e C. Secondo la scheda del corso i laboratori hanno la stessa sequenza nei tre canali e gli stessi esercizi su CodeRunner. Le slide 2026/27 dei canali A e C per questo laboratorio non le ho viste: controlla il giorno del tuo turno su Moodle.

I programmi del codice di partenza li ho compilati e provati tutti con gcc 16.1 su Windows 11 a 64 bit. Dove il risultato su Linux, al laboratorio Turing, può essere diverso, lo dico.

§1

Aritmetica e overflow: aritmetica.c

slide 2

Il primo programma va letto prima di eseguirlo: per ogni printf prova a indovinare che cosa stampa, poi controlla. La slide dice di compilarlo con:

gcc -Wall aritmetica.c -o aritmetica        (Linux e macOS)
gcc -Wall aritmetica.c -o aritmetica.exe    (Windows)

Nota · Senza -Werror, per una volta

Il programma dichiara tre variabili che non usa, n1, p e t. Con -Wall gcc stampa tre avvisi unused variable; con -Wall -Werror non compila. Per questo la slide usa solo -Wall: gli avvisi si leggono, ma il programma parte. All'esame invece vale -Werror, e le variabili inutili vanno tolte.

Le divisioni

printf("99 / 50 = %d\n", 99 / 50);       // divisione intera
printf("99 %% 50 = %d\n", 99 % 50);      // resto della divisione intera
printf("99 / 50.0 = %f\n", 99 / 50.0);   // divisione reale
printf("99.0 / 50 = %f\n", 99.0 / 50);   // divisione reale
99 / 50 = 1
99 % 50 = 49
99 / 50.0 = 1.980000
99.0 / 50 = 1.980000

Due cose da notare.

  • %% dentro la stringa di printf stampa un solo %. Un % da solo sarebbe l'inizio di uno specificatore.
  • Basta un reale, a sinistra o a destra, per avere la divisione con la virgola: è la promozione di tipo della lezione 03B.

Poi il programma prova il cast in due posti diversi, con int m = 99 e int n = 50:

m / n, con cast su m: 1.980000
m / n, con cast sul risultato: 1.000000

(double) m / n converte m prima della divisione; (double) (m / n) converte il risultato di una divisione già intera. È la trappola della lezione 03B.

L'overflow

int max = INT_MAX;
printf("INT_MAX = %d\n", max);
max = max + 3;
printf("dopo aver sommato 3 = %d\n", max);
INT_MIN = -2147483648
INT_MAX = 2147483647
dopo aver sommato 3 = -2147483646

INT_MAX e INT_MIN sono il massimo e il minimo di un int, definiti in limits.h. Aggiungendo 3 al massimo, il numero esce dall'intervallo e ricomincia dai negativi, come il contachilometri all'indietro della lezione 03 di Fondamenti: è l'overflow in complemento a 2. Il compilatore non avvisa.

Trappola · L'overflow degli int con il segno non è garantito

Per lo standard del C, l'overflow di un intero con il segno è un comportamento indefinito: il risultato −2 147 483 646 è quello che succede quasi sempre, ma il linguaggio non lo promette. Il programma va scritto in modo che l'overflow non capiti.

L'ultima riga stampa l'indirizzo di max con %p: cambia a ogni esecuzione, come nella lezione 02C.

Prova tu

Che cosa stampano printf("%d", 17 / 5), printf("%d", 17 % 5) e printf("%f", 17 / 5.0)?

3, 2 e 3.400000.

Da ricordare

  • Tra interi: / dà la parte intera, % il resto. Con un reale: divisione con la virgola.
  • %% stampa un %. Superare INT_MAX è overflow.
§2

Operazioni su interi

slide 3

Il primo programma da scrivere da zero: operazioni_su_interi.c. Chiede due interi n1 e n2, e stampa la somma, il prodotto, la divisione intera, la divisione reale e il resto.

#include <stdio.h>

int main(void) {
    int n1;
    int n2;
    printf("Inserisci due numeri interi: ");
    scanf("%d %d", &n1, &n2);

    int somma = n1 + n2;
    printf("Somma: %d\n", somma);
    printf("Prodotto: %d\n", n1 * n2);
    printf("Divisione intera: %d\n", n1 / n2);
    printf("Divisione reale: %f\n", (double)n1 / n2);
    printf("Resto: %d\n", n1 % n2);
}

Con l'input 17 5 stampa somma 22, prodotto 85, divisione intera 3, divisione reale 3.400000 e resto 2.

Trappola · Con i negativi

Con -17 5 il programma stampa divisione intera −3 e resto −2. In C la divisione intera taglia verso lo zero, e il resto ha il segno del primo numero. In matematica, nella lezione di Matematica Discreta, il resto è sempre positivo: lì −17 diviso 5 dà quoziente −4 e resto 3. Attenzione quando usi % con i negativi.

Il programma non controlla n2 = 0: con 0 come secondo numero, la divisione intera fa fallire il programma. Lo saprai sistemare con le condizioni.

Prova tu

Che cosa stampa il programma con l'input 7 2?

Somma 9, prodotto 14, divisione intera 3, divisione reale 3.500000, resto 1.

Da ricordare

  • La divisione reale tra due int si ottiene con un cast su un operando.
  • In C, con i negativi, / taglia verso lo zero e % ha il segno del primo numero.
§3

L'ordine di valutazione

slide 4–7

Le slide chiedono di calcolare a mano tre espressioni, prima di provarle. Si usano le precedenze della lezione 02B: prima le parentesi, poi *, / e % da sinistra a destra, poi + e - da sinistra a destra.

EspressionePassiRisultato
7 + 3 * 6 / 2 - 13 * 6 = 18, 18 / 2 = 9, 7 + 9 = 16, 16 - 1 = 1515
2 % 2 + 2 * 2 - 2 / 22 % 2 = 0, 2 * 2 = 4, 2 / 2 = 1, 0 + 4 - 1 = 33
(3 * 9 * (3 + (9 * 3 / (3))))9 * 3 / 3 = 9, 3 + 9 = 12, 3 * 9 * 12 = 324324

Sono i risultati delle slide 5, e quelli che stampa il programma.

Quale formula è ?

La slide 6 dà sei espressioni e chiede quali calcolano . La regola: la moltiplicazione viene prima della somma, e le parentesi intorno a una moltiplicazione non cambiano niente.

#EspressioneGiusta?Perché
1a * x * x * x + 7sìle moltiplicazioni prima, poi + 7
2a * x * x * (x + 7)nola parentesi fa sommare 7 a x prima
3(a * x) * x * (x + 7)nostesso errore della 2
4(a * x) * x * x + 7sìla parentesi intorno a a * x non cambia niente
5a * (x * x * x) + 7sìcome la 4
6a * x * (x * x + 7)noil 7 entra nella moltiplicazione

Ho controllato con a = 2 e x = 3: la formula vale 61. Le espressioni 1, 4 e 5 danno 61; la 2 e la 3 danno 180; la 6 dà 96.

Prova tu

Quanto vale 10 - 4 - 3? E 10 - (4 - 3)?

3, perché - si fa da sinistra: 10 - 4 = 6, poi 6 - 3 = 3. Con le parentesi: 4 - 3 = 1, poi 10 - 1 = 9.

Da ricordare

  • *, /, % prima di + e -; a parità, da sinistra a destra.
  • Una parentesi intorno a una moltiplicazione non cambia niente; una intorno a una somma sì.
§4

Circonferenza e area: circonferenza.c

slide 8

Il programma circonferenza.c legge il raggio e deve stampare circonferenza e area. Le due righe di calcolo sono lasciate da completare: ricorda che la circonferenza è e l'area è .

#include <stdio.h>

int main(void) {
    // La costante pi greco
    const float PI_GRECO = 3.1415926535f;

    // Chiediamo all'utente il raggio
    printf("Inserisci il raggio del cerchio: ");
    float r;
    scanf("%f", &r);

    // Calcolo della circonferenza e dell'area
    float circonferenza = 2 * PI_GRECO * r;
    printf("La circonferenza del cerchio e': %f\n", circonferenza);

    float area = PI_GRECO * r * r;
    printf("L'area del cerchio e': %f\n", area);
}

Con il raggio 3 stampa 18.849556 e 28.274334. Così com'è, il codice di partenza non compila nemmeno con -Wall: circonferenza e area sono usate nelle printf ma non dichiarate.

Nota · Prova con il raggio 2

Con il raggio 2 la circonferenza e l'area vengono uguali, tutte e due 12.566371. Non è un errore: e fanno tutti e due . Per controllare il programma usa un altro raggio.

La domanda: che cosa vuol dire const?

const davanti a una dichiarazione la rende una costante: il valore si dà all'inizio e poi non si può più cambiare. Se scrivi PI_GRECO = 3; più avanti, gcc si ferma con error: assignment of read-only variable 'PI_GRECO'. Il nome tutto maiuscolo è una convenzione per le costanti, non un obbligo.

Il commento del codice ricorda che math.h ha già la costante M_PI. Le slide avvisano che, su Linux, usando math.h può servire l'opzione -lm.

Prova tu

Con il raggio 1, che cosa devono stampare circonferenza e area?

La circonferenza , circa 6.283185, e l'area , circa 3.141593.

Da ricordare

  • const fa una variabile che non si può più modificare.
  • Per provare un programma, scegli dati che non diano risultati uguali per caso.
§5

Trovare gli errori

slide 9–11

All'esame il compilatore ti dice dove ha trovato un errore, ma non sempre perché. Qui si allena l'occhio: prima si cercano gli errori leggendo, poi si controlla con gcc.

Il programma della slide 9

#include <stdio.h>
int main() {
int x, y;
printf("Inserisci due interi: ");
scanf("%d %d", &x, y)
z = x + y;
printf("La somma %d + %d vale ", x, y);
printf("%d\n", &z);
}

Gli errori sono quattro:

  1. in scanf manca la & davanti a y: scanf vuole un indirizzo;
  2. manca il ; dopo la scanf;
  3. z non è dichiarata;
  4. l'ultima printf stampa &z, l'indirizzo, invece del valore z.

gcc con -Wall -Werror ne trova subito tre: format '%d' expects argument of type 'int *', but argument 3 has type 'int', expected ';' before 'z' e 'z' undeclared. Il quarto lo segnala dopo aver corretto gli altri. Il programma corretto:

#include <stdio.h>

int main(void) {
    int x, y;
    printf("Inserisci due interi: ");
    scanf("%d %d", &x, &y);
    int z = x + y;
    printf("La somma %d + %d vale ", x, y);
    printf("%d\n", z);
}

errori.c: gli otto errori

La slide 11 chiede di trovare, senza compilare, gli 8 errori di errori.c. Prova da solo prima di leggere.

#include <stdio.h>

int main(void) {
    float f1, f2;
    printf("Inserisci due numeri reali: ");
    scanf("%f %d", &f1, &f2);

    float risultato = (f1 + f2) / 2);
    printf("Risultato = %f %d\n", &risultato);

    // Calcoliamo il quadrato
    // float quadrato = risultato * risultato;
    printf("Il quadrato e' \n", quadrato) }
}
#RigaErroreCorrezione
1scanf("%f %d", …)%d per un float%f %f
2(f1 + f2) / 2);una parentesi chiusa di troppo(f1 + f2) / 2;
3printf(…, &risultato)passa l'indirizzo invece del valorerisultato
4"Risultato = %f %d\n"%d senza un valore da stamparetogliere %d
5// float quadrato = …la dichiarazione è commentata: quadrato non esistetogliere //
6"Il quadrato e' \n"manca lo specificatore per quadrato%f
7printf(…) }manca il ; dopo la printf;
8} finaleuna graffa chiusa di troppotogliere una }

Compilando il file originale con -Wall -Werror, gcc 16.1 segnala gli errori 1, 2, 3, 4, 5, 7 e 8. Il 6 lo segnala solo dopo le altre correzioni, come «troppi argomenti per il formato». Il programma corretto, con 3 e 4, stampa Risultato = 3.500000 e Il quadrato e' 12.250000.

Prova tu

Perché printf("%d\n", &z); è un errore anche se compila senza -Wall?

Perché &z è l'indirizzo di z, non il suo valore: il programma stamperebbe un numero senza senso. Con -Wall -Werror gcc lo blocca, perché %d vuole un int e riceve un int *.

Da ricordare

  • In scanf serve la &; in printf no.
  • Ogni specificatore vuole un valore del tipo giusto, nello stesso ordine.
  • Il primo errore può nasconderne altri: correggi e ricompila.
§6

La media di tre numeri: media.c

slide 12

media.c legge tre interi x, y, z e calcola la media in tre modi. Con l'input 8, 2, 3, che danno somma 13:

Riga del programmaChe cosa faStampa
int media1 = (x + y + z) / 3;divisione intera4
double media2 = (x + y + z) / 3;divisione intera, poi convertita in double4.000000
double media3 = (x + y + z) / 3.0;divisione con la virgola4.333333

Solo la terza è giusta: è la divisione che inganna della lezione 03B.

Le tre varianti del commento

Il codice chiede che cosa fanno tre modi di scrivere media3, e dove avviene la conversione da int a double. Con 1, 2, 5, che danno somma 8:

VarianteTipi delle operazioniDove si converteValore
(x + y + z) / 3.0somma int; divisione tra int e doublela somma diventa double per la divisione2.666667
(double)(x + y + z) / 3somma int; cast; divisione tra double e intil cast sulla somma, poi il 3 diventa double2.666667
(double)((x + y + z) / 3)somma int; divisione intera; castil cast sul risultato, quando la virgola è già persa2.000000

Arrotondare

Il programma arrotonda media3 in quattro modi. Con 1, 2, 5, cioè 2.666667:

EspressioneChe cosa faRisultato
(int)media3taglia la parte dopo la virgola2
(int)floor(media3)arrotonda per difetto2
(int)round(media3)arrotonda al più vicino3
(int)ceil(media3)arrotonda per eccesso3

Con i numeri positivi il cast e floor danno lo stesso risultato. Con i negativi no: con −2.5 il cast dà −2, floor dà −3, ceil dà −2 e round dà −3, perché a metà strada round si allontana dallo zero.

8.136 per 1000

L'ultima parte del programma calcola (int)(f * 1000) con f = 8.136, e stampa 8135, non 8136. Il motivo è quello della lezione 03B: 8.136 non si scrive esattamente in base 2. In memoria è un po' meno di 8.136, e f * 1000 vale 8135.99999999999909… Il cast a int taglia, e resta 8135. Con (int)round(f * 1000) si ottiene 8136.

Prova tu

Con l'input 8, 2, 3, che cosa stampa (int)ceil(media3)?

5: media3 vale 4.333333, e ceil arrotonda per eccesso a 5.

Da ricordare

  • Per una media con la virgola si divide per 3.0, o si fa un cast su un operando.
  • Il cast a int taglia; per arrotondare al più vicino serve round.
§7

La tabella dei tipi e dim_tipi.c

slide 13–15

Le slide 13 e 14, e il foglio a parte, riportano la tabella dei tipi del C con dimensione, intervallo e specificatore. La slide 14 lo dice in grande: non serve impararla a memoria. La versione con le spiegazioni è nella lezione 02B.

TipoUsoByte (64 bit)Specificatore
charcaratteri ASCII1%c
shortinteri2%hd
intinteri4%d
longinteri8 su Linux, 4 su Windows%ld
long longinteri8%lld
unsigned intnaturali4%u
size_tdimensioni8%zu
floatreali4%f
doublereali8%lf in scanf, %f in printf

Gli unsigned partono da 0 e arrivano al doppio: un unsigned char va da 0 a 255, un unsigned int da 0 a 4 294 967 295.

Che cosa stampa dim_tipi.c

dim_tipi.c stampa la dimensione di ogni tipo con sizeof e il suo intervallo, con le costanti di limits.h e float.h. Sul mio PC, Windows 11 a 64 bit:

sizeof(long)     = 4  intervallo: -2147483648, 2147483647
sizeof(long long)= 8  intervallo: -9223372036854775808, 9223372036854775807
...
sizeof(float) = 4  intervallo: 1.175494e-38, 3.402823e+38
sizeof(double)= 8  intervallo: 2.225074e-308, 1.797693e+308
...
sizeof(char*)    = 8
sizeof(int*)     = 8
sizeof(double*)  = 8

long vale 4 byte su Windows e 8 su Linux: la tabella lo avvisa, le dimensioni dipendono dal sistema. Al laboratorio Turing, con Linux, vedrai 8.

La domanda: che cosa hanno di speciale i puntatori?

Tutti i tipi puntatore hanno la stessa dimensione: 8 byte su un computer a 64 bit. Il perché è nella lezione 02C: un puntatore contiene un indirizzo, e tutti gli indirizzi di una macchina hanno la stessa lunghezza, qualunque cosa ci sia a quell'indirizzo. Un char è di 1 byte e un double di 8, ma i loro indirizzi sono tutti e due di 8 byte.

L'ultima parte del programma usa size_t, il tipo senza segno restituito da sizeof: 100 int occupano 100 * sizeof(int) = 400 byte.

Prova tu

Su un computer a 64 bit, quanto valgono sizeof(char), sizeof(char*) e sizeof(int) * 10?

1, 8 e 40.

Da ricordare

  • La tabella dei tipi non va imparata a memoria: servono gli specificatori più usati.
  • Ogni puntatore occupa 8 byte su 64 bit, qualunque sia il tipo puntato.
§8

La documentazione del C

slide 16

Nessuno ricorda tutte le funzioni e tutti gli specificatori: si cercano nella documentazione. Il riferimento più usato è cppreference, che ha una versione da scaricare e usare senza Internet. La slide spiega come:

  1. vai su cppreference.com/w/c;
  2. in fondo alla pagina, «Offline version»: scarica la versione più recente;
  3. apri la pagina html-book/reference/en/c.html;
  4. nella sezione degli header cerca <stdio.h> e leggi la documentazione completa di printf.

La slide avverte che la documentazione vera è molto più dettagliata di quello visto a lezione. Serve proprio a imparare a cercare: nella pagina di printf trovi, per esempio, che %% stampa un % e che %.3f fissa le cifre dopo la virgola.

Prova tu

Nella pagina di printf, quale specificatore stampa un intero in esadecimale?

%x, con le lettere minuscole, o %X con le maiuscole. printf("%x", 255) stampa ff.

Da ricordare

  • cppreference è il riferimento del C, anche senza Internet.
  • Per ogni funzione nuova, guarda prima la sua pagina.
§9

La spesa al mercato

slide 17

Il programma mercato.c calcola la spesa per 3 pacchi di orecchiette a 1.50 euro e 1 kg e mezzo di pomodori a 2.50 euro al kg. Le slide chiedono variabili con tipi adatti, una variabile per il totale, indentazione e commenti.

#include <stdio.h>

int main(void) {
    // prezzi unitari, in euro
    double prezzoOrecchiette = 1.50;   // un pacco
    double prezzoPomodori = 2.50;      // al kg

    // quantita' acquistate
    int pacchiOrecchiette = 3;
    double kgPomodori = 1.5;

    double totale = pacchiOrecchiette * prezzoOrecchiette + kgPomodori * prezzoPomodori;
    printf("Spesa totale: %.2f euro\n", totale);
}

Stampa Spesa totale: 8.25 euro: 3 per 1.50 fa 4.50, 1.5 per 2.50 fa 3.75.

Le scelte dei tipi: i pacchi si contano, quindi int; i chili e i prezzi hanno la virgola, quindi double. Il %.2f stampa i centesimi.

Con le quantità da tastiera

La seconda parte chiede di leggere le quantità da tastiera invece di scriverle nel codice. Servono due scanf, con lo specificatore giusto per ogni tipo:

int pacchiOrecchiette;
double kgPomodori;
printf("Pacchi di orecchiette: ");
scanf("%d", &pacchiOrecchiette);
printf("Kg di pomodori: ");
scanf("%lf", &kgPomodori);

Con 3 pacchi e 2 kg stampa Spesa totale: 9.50 euro. Il %lf per il double è obbligatorio: con %f, -Wall -Werror non compila.

Prova tu

Se i prezzi fossero in centesimi, che tipo useresti?

int: 150 e 250 centesimi sono interi esatti. Molti programmi che contano soldi fanno così, per evitare le approssimazioni dei reali.

Da ricordare

  • Le cose che si contano sono int; le misure con la virgola sono double.
  • Leggere un double: %lf.
§10

Gli scambi di variabili

slide 18

L'ultimo esercizio riprende la lezione 03A. Prima si legge e si prova scambio.c, che scambia x = 5 e y = 8 con una variabile intermedia e stampa x: 8, y: 5. Poi si scrive scambio4.c: quattro variabili, in cui v1 prende il valore di v2, v2 di v3, v3 di v4 e v4 di v1.

La soluzione completa, provata, è nella lezione 03A, nell'esercizio «scambio4.c del Laboratorio 02». L'idea: una sola variabile d'appoggio, che salva v1 prima che venga sovrascritta.

int temp = v1;
v1 = v2;
v2 = v3;
v3 = v4;
v4 = temp;

Con 10, 20, 30, 40 alla fine i valori sono 20, 30, 40, 10.

Prova tu

E se volessi il giro al contrario, con v1 che prende il valore di v4?

Si salva la variabile sovrascritta per prima, che ora è v4: int temp = v4; v4 = v3; v3 = v2; v2 = v1; v1 = temp;.

Da ricordare

  • Una rotazione di quattro variabili richiede una sola variabile d'appoggio.
  • Si salva per prima la variabile che verrà sovrascritta per prima.
§11

I simboli di questa lezione

SimboloSi leggeVuol direEsempio
%«modulo»il resto della divisione intera99 % 50 vale 49
%%«percento percento»in printf: stampa un %printf("100%%")
INT_MAX, INT_MIN«int max», «int min»il massimo e il minimo di un int, da limits.h2147483647
const«const»la variabile non si può modificareconst float PI = 3.14f;
M_PI«emme pi»la costante pi greco di math.h
floor, ceil, round«floor», «ceil», «round»arrotondano per difetto, per eccesso, al più vicinoceil(4.3) vale 5
sizeof«size of»i byte occupati da un tiposizeof(int) vale 4
%zu«percento zeta u»specificatore per size_t
-Wall«meno W all»gcc mostra gli avvisi
§12

Verso l'esame

esame

L'esame è al PC, con CodeRunner: il tuo codice viene compilato con -Wall -Werror e le sue stampe confrontate con quelle attese. Questo laboratorio allena quasi tutto quello che serve per non perdere punti nei primi esercizi:

  1. leggere gli errori del compilatore e correggerli uno alla volta, come in errori.c;
  2. scegliere i tipi: int per contare, double per misurare;
  3. le divisioni: intera quando vuoi la parte intera, con la virgola quando vuoi la media;
  4. gli specificatori giusti in printf e in scanf, compresi %lf e %.2f;
  5. niente variabili inutilizzate: con -Werror bloccano la compilazione.

Metodo · Prima di consegnare un esercizio

  1. Compila con gcc -Wall -Werror. Se ci sono errori, correggi il primo e ricompila.
  2. Prova con dati scelti bene: un caso normale, uno con la virgola, uno con i negativi o lo zero.
  3. Calcola a mano almeno un risultato e confrontalo con la stampa.
  4. Controlla la forma della stampa: spazi, a capo, numero di cifre.
§13

Quiz

come all'esame
  1. Che cosa stampa printf("%d %d", 99 / 50, 99 % 50);?
  2. Quanto vale 7 + 3 * 6 / 2 - 1 in C?
  3. Quale espressione calcola ?
  4. Con int x = 1, y = 2, z = 5; quanto vale (double)((x + y + z) / 3)?
  5. Che cosa stampa printf("%d", (int)(8.136 * 1000));?
  6. Su un computer a 64 bit, quanto vale sizeof(char*)?
  7. Perché aritmetica.c non compila con -Wall -Werror?
  8. Quale riga legge correttamente i chili di pomodori in double kg?
  9. Con -17 e 5, che cosa stampa printf("%d %d", -17 / 5, -17 % 5);?
§14

Esercizi

con soluzioni

1 · Riscaldamento: indovina le stampe base

Senza compilare, scrivi che cosa stampano: (a) printf("%d", 20 / 3); (b) printf("%d", 20 % 3); (c) printf("%f", 20 / 3.0); (d) printf("%.1f", 20 / 3.0); (e) printf("%d%%", 50);

Soluzione

(a) 6. (b) 2. (c) 6.666667. (d) 6.7, arrotondato. (e) 50%.

2 · Riscaldamento: precedenze base

Calcola a mano: (a) 8 - 2 * 3; (b) (8 - 2) * 3; (c) 20 / 4 / 5; (d) 20 / (4 / 5); (e) 7 % 3 * 2.

Soluzione

(a) 2. (b) 18. (c) 1, da sinistra: 20 / 4 = 5, poi 5 / 5 = 1. (d) Errore a runtime: 4 / 5 tra interi fa 0, e dividere per zero fa fallire il programma. (e) 2: 7 % 3 = 1, poi 1 * 2 = 2.

3 · Riscaldamento: il tipo giusto base

Che tipo usi per: (a) l'età in anni; (b) la media dei voti; (c) il numero di byte di un file; (d) la lettera iniziale di un nome; (e) il prezzo in euro con i centesimi?

Soluzione

(a) int. (b) double. (c) size_t, il tipo delle dimensioni, o long long se il file è enorme. (d) char. (e) double, oppure un int che conta i centesimi.

4 · Secondi in ore, minuti e secondi medio

Scrivi un programma che legge un numero di secondi e stampa ore, minuti e secondi. Con 3725 deve stampare 1 h 2 min 5 s.

Soluzione
#include <stdio.h>

int main(void) {
    int totale;
    scanf("%d", &totale);
    int ore = totale / 3600;
    int minuti = (totale % 3600) / 60;
    int secondi = totale % 60;
    printf("%d h %d min %d s\n", ore, minuti, secondi);
}

3725 / 3600 fa 1 ora; il resto, 125, diviso 60 fa 2 minuti; 3725 % 60 fa 5 secondi. / e % insieme separano le unità.

5 · Le temperature medio

Scrivi un programma che legge una temperatura in gradi Celsius, un double, e la stampa in gradi Fahrenheit con una cifra dopo la virgola. La formula è . Attenzione a come scrivi 9/5.

Soluzione
#include <stdio.h>

int main(void) {
    double c;
    scanf("%lf", &c);
    double f = c * 9.0 / 5.0 + 32;
    printf("%.1f\n", f);
}

Con 100 stampa 212.0, con 37 stampa 98.6. Se scrivi c * (9 / 5) + 32, la parentesi fa la divisione intera 9 / 5 = 1, e il risultato è sbagliato: con 100 viene 132.0.

6 · Media e arrotondamenti tipo esame

Scrivi un programma che legge quattro voti interi e stampa la media con 2 cifre dopo la virgola, poi la media arrotondata al voto intero più vicino. Con 27, 28, 30, 24 deve stampare 27.25 e 27.

Soluzione
#include <stdio.h>
#include <math.h>

int main(void) {
    int a, b, c, d;
    scanf("%d %d %d %d", &a, &b, &c, &d);
    double media = (a + b + c + d) / 4.0;
    printf("%.2f\n", media);
    printf("%d\n", (int)round(media));
}

La somma 109 divisa per 4.0 fa 27.25; round dà 27. Con i voti 27, 28, 30, 25 la media è 27.5 e round dà 28. Su Linux si compila con -lm.

7 · Trova gli errori tipo esame

Il programma dovrebbe leggere base e altezza di un triangolo, due double, e stampare l'area. Trova e correggi gli errori: double b, h; scanf("%lf %lf", b, h); double area = 1 / 2 * b * h; printf("Area: %d\n", area);

Soluzione
  1. In scanf mancano le &: &b, &h. Con -Wall -Werror non compila.
  2. 1 / 2 è una divisione intera e fa 0: l'area sarebbe sempre 0. Va scritto b * h / 2 oppure 0.5 * b * h.
  3. %d per un double: serve %f. Con -Wall -Werror non compila.

Corretto: scanf("%lf %lf", &b, &h); double area = b * h / 2; printf("Area: %f\n", area);.

§15

Domande di ripasso

autoverifica

Rispondi a voce alta o per iscritto, poi apri la risposta.

Che differenza c'è tra 99 / 50 e 99 / 50.0?

Il primo è una divisione tra interi e dà 1. Nel secondo c'è un reale, quindi la divisione è con la virgola e dà 1.98.

Che cosa succede sommando 3 a INT_MAX?

Il numero esce dall'intervallo degli int e, di solito, ricomincia dai negativi: −2 147 483 646. È un overflow, e per il C è comportamento indefinito.

A che cosa serve const?

A dichiarare una costante: il valore si dà all'inizio e il programma non può più cambiarlo.

Che differenza c'è tra (int)x, floor(x) e round(x)?

(int)x taglia la parte dopo la virgola, verso lo zero. floor arrotonda per difetto, round al più vicino. Con −2.5: −2, −3 e −3.

Perché (int)(8.136 * 1000) dà 8135?

Perché 8.136 non si scrive esattamente in base 2: il prodotto è 8135.999…, e il cast a int taglia.

Perché tutti i puntatori hanno la stessa dimensione?

Perché contengono un indirizzo, e su una macchina tutti gli indirizzi hanno la stessa lunghezza: 8 byte su 64 bit.

Dove si cercano le informazioni su printf e sulle altre funzioni del C?

Nella documentazione, per esempio su cppreference, che ha anche una versione da usare senza Internet.

§16

Glossario

termini
Codice di partenza
I programmi già scritti forniti con il laboratorio, da leggere, provare e completare.
Divisione intera
/ tra due interi: tiene solo la parte intera, tagliando verso lo zero.
Modulo
%: il resto della divisione intera; in C ha il segno del primo numero.
Overflow
Un risultato intero che supera il massimo del suo tipo; per gli int con il segno è comportamento indefinito.
INT_MAX, INT_MIN
Massimo e minimo di un int, definiti in limits.h.
const
Parola chiave che rende una variabile non modificabile.
floor, ceil, round
Funzioni di math.h che arrotondano per difetto, per eccesso e al più vicino.
sizeof
Operatore che dà quanti byte occupa un tipo o una variabile.
cppreference
Sito di documentazione del C e del C++, scaricabile per l'uso senza Internet.
Wall
Opzione di gcc che mostra gli avvisi; con -Werror ogni avviso diventa un errore.
§17

Checklist

0 su 10

Spunta quando sai fare la cosa senza guardare gli appunti. Le spunte restano salvate in questo browser.