Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoFaustino Valeri Modificato 9 anni fa
1
Parte 3 Lo stato: variabili, espressioni ed assegnazioni
Informatica A.A. 2009/2010 Parte 3 Lo stato: variabili, espressioni ed assegnazioni Corso A: Prof. Stefano Berardi Corso B: Prof. Ugo de’ Liguoro
2
“ASCII Art” |\=/|.-"""-. |\=/| /6 6\ \ /6 6\ =\_Y_/= (_ ;\ )) =\_Y_/=
|\=/|.-""" |\=/| /6 6\ \ /6 6\ =\_Y_/= (_ ;\ )) =\_Y_/= ^//_/-/__/// (( / ^ \ (( \\ /| | |\ \( | | | ) '"" ""‘ |\ _,,,--,,_ /,`.-'`' ._ \-;;,_ |,4- ) )_ .;.( `'-' '---''(_/._)-'(_\_) | o | | o ///// /= | | O """"""^:. /= | | / O )) "= | | o )____,,,,----\= | | """ \= | | \= |
3
Indice Parte 3: Lo stato e le variabili
La nozione di stato. Variabili: dichiarazione, assegnazione e tipi in C++. Operatori aritmetici e espressioni. Numeri in virgola mobile e conversioni di tipo. Operazioni su booleani (valori di verita’). In questa sezione vedremo come una variabile in C++ sia essenzialmente il contenuto di un indirizzo di memoria di una macchina di von Neumann.
4
1. Lo stato di un programma
I programmi detti “imperativi” consistono in una sequenza di comandi, che trasformano progressivamente i dati presenti in memoria. L’insieme dei valori memorizzati in un dato momento, in attesa della prossima istruzione da eseguire (compreso il contatore di programma che decide la prossima istruzione) costituiscono lo stato. 3-Elaboratore
5
La nozione matematica di stato
La memoria in un dato stato si può rappresentare con una funzione che ad ogni indirizzo di memoria associa il suo contenuto: 3,1416 “ciao” -1256 true i1 i2 i3 i4 i5 3-Elaboratore
6
Indirizzo (binario o esadecimale)
2. Variabili in C++ Una variabile in C++ è una locazione di memoria, dunque un numero scritto in binario: nome Indirizzo (binario o esadecimale) tipo il nome x viene detto “identificatore” l’indirizzo di memoria si riferisce alla cella di memoria con i valori della variabile. il tipo determina la dimensione (il numero di bytes) occupati dalla variabile, e il modo in cui se ne interpreta il contenuto
7
Variabili e valori Attenzione! una cella di memoria di una macchina di von Neumann contiene sempre un valore, dunque una variabile C++ ha sempre un valore, anche se noi non ne abbiamo scelto nessuno. Una variabile è una parte dello stato. Il valore di una variabile può essere modificato da un comando di assegnazione: Indirizzo: 0x0064fddc x x 1024 Tipo: int Valore: Per ottenere che x valga –1024 occorre eseguire la seguente istruzione detta assegnazione: x = -1024; Assegnazioni, e tutte le altre istruzioni che vedremo, terminano con un punto e virgola. 3-Elaboratore
8
Variabili: dichiarazione e definizione
Per ogni variabile dobbiamo dichiarare un tipo: int x; /* dichiarazione della var. x di tipo intero */ Nella dichiarazione si deve assegnare un tipo (dunque un numero di bytes di memoria), e si può assegnare alla variabile un valore iniziale (una definizione): int x = 0; /* definizione della variabile x di tipo intero e valore iniziale 0 */ Dobbiamo fare attenzione a definire o assegnare sempre ogni variabile. Una variabile ha un valore solo per il fatto di essere stata dichiarata e quindi associata a un indirizzo di memoria di una macchina di von Neumman. Questo valore esiste ma è “casuale”, e noi possiamo usarlo senza rendercene conto, provocando errori difficili da scoprire.
9
Quando dobbiamo usare le variabili?
Il più possibile! Ogni parametro del programma deve essere indicato da una variabile e non da un numero. Se dobbiamo calcolare l’area totale di 100 rettangoli di base 20 e altezza 10, anziché scrivere int AreaTot = 100*20*10; dobbiamo invece scrivere, per leggibilità: int Nrett=100, base=20, altezza=10; int AreaTot = Nrett*base*altezza; Anche le dichiarazioni sono istruzioni e quindi terminano con un punto e virgola. 3-Elaboratore
10
Perché dobbiamo usare le variabili il più possibile?
Ci sono più vantaggi. Usando il più possibile le variabili, il programma diventa più leggibile: ogni quantità, per esempio Nrett (“numero rettangoli”), compare con un nome che ne spiega in parte l’uso. In un programma più leggibile è più facile trovare gli errori. Trovare gli errori, di solito, è la maggior parte del lavoro. Usando il più possibile le variabili, il programma diventa più flessibile. Per cambiare il valore di un parametro dobbiamo solo cambiarlo una volta, dove viene definito, anziché dover esaminare tutti i numeri che compaiono in tutte le formule, un compito faticoso e che produce errori. 3-Elaboratore
11
I tipi di base delle variabili C++
I tipi rappresentano l’insiemi dei possibili valori di una variabile: bool: valori di verità {true, false} int: un intervallo degli interi (con segno) char: 256 caratteri a, …, z, A, …, Z (maiuscole e minuscole sono caratteri diversi), interpunzione, spazio, a capo, caratteri speciali, …, tutti rappresentati da un intero tra 0 e 255. float, double: numeri con la virgola e con segno, rappresentati in virgola mobile, in precisione semplice e doppia rispettivamente (float è poco preciso e non è quasi piu’ usato). 3-Elaboratore
12
Altri tipi per le variabili del C++
short: interi brevi con segno (numero bytes dimezzata rispetto a int) long: interi lunghi con segno (numero bytes raddoppiata rispetto a int) Vi sono poi tipi ottenuti modificando altri tipi: unsigned int: interi senza segno long int: come long long long: interi con numero bytes il quadruplo di int Il numero di bytes usato da ogni tipo cambia da un compilatore all’altro: per conoscerlo c’è l’operazione sizeof(short), sizeof(long), … 3-Elaboratore
13
Il tipo void del C++ Tra i tipi di base del C++ c’è un tipo curioso, void, che rappresenta l’insieme vuoto. Per definizione, non esistono valori di tipo void, e non si possono dichiarare variabili di tipo void, e il tipo void non occupa spazio di memoria. Il tipo void ci appare inutile, ma viene invece utilizzato per descrivere sottoprogrammi di tipo particolare. Vedremo come nella sezione delle dispense dedicata alle funzioni. 3-Elaboratore
14
Dimensioni e valori interi in DevC++
L’intervallo e il numero dei valori rappresentati da una variabile dipende da quanti bytes sono usati per rappresentare un oggetto di quel tipo. Qualche esempio (come abbiamo detto, il numero di bytes di un tipo varia da un compilatore all’altro) short da –32768 a int da – a long da – a unsigned short da 0 a unsigned int da 0 a unsigned long da 0 a 3-Elaboratore
15
3. Operatori aritmetici in C++
Gli operatori aritmetici predefiniti in C++ sono 5: m + n // addizione m – n // differenza m * n // moltiplicazione m / n // parte intera di m:n m % n // resto di m:n (m mod n) Per esempio 20 % 6 = 2 perche’ il resto di 20:6 vale 2 (20=6x3+2). Attenzione, il % non è il modulo per valori negativi: (-7)%6 vale -1, mentre (-7 mod 6) vale 5. Quando a può essere negativo, (a mod b) si calcola per es. come (b+a%b)%b.
16
Espressioni aritmetiche
In C++ possiamo scrivere delle espressioni aritmetiche composte, come: Se x ed y sono variabili intere, allora l’espressione ha tipo intero, e se ad esempio x = 2 ed y = -3 allora il valore dell’espressione è –2. In un’espressione come 7+(4x-5)*y le variabili sono usate in lettura: il computer, quando calcola l’espressione, copia il valore di x, y nei registri della ALU, nella CPU, ma non le modifica 3-Elaboratore
17
Stampa di Espressioni aritmetiche
La stampa di una espressione aritmetica si ottiene in C++ con l’istruzione cout (anch’essa terminata da un ;) cout << espressione1 << … << espressionek; int x = 2, y = -3; cout << 7 + (4*x – 5)*y; // produce la stampa a video // del valore dell’espressione, in questo caso -2 cout << x << y << 7 + (4*x – 5)*y << endl; // possiamo stampare quante espressioni vogliamo // il comando endl posto alla fine di un cout va a capo Una espressione è una combinazione di costanti, variabili, operatori 3-Elaboratore
18
Assegnazione e lettura di variabili
Per assegnare o inserire da tastiera un valore in una variabile si fa come segue: int x = 2, y = -3; int n; int z = 7 + (4*x – 5)*y; // assegna a z il valore dell’espressione cin >> x; /* ferma l’esecuzione, legge un intero da tastiera e lo inserisce in x. Usate il cin con una sola variabile per volta: non scrivete cin >> x >> y;*/ cout << z; // produce la stampa a video del valore corrente di z cout << n; // stampa del valore di n, non assegnato // e quindi “casuale” (nel senso di non scelto da noi) 3-Elaboratore
19
<variabile> = <espressione>;
L’assegnazione in C++ L’assegnazione ha la forma: <variabile> = <espressione>; richiede un ; alla fine, e funziona come segue Prima si valuta l’espressione nella ALU, inserendo i valori intermedi nei registri della CPU. Poi il valore dell’ultimo registro usato viene salvato nell’indirizzo della memoria RAM associato alla variabile. I valori intermedi del calcolo vanno persi. m = 7 + 5*p; // dobbiamo aver prima assegnato un valore a p // altrimenti assegnamo a m un valore “casuale”
20
Un programma C++ nella sua forma più semplice
Un programma C++, nella sua forma più semplice, consiste in una lista di istruzioni {istr1; …, istrk;} detta blocco, avvolta tra parentesi graffe e preceduta dalla scritta int main(). Il comando cout non fa parte del C++ di base. Per usarlo è necessario includere la libreria di comandi “iostream”, con il comando #include <iostream>. Una libreria ci consente di estendere il C++ con nuovi comandi. Una libreria che usiamo spesso è cmath, per includere nel C++ le funzioni matematiche (radice, seno, logaritmo eccetera).
21
Altre avvertenze Il compilatore Dev-C++ richiede anche un comando system("pause"); alla fine del main per vedere il risultato. “system” fa parte della libreria stdlib.h, che è necessario includere. Se il vostro sistema operativo non è Windows, al posto di system(“pause”) usate getch(); Per usare il cout, è necessario inserire il comando “using namespace std” prima del main. Per indicare ab non scrivete a^b ma pow(a,b): a^b indica il “Bitwise Xor”, un’operazione completamente diversa. “pow” fa parte della libreria cmath. Vedremo ulteriori dettagli in laboratorio. Ora siamo pronti a scrivere un primo esempio di programma C++. 3-Elaboratore
22
Un primo esempio di programma C++
#include <iostream> /* per il cout */ #include <stdlib.h> /* per il system(“pause”) */ #include <cmath> /* per pow(a,b) */ using namespace std; /* per il cout */ int main() {double n = 2.0, s = 7.0; double media; media = s/n; cout << media << endl; /* stampa 7.0/2.0, dunque 3.5 */ cout << pow(10.0,3) << endl; /* stampa 103 = 1000 */ system("pause"); /* arresta l’esecuzione e consente di vedere il risultato*/ } 3-Elaboratore
23
Incrementi e decrementi di variabili
Il simbolo “x=” non si legge: “x uguale a …”, ma “x assegnata a …” La valutazione dell’espressione a destra di “=” precede l’assegnazione. Dunque la stessa variabile può comparire sia a sinistra che a destra dell’assegnazione senza che ci siano contraddizioni. Per esempio possiamo avere: n = n + 1; /* incrementa n di 1, non significa ”n uguale a n+1” */ 3-Elaboratore
24
Abbreviazioni per incrementi, decrementi
Il C/C++ usa una forma abbreviata per l’incremento (decremento) di una variabile i: ++i; (--i;) // pre-incremento (decr.) i++; (i--;) // post-incremento (decr.) Se usati da soli, pre e post incremento si equivalgono: ++i; equivale a i++; equivale a i = i+1; 3-Elaboratore
25
Esempi di abbreviazioni (sconsigliate)
Accenniamo ora a delle abbreviazioni, di cui tuttavia sconsigliamo l’uso, perché rendono difficoltosa la lettura di un programma. Pre incremento ++i e post incremento i++, se usati entro un’espressione, hanno significato diverso. In un caso prima si incrementa i e poi si prosegue il calcolo, nell’altro caso si fa il contrario. n=++i * 7; equivale a i=i+1; n=i*7; n=i++ * 7; equivale a n=i*7; i=i+1; 3-Elaboratore
26
Ancora abbreviazioni (sempre sconsigliate)
n += 7 + m; abbrevia n = n m; n -= 7 + m; abbrevia n = n – (7 + m); n *= 7 + m; abbrevia n = n * (7 + m); n /= 7 + m; abbrevia n = n/(7 + m); Accenniamo a queste abbreviazioni solo perché lo studente può trovarle in programmi scritti da altri. Per scrivere un programma, invece, raccomandiamo di usare la massima semplicità di notazione. 3-Elaboratore
27
4. Aritmetica in virgola mobile
Ogni calcolo in C++ si svolge con un numero fisso di cifre binarie, e dunque con una massima precisione ottenibile, e un valore massimo rappresentabile. Quando questo valore massimo viene superato, il risultato diventa completamente insensato. Per esempio, il tipo float in Dev-C++ occupa 4 bytes = 32 bits, di cui 23 per le cifre significative e 8 per l’esponente del numero. le cifre decimali significative (affidabili) sono 6 il valore minimo pos. è il valore massimo pos. è 3-Elaboratore
28
Altri tipi per i numeri in virgola mobile
sizeof(float) = 4 bytes (32 bits) sizeof(double) = 8 bytes (64 bits) sizeof(long double) = 12 bytes (96 bits) Il tipo double ha dimensione 100% in piu’ del tipo float, il tipo long double dimensione 50% in piu’ di double: 100% in piu’ significa il doppio di cifre affidabili. L’intervallo dei valori rappresentati cresce esponenzialmente. 3-Elaboratore
29
Conversione automatica da un tipo a uno “maggiore”
Quando espressioni di tipo diverso occorrono nella stessa espressione avviene una conversione al tipo “maggiore”. Per esempio un intero 3 diventa il numero reale 3.0, una buona idea. Però la cifra ‘3’ dell’alfabeto ASCII diventa l’intero 51 (perché ‘3’ è il carattere 51 dell’alfabeto ASCII), una scelta piuttosto discutibile. Qui sotto una lista di tipi convertibili, ciascuno al tipo successivo: bool < char < short < int < long < float < double bool contiene false = 0, true = 1 char = tipo dei caratteri nell’alfabeto ASCII, rappresentati da interi tra 0 e 255 3-Elaboratore
30
Conversione automatica da un tipo a uno “minore”
Viceversa, se una variabile x di tipo “minore” si trova a sinistra di “=” avverrà una coercizione, una sorta di approssimazione del valore di x nel tipo “minore”. Questo spesso è causa di guai … Per esempio, se x ha tipo int e scrivo x = ; allora il numero con la virgola viene arrotondato all’intero 3 (senza virgola) prima di essere assegnato a x. Allo stesso modo se scrivo int x=1/10; in realtà, a causa dell’arrotondamento, sto scrivendo int x=0; Per forzare un tipo, per esempio il tipo double, dobbiamo scrivere ((double) 3) oppure 3.0.
31
Esempi di arrotondamenti non voluti
Vediamo alcuni modi di scrivere la divisione tra due numeri reali. Se ci dimentichiamo di precisare che di reali si tratta arrotondiamo il risultato. int main() {int n = 2, s = 7; double media; media = s/n; cout << media; // arrotondam.: 3 media = ((double) s)/n; cout << media; // ok: 3.5 media = (double)(s/n); cout << media; // arr.: 3 media = 7.0/2.0; // ok: 3.5 cout << media; /* vale 3.5 */ } L’operazione ((tipo) espr.) forza una espressione ad avere un tipo e viene detta casting.
32
Un esempio di conversione automatica
char ch; int i; float f; double d; float result; result = ( ch / i ) ( f * d ) (f + i); float int double float double int double double double double Arrotondamento: float ha meno cifre significative di double
33
!(x <= y) && (z != 0 || x%y == 0)
5. Espressioni booleane Sono quelle il cui valore appartiene all’insieme {true, false}. Hanno tipo bool. && rappresenta l’operazione di congiunzione di due valori di verita’, || quella disgiunzione, ! rappresenta la negazione di un valore di verita’, “a==b” il valore di verita’ dell’affermazione “a, b sono uguali”, “a != b il valore di verita’ dell’affermazione “a, b sono diversi”, e cosi’ per a<b, a<=b, a>b, a>=b. !(x <= y) && (z != 0 || x%y == 0) and not or uguale minore o uguale diverso 3-Elaboratore
34
Test di uguaglianza == e assegnazione =
Nel linguaggio C++ l’espressione booleana a==b indica il valore di verità dell’affermazione “a, b sono uguali”. a==b vale true se le due espressioni a, b hanno lo stesso valore e false se hanno valori diversi. 2+2==4 vale true mentre 2+2==5 vale false. a=b invece indica il comando “calcola il valore di b e assegnalo alla variabile a”. Un errore molto comune è confondere (a==b) con (a=b). 3-Elaboratore
35
Cosa succede se confondo == con =
Un errore molto comune è confondere (a==b) con (a=b). Se scrivo (x=3) al posto di (x==3) non ottengo il valore di verità true o false dell’affermazione “x, 3 sono uguali” ma rendo x uguale a 3, qualunque fosse il valore originario di x, e ottengo come risultato il valore 3. Se uno dei vostri primi programmi non funziona, controllate dentro gli if se non avete scritto (x=3) al posto di (x==3) . 3-Elaboratore
36
Algebra di Boole e Leggi di de’ Morgan
L’insieme Bool = {true, false} con le operazioni di negazione , congiunzione e disgiunzione è un’Algebra di Boole. Nel prossimo lucido includiamo una lista delle principali leggi logiche valide per , , . Queste leggi sono valide in C++ finché le espressioni che calcoliamo sono definite. Vedremo dopo perchè una espressione può essere indefinita e cosa succede quando compaiono espressioni indefinite. 3-Elaboratore
37
Algebra di Boole e Leggi di de’ Morgan
e sono associative, commutative, hanno elemento neutro (true per e false per ) e sono idempotenti: xx = x = xx per ogni xBool e sono distributive ciascuna rispetto all’altra: x(yz) = (xy)(xz) e x(yz) = (xy)(xz) per ogni x,y,zBool.. La negazione soddisfa la Legge di Doppia Negazione: x = x per ogni xBool. Vale la Legge di de’ Morgan: (x y) = x y e (x y) = x y per ogni x,yBool. 3-Elaboratore
38
Le versioni “lazy” di And, Or
In C++ valutiamo le espressioni booleane da sinistra a destra e in un modo detto lazy, fermandoci cioè non appena conosciamo il risultato. Come conseguenza, se compaiono espressioni indefinite non vale più, in C++, la commutativita’ dell’OR. Un esempio: (n == 0) || (34/n > 7) è sempre definita. Infatti se n è 0 vale True, perche’ terminiamo subito il calcolo e non eseguiamo 34/n. Se n non è 0 vale il valore di (34/n > 7), che in questo caso è definito. L’espressione ottenuta scambiando l’ordine di || invece non è definita se n è 0, dato che richiede il calcolo di 34/0: (34/n > 7) || (n == 0) . Per evitare questi problemi, vi consigliamo di evitare il più possibile le espressioni indefinite.
39
Una tabella per il calcolo “lazy” e da sinistra a destra di And, Or
Indichiamo “indefinito” con a b a && b a || b true false Un esempio: (true || ) vale true, mentre ( || true) vale : dunque il || non è commutativo
40
Riepilogo Il contenuto della parte della memoria RAM usata dal programma (incluso il contatore di programma) costituisce lo stato; i valori in memoria sono letti e modificati attraverso l’uso di variabili; il valore di una variabile x viene: letto quando si valuta un’espressione contenente x scritto quando eseguiamo x = espressione. Dobbiamo fare attenzione a non superare il valore massimo di un tipo, a non confondere interi e reali, == con =. Per il tipo bool valgono le leggi logiche
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.