Lab02 1
Fondamenti di Informatica e Laboratorio T
Lab 02
Tipi semplici in C
Lab02 2
Obiettivo dell’esercitazione
• Acquistare familiarità con i tipi di dato semplici
supportati dal linguaggio C
• Comprenderne alcuni limiti nella
rappresentazione dell’informazione
– Dimensione in byte dei tipi semplici e limiti di
rappresentazione
– Problemi di overflow, underflow, troncamento e
“division by zero”
– Espressioni su interi, razionali, e casting esplicito
Lab02 3
Quanti bit sono usati per un tipo?
• In C il numero di bit utilizzati per ogni tipo
dipende dal compilatore
• Uniche regole:
– short int: almeno 16 bit (2 byte)
– int: a discrezione del compilatore, ma vale sempre:
sizeof(int) >= sizeof (short int)
– long int: almeno 32 bit (4 byte), e vale sempre
sizeof(long int) >= sizeof(int)
Lab02 4
Quanti bit sono usati per un tipo?
– float: nessun limite minimo, ma tipicamente
almeno 32 bit (4 byte)
– double: nessun limite minimo, ma tipicamente
almeno 64 bit (8 byte)
– long double: ???
Lab02 5
Quanti bit sono usati per un tipo?
Come posso conoscere le dimensioni di un tipo?
1. Gli header “limits.h” e “float.h” specificano le costanti
tipiche di un compilatore (vedremo nelle prossime lezioni
cosa sono gli header files)
2. Posso usare l’operatore sizeof
sizeof è un operatore speciale del linguaggio C, che
applicato ad un tipo restituisce il numero di bytes usati
per memorizzare quel tipo
Lab02 6
Esercizio 1
#include <stdio.h>
int main(void)
{
int dim0, dim1, dim2, dim3;
int dim4, dim5, dim6;
dim0 = sizeof(char);
dim1 = sizeof(short int);
dim2 = sizeof(int);
dim3 = sizeof(long int);
dim4 = sizeof(float);
dim5 = sizeof(double);
dim6 = sizeof(long double);
return (0);
}
1. Copiare, compilare edeseguire il seguenteprogramma
2. Utilizzando il debugger e la finestra di “watch”, risponderealle seguenti domande:
a) Quanto vale dim2 prima e
dopo l’esecuzione
dell’assegnamento?
b) Quanti bit sono utilizzati per
rappresentare un intero?
c) Quanti bit sono utilizzati per
rappresentare un float?
Lab02 7
Esercizio 1
CHAR
SHORT INT
INT
LONG INT
FLOAT
DOUBLE
LONG DOUBLE
Lab02 8
Quanti numeri interi posso rappresentare con una variabile di tipo X?
Supponiamo che uno short int sia codificato con 16 bit (2
byte)…
… 16 bit � 216 �ho a disposizione 65536 simboli, ma…
… dobbiamo decidere anche se l’intero è signed o
unsigned…
1. Caso short int (signed short int): -32768 … 32767
-215 … 215 − 1
2. Caso unsigned short int: 0 … 65535
0 … 216 − 1
Lab02 9
Esercizio 2
#include <stdio.h>
int main(void)
{
short int i;
short int k;
k = 10000;
i = 30000 + k;
return (0);
}
1. Copiare, compilare ed eseguire il seguente
programma
2. Utilizzando il debugger e la finestra di
“watch”, rispondere alle seguenti domande:
a) Quanto valgono i e k prima degli
assegnamenti?
b) Secondo voi, quanto dovrebbe valere i dopo
l’assegnamento?
c) Quanto vale effettivamente i dopo
l’assegnamento? Perchè?
3. Modificate il programma, specificando i e k
come variabili unsigned… cosa cambia? Il
comportamento del programma ora è
corretto? Perchè?
Lab02 10
Esercizio 2
BASE 10
10000
30000
---------------
40000
BASE 2
0010011100010000
0111010100110000
---------------------------------------
1001110001000000
Nel caso SHORT INT I numeri negativi sono rappresentati in complemento a 2
1001110001000000
0110001110111111
0110001111000000
25536
RISULTATO
COMPLEMENTO A 1
COMPLEMENTO A 2
VALORE DECIMALE
Lab02 11
E’ sempre possibile rappresentare un
qualunque numero reale?
Anche la rappresentazione dei numeri reali soffre di alcuni
limiti:
1. Indipendentemente da quanti bit uso per rappresentare un numero reale, tali bit devono essere sempre in numero finito…… se il numero di bit è finito, da qualche parte dovrò approssimare
qualcosina…
2. La trasformazione della rappresentazione di un numero reale da una base ad un’altra non è sempre indolore……può succedere che, dato un numero reale con un numero di cifre decimali
finito in base 10…
… durante la trasformazione di base possa diventare un numero con con la
parte dopo la virgola addirittura PERIODICA! Quindi, ulteriore
approssimazione…
Lab02 12
Esercizio 3
#include <stdio.h>
int main(void)
{
float k;
k = 5.6F;
k = k - 5.59F;
return (0);
}
1. Copiare, compilare ed eseguire il seguente
programma
2. Utilizzando il debugger e la finestra di
“watch”, rispondere alle seguenti domande:
a) Quanto vale k prima del primo
assegnamento?
b) Quanto vale k dopo il primo assegnamento?
Quant’e’ l’errore di approssimazione?
c) Quanto dovrebbe valere, e quanto vale
effettivamente k dopo il secondo
assegnamento? Perchè?
3. Modificate il programma, specificando k
come variabile double… cosa cambia?
Quanto vale l’errore di approssimazione?
Lab02 13
Esercizio 3
Se definiamo k come float
- Dopo il primo assegnamento
k=5.5999999
- Dopo il secondo assegnamento
k=0.00999975204
Se definiamo k come double
- Dopo il primo assegnamento
k=5.5999999046325684
- Dopo il secondo assegnamento
k=0.0099997520446777344
Lab02 14
Espressioni eterogenee
Cosa succede se in una espressione uso tipi diversi?
… laddove possibile, una espressione eterogenea viene
risolta applicando la promotion dei tipi, e considerando
l’overloading degli operatori…
Cosa succede se assegno ad un tipo inferiore un valore
rappresentato tramite un tipo superiore?
Come si effettua la conversione esplicita da un tipo ad un
altro?
Lab02 15
Esercizio 4
#include <stdio.h>
int main(void)
{
int i, k;
float j;
i = 20;
k = i % 3;
i = i / 3;
k = i / 4.0F;
j = i / 4.0F;
return (0);
}
1. Copiare, compilare ed eseguire il seguente
programma…
2. Utilizzando il debugger e la finestra di “watch”,
rispondere alle seguenti domande:
a) Quanto valgono i e k dopo il primo blocco di
assegnamenti?
b) Quanto valgono k e j dopo il secondo blocco di
assegnamenti?
c) Se k e j al termine del programma hanno valori
diversi, perchè?
3. In fase di compilazione il programma potrebbe aver
generato dei warnings…
a) Leggete i warning e spiegate il loro significato
b) Correggete il codice al fine di far scomparire i
warning (compilate sempre con “rebuild all”)
Lab02 16
Esercizio 4
#include <stdio.h>
int main(void)
{
int i, k;
float j;
i = 20;
k = i % 3;
i = i / 3;
k = i / 4.0F;
j = i / 4.0F;
return (0);
}
← i = 2147311616, k = 88, j = 8.92413003e-039
← i = 20, k = 88, j = 8.92413003e-039
← i = 20, k = 2, j = 8.92413003e-039
← i = 6, k = 2, j = 8.92413003e-039
← i = 6, k = 1, j = 8.92413003e-039
← i = 6, k = 1, j = 1.5
Lab02 17
Priorità Operatore Simbolo Associatività
1 (max) chiamate a funzione selezioni
()
[] -> . da sinistra a destra
2 operatori unari: op. negazione op. aritmetici unari op. incr. / decr. op. indir. e deref. op. sizeof
! ~
+ -
++ --
& *
sizeof
da destra a sinistra
3 op. moltiplicativi * / % da sinistra a destra
4 op. additivi + - da sinistra a destra
Operatori: priorità ed associatività
Lab02 18
Priorità Operatore Simbolo Associatività
5 op. di shift >> << da sinistra a destra 6 op. relazionali < <= > >= da sinistra a destra 7 op. uguaglianza == != da sinistra a destra 8 op. di AND bit a bit & da sinistra a destra 9 op. di XOR bit a bit ^ da sinistra a destra
10 op. di OR bit a bit | da sinistra a destra 11 op. di AND logico && da sinistra a destra 12 op. di OR logico || da sinistra a destra 13 op. condizionale ?...: da destra a sinistra 14 op. assegnamento
e sue varianti
=
+= -= *= /=
%= &= ^= |= <<= >>=
da destra a sinistra
15 (min) op. concatenazione , da sinistra a destra
Operatori: priorità ed associatività
Lab02 19
Esercizio 5 – Scova l’errore
Aldo, Giovanni e Giacomo hanno comprato in
pasticceria una torta già tagliata in 12 fette, e poi
si sono incontrati per mangiarla assieme.
E’ andata più o meno così:
• Aldo ha mangiato 2 fette.
• Giovanni ne ha prese 5 nel piatto, ma poi si è
ricordato di essere a dieta e quindi ne ha
restituite 3.
• Giacomo ne ha prese 6, ma poi dopo averne
mangiate 2 ha restituito le altre… salvo che di
nascosto ne ha mangiato un’ulteriore fetta…
Lab02 20
Esercizio 5 – Scova l’errore
Fette di torta iniziali = 12
Aldo ne mangia 2 fette → restano 10 fette
Giovanni ne ha prese 5 ma ne ha restituite 3
Quindi ne ha prese 2 → restano 8 fette
Giacomo ne ha prese 6, mangiate 2 e restituite le altre. In seguito
ha mangiato un’altra fetta.
Quindi ne ha prese 3 → restano 5 fette
Hanno scritto quindi un programma che calcola il numero di fette
rimaste nel piatto… al numero iniziale di fette hanno sottratto le
fette mangiate da ogni membro della famiglia…
Lab02 21
Esercizio 5 – Scova l’errore
#include <stdio.h>
int main(void)
{
int torta_i = 12;
int torta_f;
torta_f = torta_i – 2 – 5-3 – 6-4-1;
return (0);
}
Il programma è sbagliato… perchè?
1. Correggete l’espressione inserendo le parentesi nei punti giusti, e senza sostituire all’operatore ‘-’ l’operatore ‘+’…
2. Verificate tramite il debugger che il numero di fette finale calcolato siaeffetivamente quello giusto…
Aldo…
Giovanni…
Giacomo…
Lab02 22
Esercizio 5 – Scova l’errore
#include <stdio.h>
int main(void)
{
int torta_i = 12;
int torta_f;
torta_f = torta_i – 2 – (5-3) – (6-4)-1;
return (0);
}
Aldo…
Giovanni…
Giacomo…
Lab02 23
Esercizio 6
#include <stdio.h>
int main(void)
{
double d = 15 / 6;
printf( "15 / 6 is %lf", d );
return 0;
}
Cosa Stampa?
Lab02 24
Esercizio 7
#include <stdio.h>
int main(void)
{
double d = 15.0 / 6;
printf( "15 / 6 is %lf", d );
return 0;
}
Cosa Stampa?
Lab02 25
Sol. Esercizio 6/7
“15 / 6” è una divisione tra interi, il cui risultato è 2.
Nel calcolare “15.0 / 6”, l’intero “6” viene promosso a double. Il risultato della divisione è quindi 2.5.
Lab02 26
Esercizio 8
#include <stdio.h>
int main(void)
{
int a = 4;
float b = 3.14159;
float fresult;
fresult = a * b;
printf( "a * b = %f", fresult );
return 0;
}
Cosa Stampa?
Lab02 27
Esercizio 9
#include <stdio.h>
int main(void)
{
int a = 4;
float b = 3.14159;
int iresult;
iresult = a * b;
printf( "a * b = %d", iresult );
return 0;
}
Cosa Stampa?
Lab02 28
Sol. Esercizio 8/9
int iresult;
iresult = a * b;
Poiché la variabile “iresult” è un intero, ilrisultato dell’espressione “a*b” vienetroncato.
Lab02 29
Esercizio 10
#include <stdio.h>
int main(void)
{
char x = 'd’;
int y = 100;
printf("%c %d : %c %d", x,x,y,y);
return 0;
}
Cosa Stampa?
Lab02 30
Sol. Esercizio 10
char x = 'd’;
int y = 100;
printf("%c %d : %c %d", x,x,y,y);
Stampa: d 100 : d 100
Perché il codice ASCII per “d” è 100!
Lab02 31
Esercizio 11
#include <stdio.h>
int main(void)
{
char x = 'd';
int y = 100;
double d = 5.1;
float f = 3.9;
int a = 4;
printf("%d\n", x*y);
return 0;
}
Lab02 32
Esercizio 11b
Provare ad inserire nel programma dell’esercizio 11
le seguenti istruzioni. Prima di eseguirle provare
a dire cosa stampano.
printf("%d\n", a + y * x );
printf("%d\n", (a + y) * x );
printf("%d\n", ( a + y ) * y);
printf("%d\n", a + ( y * y ) );
printf("%d\n", ( a + y ) * ( y * ( a + y ) ) );
printf("%d\n", ( a + y ) * x + ( ( y / a ) - ( a / y ) ) );
Lab02 33
Esercizio 11c
printf("%lf\n", ((a+y)*d)/f);
printf("%d\n", (int)(((a+y)*d)/f));
printf("%.2lf\n", ((a+y)*d)/f);
printf("%.2lf\n", ((a+d)*x)/f);
printf("%lf\n", ((a/f)*d)/f);
printf("%lf\n", (int)f/d);
printf("%d\n", (int)f/(int)d);
Lab02 34
Casting
int main(void)
{
int i, k;
float j = 10.3F;
double g = 12.5;
i = 19;
k = i % 3;
i = (int) j / 3;
k = (int) j / 4.0F;
j = (float) g / 4;
g = (double) i / 4;
return (0);
}
1. Copiare, compilare ed eseguire il
seguente programma…
2. Utilizzando il debugger e la finestra di
“watch”, rispondere alle seguenti
domande:
a) Quanto valgono I, k dopo il primo
blocco di assegnamenti?
b) Quanto valgono k, j e g dopo il secondo
blocco di assegnamenti?
3. In fase di compilazione il programma
potrebbe aver generato dei warnings…
a) Leggete i warning e spiegate il loro
significato
b) Correggete il codice al fine di far
scomparire i warning (compilate
sempre con “rebuild all”)
Lab02 35
Casting
int main(void)
{
int i, k;
float j = 10.3F;
double g = 12.5;
i = 19;
k = i % 3;
i = (int) j / 3;
k = (int) j / 4.0F;
j = (float) g / 4;
g = (double) i / 4;
return (0);
}
← i = 4200682, k = 2293544, j = 10.3000002, g = 12.5
← i = 19, k = 2293544, j = 10.3000002, g = 12.5
← i = 19, k = 1, j = 10.3000002, g = 12.5
← i = 3, k = 1, j = 10.3000002, g = 12.5
← i = 3, k = 2, j = 10.3000002, g = 12.5
← i = 3, k = 2, j = 3.125, g = 12.5
← i = 3, k = 2, j = 3.125, g = 0.75
Lab02 36
Casting
int main(void)
{
int i, k;
float j = 10.3F;
double g = 12.5;
i = 19;
k = i % 3;
i = (int) j / 3.0F;
k = (int) j / 4;
j = (double) g / 4;
g = (double)(i / 4);
return (0);
}
Modificate ora il
programma nel
seguente modo.
Come cambiano
i risultati ?
Lab02 37
Casting
← i = 4200682, k = 2293544, j = 10.3000002, g = 12.5
← i = 19, k = 2293544, j = 10.3000002, g = 12.5
← i = 19, k = 1, j = 10.3000002, g = 12.5
← i = 3, k = 1, j = 10.3000002, g = 12.5
← i = 3, k = 2, j = 10.3000002, g = 12.5
← i = 3, k = 2, j = 3.125, g = 12.5
← i = 3, k = 2, j = 3.125, g = 0
int main(void)
{
int i, k;
float j = 10.3F;
double g = 12.5;
i = 19;
k = i % 3;
i = (int) j / 3.0F;
k = (int) j / 4;
j = (double) g / 4;
g = (double)(i / 4);
return (0);
}
Lab02 38
Esercizio 12a
#include <stdio.h>
int main(void)
{
int a = -10;
unsigned short b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
Cosa Stampa?
Lab02 39
Esercizio 12a
#include <stdio.h>
int main(void)
{
int a = -10;
unsigned short b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
-5 4
perchè promuove b ad int
Lab02 40
Esercizio 12b
#include <stdio.h>
int main(void)
{
short a = -10;
unsigned int b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
Cosa Stampa?
Lab02 41
Esercizio 12b
#include <stdio.h>
int main(void)
{
short a = -10;
unsigned int b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
4294967291 4
promuove a ad unsigned int
Lab02 42
Esercizio 12c
#include <stdio.h>
int main(void)
{
int a = -10;
unsigned int b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
Cosa Stampa?
Lab02 43
Esercizio 12c
#include <stdio.h>
int main(void)
{
int a = -10;
unsigned int b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
4294967291 4
promuove a ad unsigned int
Lab02 44
Esercizio 12d
#include <stdio.h>
int main(void)
{
short a = -10;
unsigned short b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
Cosa Stampa?
Lab02 45
Esercizio 12d
#include <stdio.h>
int main(void)
{
short a = -10;
unsigned short b = 5;
long long c = b+a;
printf("%lld %lu\n",c,sizeof(b+a));
return 0;
}
-5 4
promuove entrambi ad int