Sei sulla pagina 1di 10

2

L’indentazione del codice


 L’indentazione consiste nel precedere le righe
di codice con un certo numero di spazi
Complementi - 1  Ha lo scopo di evidenziare i blocchi di codice
 Ignorata dal compilatore, serve al
programmatore per cogliere visivamente la
struttura del programma
Ver 2.4
 Si indenti il codice mentre lo si sviluppa, non
successivamente per renderlo “bello”
 Il numero di spazi è sempre multiplo di un
certo valore scelto come base (in genere 3 o 4)
 Normalmente si può definire il tasto Tab in
© 2010 - Claudio Fornaro - Corso di programmazione in C modo che introduca quel numero di spazi

3 4

L’indentazione del codice L’indentazione del codice


 L’indentazione esprime “dipendenza”,  Esempio:
“controllo”: l’istruzione non indentata che for (i=1; i<100; i++)
precede il blocco controlla il blocco indentato {
 Esempio: Istruzione non printf("%d", i);
for (i=0; i<10; i++) indentata if (i % 7 == 0)
{
{ printf(" divisibile per 7");
scanf("%d", &a); Blocco cont++;
printf("%d\n", a*2); indentato }
} printf("\n");
Le due istruzioni scanf e printf sono }
controllate dall’istruzione for precedente, la Le istruzioni printf , if e printf del
printf non è controllata dalla scanf e per blocco del for sono allo stesso livello, il
questo è allo stesso livello (non è indentata) blocco dell’if è ulteriormente indentato
5 6

L’indentazione del codice L’indentazione del codice


 L’indentazione è necessaria anche in assenza  Per il posizionamento delle parentesi graffe
delle parentesi graffe (quando sono opzionali) che racchiudono il blocco si suggerisce di
 Esempio: utilizzare la modalità Kernighan-Ritchie 2a ed.:
for (i=0; i<10; i++)  la graffa di inizio blocco è collocata sotto il primo
carattere della parola chiave che controlla il blocco,
for (j=0; j<20; j++) in una riga a sé stante
printf("%d,%d", i, j);
 tutte le istruzioni del blocco sono indentate (es. 4
spazi)
L’istruzione printf è controllata  la graffa di fine blocco è allineata sotto quella di
dall’istruzione for precedente che a sua volta inizio blocco, in una riga a sé
è controllata dall’istruzione for più esterna  Ulteriori esempi di indentazione K&R2 corretta
e coerente possono essere trovati in tutte le
le soluzioni degli esercizi

7 8

Magic numbers Magic numbers


 Per chiarezza, si cerca di evitare/limitare la  Esempio errato (Che rappresenta quell’ “80” ?):
presenza di valori numerici nei programmi int v[80];
for (i=0; i<80; i++)
 Si preferisce definire delle costanti scanf("%d", &v[i]);
 Esempio errato (Che rappresenta quel “26”? ):  Esempio corretto:
for (i=0; i<26; i++) define MAXVETT 80
...
printf("%c", 'A'+i);
int v[MAXVETT];
 Esempio corretto: for (i=0; i<MAXVETT; i++)
#define LETTERE_ALFAB 26 scanf("%d", &v[i]);
... MAXVETT è “auto-esplicativo”, inoltre si ha un
for (i=0; i<LETTERE_ALFAB; i++) ulteriore vantaggio: se si vuole cambiare la
printf("%c", 'A'+i); dimensione del vettore nel programma è
sufficiente cambiare questa sola define
9 10

Uscita dal programma Effetti collaterali


 Il programma termina quando viene eseguita  Un’espressione può produrre un risultato e/o
un’istruzione return: dare effetti collaterali (side-effect )
return status;  Esempio
 Possono esserci più istruzioni return x = 3 * i++;
 Nel main la return termina il programma e 3*i è un calcolo che produce un valore,
passa il valore status al S.O. per informarlo mentre i++ ha l’effetto collaterale di
sull’esito dell’esecuzione: incrementare i di 1
 il valore 0 indica che il programma ha eseguito
quanto doveva: terminazione con successo  Quando tutti i side-effect di un’espressione
 valori diversi da 0 indicano che il programma ha sono stati effettuati, si dice che si è raggiunto
avuto problemi (es. non ha trovato un file): un sequence point
terminazione con malfunzionamento
 Includendo <stdlib.h>, per status si  Prima del raggiungimento del sequence point,
possono usare le costanti EXIT_SUCCESS (al il valore delle variabili soggette ad side-effect
posto di 0) ed EXIT_FAILURE (generico ≠ 0) è indefinito e quindi non devono essere usate

11 12

Effetti collaterali Effetti collaterali


 In una stessa espressione quindi NON può  Esempi di errori
comparire più di una volta una variabile  x = i++ * i++;
soggetta a side-effect l’incremento/decremento postfisso non è garantito
venga effettuato subito dopo la valutazione (uso)
 Il sequence point viene raggiunto solo prima della variabile: le due i potrebbero essere
di passare all’istruzione successiva, salvo: incrementate solo appena prima di passare
 dopo l’esecuzione della prima parte delle all’istruzione successiva (in questo caso x
espressioni contenenti gli operatori &&, ||, ?: e conterrebbe i elevato al quadrato)
l'operatore virgola ‘,’  x = ++a / --a;
 quando vengono valutate le espressioni di while, In questo caso ci sono problemi di ordine di
for, do, if, switch e return valutazione: non si sa a priori se l’incremento viene
 dopo che tutti gli argomenti di una funzione sono effettuato prima del decremento o viceversa, i
stati valutati, ossia subito prima della chiamata alla risultati possono dunque essere diversi su
funzione stessa compilatori diversi
 v[i] = i++;
13 14

Ordine di valutazione Ordine di valutazione


 Le regole di precedenza tra gli operatori e le  Altri esempi di errori:
parentesi impongono solo un parziale  printf("%d %f\n", ++n, tan(1./n));
ordinamento nella valutazione delle espressioni non si sa se viene prima valutata l’espressione ++n
 Ad esempio in un’espressione come e poi calcolata la funzione tan()o viceversa,
x = f() + g() * h(); quindi non si sa se il valore di n usato in tan() è
viene calcolata prima la moltiplicazione e poi la quello prima o dopo l’incremento.
somma, ma non è noto in quale ordine le La virgola che li separa non è un operatore, ma un
funzioni siano chiamate (e producano i valori) separatore e quindi non garantisce alcun ordine di
valutazione
 Per garantire un determinato ordine si usano
x = sin(1/++x) + cos(1/++x);
variabili per mantenere i risultati intermedi 
non è noto se viene calcolata prima sin o prima
 Si può talvolta utilizzare un costrutto che cos, per cui gli argomenti di sin e cos possono
inserisce un sequence point (&&, ‘,’, etc.) essere diversi utilizzando compilatori diversi

15 16

Ordine di valutazione Ordine di valutazione


 Altri esempi di errori:  Altri esempi di errori:
 x = sin(x++) + sin(x++); in questi casi non è noto se venga valutata prima la
non è noto quale delle funzioni sin venga parte a sinistra o quella a destra dell’uguale, inoltre
calcolata prima; essendo uguali non è importante, in una stessa espressione NON può comparire più
ma solo perché la chiamata a funzione inserisce un di una volta una variabile soggetta a side-effect
sequence point e quindi permette a x di essere  v[i] = ++i;
riutilizzata nella stessa espressione v[i] = i++;
 x = i++ * i++; non è noto quale valore di i venga usato in v[i]
qui invece, non essendoci funzioni, non viene  v[++i] = ++i;
richiesto alcun sequence point, quindi NON è non è noto quale valore di i venga incrementato
accettabile prima
 x = v[++i] - v[++i];
non si sa quali siano gli indici effettivi delle due
v[++i] in quanto non è noto quale dei due venga
valutato per primo prima di calcolare la sottrazione
17 18

Operatore virgola Operatore virgola


 Unisce due espressioni in un’unica espressione  In un contesto dove la virgola ha il significato
 Permette di inserire due espressioni dove di separatore, per inserire l’operatore virgola si
sintatticamente ne è prevista una sola: includono questo e suoi operandi tra parentesi:
for (i=0, j=10; i<j ; i++, j--) funz(a, (b=1,b+2), c);
 L’operatore virgola inserisce un sequence funz ha 3 parametri il secondo vale 3, b vale 1
point: l’espressione di destra viene valutata  Esempi
solo dopo che l’espressione di sinistra è stata x=2*4, 5*6; x=8, 30 scartato
valutata completamente (side-effect terminati) (la prima espressione è x=2*4, l’altra 5*6)
 Le due espr. possono essere di tipo diverso: x=(2*4, 5*6); x=30, 8 scartato
 il tipo e il valore dell’espressione composta sono x=2*4, y=5*6; x=8, y=30
quelli dell’espressione di destra x=(2*4, y=5*6); 8 scartato, y=30, x=30
 il tipo e il valore dell’espr. di sinistra sono scartati x=(y=2*4, 5*6); y vale 8, x = 30

19 20

Espressione condizionale Espressione condizionale


 E’ un’unica espressione che può assumere  Esempi
due valori in base ad una condizione  Il maggiore tra a e b:
 x = (condizione) ? espr1 : espr2; x = (a>b)?a:b;
equivale a:  Il valore assoluto di a:
x = (a>0)?a:-a;
if (condizione)
 Il plurale di una parola
x = espr1; printf("%d oggett%c\n",
else k, (k==1)?'o':'i');
x = espr2;
 condizione viene valutata completamente
prima delle expr (inserisce un sequence
point), le parentesi sono opzionali ma
consigliabili per chiarezza
 Viene calcolata una sola delle due expr
21 22

Espressioni condizionali Precedenza e associatività


 Il tipo del risultato è sempre il più “capiente” () [] -> . SD
tra quelli prodotti dalle due expr ! ~ ++ –– + – * & (cast ) sizeof SD
* / % SD
(flag == 1) ? 11 : 12.0; + - (somma e sottrazione) SD
restituisce sempre un valore double perché << >> SD
12.0 è un double mentre 11 un int (quindi < <= > >= SD
restituisce 11.0 quando flag vale 1) == != SD
& SD
 Ha associatività da destra a sinistra: ^ SD
x=(a>b && a>c) ? a : (b>c)? b:c; | SD
equivale a: && SD
x=(a>b && a>c) ? a : ((b>c)? b:c); || SD
?: SD
 Un espressione condizionale non produce un = += –= *= /= %= &= ^= |= <<= >>= SD
L-value quindi non si può scrivere: , SD
(a>b)?a:b = 12;  SD: da Sinistra a Destra, SD: da Dst. a Sin.

23 24

Big-endian e little-endian Big-endian e little-endian


 Indicano l'ordine in cui una sequenza di byte  Nel formato little-endian alcuni calcoli sono
è memorizzata nella memoria più semplici e veloci (quando un numero
 big-endian rappresenta un ordine in cui aumenta, si aggiungono byte per le cifre più
"big end" (il valore più significativo nella significative nella parte alta della memoria)
sequenza) è memorizzato prima (ad un  I processori Intel sono little-endian
indirizzo di memorizzazione più basso)  Il TCP/IP memorizza i dati come big-endian
 little-endian è un ordine in cui "little end" (detto per questo anche network order)
(il valore meno significativo della sequenza)  I processori Motorola sono big-endian
è memorizzato prima  I mainframe IBM e i supercomputer Cray sono
 Esempio: in un computer big-endian il num. big-endian
esadecimale 2F82 è memorizzato con 2F
all’indirizzo più basso e 82 in quello più alto
25 26

La funzione system Operatori bitwise


 Esegue un comando di shell  Operano su valori interi (con o senza segno) a
 E’ definita in <stdlib.h> livello dei singoli bit:
~ complemento a 1 ~x
 Sintassi & AND bit a bit x & y
system(stringa_con_comando); | OR bit a bit x | y
 Esempio ^ EXOR bit a bit x ^ y
Pulisce lo schermo << SHIFT a sinistra x << 2
system("CLS");  DOS/Windows >> SHIFT a destra x >> 2
system("clear");  Unix/Linux  Di solito si applicano a valori senza segno
 Esempio  Hanno priorità inferiore agli oper. matematici
Sospende l’esecuzione di un programma  Il risultato viene sempre convertito secondo le
system("pause");  DOS/Windows regole delle promozioni integrali (ad esempio,
anche se x è di tipo short, ~x è di tipo int)

27 28

Operatori bitwise ~ << >> Operatore bitwise &


 L’operatore ~ inverte tutti i bit:  z = x & y;
~0 dà un valore int pari a 11..11 (–1 in CA2)  Ciascuno dei bit di z viene determinato
 Gli operatori << e >> attuano uno shift del calcolando l’AND dei corrispondenti bit di x e y
numero di posizioni indicato dall’operando di
destra: y = x << 2;  L’operatore & viene spesso usato per azzerare
 Il numero di posizioni deve essere maggiore o (“unset” o “clear”) alcuni dei bit di un valore
uguale a zero e strettamente minore del dato (x) lasciando invariati gli altri
numero di bit dell’operando di sinistra  Per specificare quali bit debbano essere
 L’operatore << aggiunge sempre bit 0 a destra azzerati si predispone una maschera da
 L’operatore >> aggiunge bit 0 a sinistra solo se mettere in AND bit a bit con x
x è unsigned; se è signed non è definito
 Questi operatori hanno forma di assegnamento
abbreviata: &= ^= |= <<= >>=
29 30

Operatore bitwise & Operatore bitwise |


 La maschera è un numero intero, i bit del  z = x | y;
numero dato x in corrispondenza di bit a 0  Ciascuno dei bit di z viene determinato
della maschera vengono azzerati (mascherati, calcolando l’OR dei corrispondenti bit di x e y
non passano attraverso la mashera), mentre  L’operatore | viene spesso usato per
quelli in corrispondenza di bit a 1 restano impostare a 1 (“set”) alcuni dei bit di un
invariati (passano attraverso la maschera) valore dato (x) lasciando invariati gli altri
 Esempio  Per specificare quali bit debbano essere
y = x & 015; impostati a 1 si predispone una maschera da
mettere in OR bit a bit con x
valore: x =2610  0..0110102
maschera: 158  0..0011012
risultato: y  0..0010002

31 32

Operatore bitwise | Operatore bitwise ^


 La maschera è un numero intero, i bit del  z = x ^ y;
numero dato x in corrispondenza di bit a 1  Ciascuno dei bit di z viene determinato
della maschera vengono impostati a 1, calcolando l’EXOR dei corrispondenti bit
mentre quelli in corrispondenza di bit a 0 di x e y
restano invariati  L’operatore ^ viene spesso usato per invertire
 Esempio alcuni dei bit di un valore dato (x) lasciando
y = x & 012; invariati gli altri
valore: x =2210  0..0101102  Per specificare quali bit debbano essere
maschera: 128  0..0011002 invertiti si predispone una maschera da
risultato: y  0..0111102 mettere in EXOR bit a bit con x
33 34

Operatore bitwise ^ Operatori bitwise e logici


 La maschera è un numero intero, i bit del  Quando le espressioni collegate dagli
numero dato x in corrispondenza di bit a 1 operatori hanno solo valori 0 e 1, si
della maschera vengono invertiti, mentre potrebbero utilizzare gli operatori bitwise al
quelli in corrispondenza di bit a 0 restano posto degli operatori logici, ma:
invariati
 la valutazione delle espressioni logiche non si
 Esempio ferma non appena il valore del risultato è
y = x & 016; individuabile
valore: x =2210  0..0101102  non c’è la garanzia di esecuzione da sinistra a
maschera: 168  0..0011102 destra degli operatori
risultato: y  0..0110002  Potrebbe invece essere utile utilizzare
l’operatore bitwise EXOR in quanto non esiste
il corrispondente operatore logico

35 36

Esercizi Homework 3-4


1. Determinare di quanti bit è composto un tipo Metodo di ordinamento Radix Sort
char, short, int e long contando i bit.  Per ordinare numeri interi positivi
2. Visualizzare in binario il valore intero (decimale  Lavora facendo riordinamenti parziali prima
con segno) dato in input. sulle unità, poi sulle decine, poi sulle
3. Scrivere un programma che chieda un valore centinaia, ecc.
intero decimale, lo visualizzi in binario e calcoli
 Esempio
quanti sono i bit pari a 1 che contiene.
 Dati i valori: 7, 12, 9, 25, 36, 11, 20, 4
4. Scrivere un programma che chieda un valore
Scriverli utilizzando per tutti lo stesso numero di
decimale senza segno (da collocare in una 
cifre: 07, 12, 09, 25, 36, 11, 20, 04
variabile unsigned int) e ruoti i bit di n
 Definire una matrice avente per righe i valori delle
posizioni a sinistra o a destra a richiesta cifre e per colonne i numeri dati
(“ruotare” i bit significa che quelli che escono
Collocare i numeri sulla riga corrispondente alla
da una parte entrano dall’altra). 
cifra delle unità, ma nella stessa colonna
37 38

Homework 3-4 Homework 3-4


Collocamento dei valori in base alla cifra unità  Raccogliere i valori riga per riga e ricollocarli in
07 12 09 25 36 11 20 04 base alla cifra decine
0 20 20 11 12 04 25 36 07 09
1 11 0 04 07 09
2 12 1 11 12
3 2 20 25
4 04 3 36
5 25 4 ................................
6 36  Raccoglierli nuovamente riga per riga (se ci fossero
7 07 più cifre l’operazione andrebbe ripetuta sulle
centinaia, sulle migliaia, etc.)
8
04 07 09 11 12 20 25 36
9 09

39 40

Homework 3 Homework 4
Si scriva un programma che realizzi il metodo di Scrivere un programma che realizzi il metodo di
ordinamento Radix Sort di valori decimali (max ordinamento Radix Sort di valori decimali (max
100 valori), considerando le singole cifre 100 valori), considerando le singole cifre binarie
decimali come visto nell’esempio, i valori del valore binario equivalente (utilizzare gli
vengano assegnati in decimale mediante scanf. operatori bitwise sulle variabili), i valori vengano
assegnati in decimale mediante scanf.