Un
linguaggio di programmazione può essere suddiviso in tre livelli:
-
Il livello lessicale comprende tutte le definizioni del linguaggio (parole
chiave, comandi, funzioni, simboli...). Il compilatore riconosce eventuali errori
lessicali. Sono elementi lessicali: gli identificatori
(sequenze di lettere e cifre numeriche incluso "_", ma devono iniziare con una
lettera), che sono definiti dal programmatore; le parole
riservate (simboli standard del linguaggio di programmazione) che non
possono essere ridefiniti dal programmatore. Due elementi lessicali sono separati
da " " o da "\n". Si distinguono OPERATORI (simboli che
indicano operazioni, ad esempio +,-,*...) e DIRETTIVE del preprocessore (quelle
precedute dal carattere # e che terminano alla fine della riga senza ;). Altri
elementi lessicali sono le COSTANTI che rappresentano valori costanti nel programma
(const int x=5;, const float a=6.7;). Infine i COMMENTI sono simboli che vengono
ignorati dal compilatore e sono utili al programmatore per spiegare il programma:
sono delimitati da /*... */ (anche su diverse righe) o da // e fine riga.
I dati primitivi sono quelli
elementari che vengono riconosciuti dal compilatore senza l'utilizzo di header
files. Questi dati non sono oggetti proprio perché non fanno parte di una classe.
Questa è una scelta del C.
-
interi
byte |
8
bit |
127 |
-128 |
short |
16
bit |
32,767 |
-32,768 |
int |
32
bit |
2,147,438,647 |
-2,147,438,648 |
long |
64
bit |
9,223,372,036,854,775,807
(circa 9.2E18) |
|
-
reali
float |
32
bit |
3.4e38
(circa) |
double |
64
bit |
1.8e308
(circa) |
-
caratteri
char |
8
bit (ASCII) per C/C++ 16
bit (UNICODE) per Java |
-
logici (SOLO C++ e Java)
bool |
(true,
false) |
Il compilatore è in grado
di valutare espressioni logiche (che ritornano un valore di tipo bool true o
false). Gli operatori utili per queste espressioni sono:
Operatori
di confronto
|
||
==
ugualianza (diversa da assegnazione)
|
||
!=
disugualianza
|
||
<
> >=
<=
ordinamento
|
||
Operatori
logici
|
||
||
or
|
||
&&
and
|
||
!
not
|
||
Attenzione: in C ogni elemento
diverso da zero è interpretato come true.
L'if
else è una struttura di controllo che esegue un'istruzione o un blocco di istruzioni
se una certa espressione logica è vera, oppure, se è falsa, esegue delle altre
istruzioni. Ecco la sintassi:
if
(a == b) |
||
{istruzioni
primo blocco} |
||
else |
||
{istruzioni secondo blocco} | ||
a==b è l'espressione logica: se è vera vengono eseguite le istruzioni del primo blocco, se è falsa quelle del secondo blocco. Il ramo else si può tralasciare: in questo caso, se l’espressione logica è falsa non viene eseguita nessuna istruzione.
Serve per scegliere tra
varie opzioni associate ad una costante. Ecco la sintassi:
switch (espressione) |
||
case (costante): |
||
{istruzioni; |
||
break;} |
||
case
(costante): |
||
{istruzioni; |
||
break;} |
||
default: |
||
{istruzioni;} |
||
L'espressione tra parentesi deve ritornare un valore costante che viene confrontato con le costanti associate ai vari case. Se il valore dell'espressione è uguale ad una delle costanti vengono eseguite le istruzioni a partire da quel case in poi (in questo caso fino al break; che fa eseguire le istruzioni successive al blocco del default). Se il valore dell’espressione non corrisponde a nessuna costante vengono eseguite le istruzioni di default.
Il for è un'istruzione che
permette di eseguire un ciclo, cioè ripetere un gruppo di istruzioni un certo
numero di volte. Ecco la sintassi:
for
(inizializzazione; controllo; incremento) |
||
{istruzioni} |
||
for(i=0;
i<10; i++) |
||
{istruzioni} |
||
Viene così eseguito il blocco
di istruzioni fino a quando il controllo (che è un espressione logica) non diventa
false. La variabile i che viene inizializzata la prima volta e poi incrementata
di 1 ad ogni ciclo è una sorta di contatore. Se il controllo non diventa mai
falso il ciclo viene eseguito all'infinito e il computer va in loop quando viene
eseguito il programma.
Permette di eseguire delle
istruzioni in modo ciclico ma la sintassi è differente da quella del for:
while
(controllo)
{istruzioni}
Il controllo è sempre un espressione logica che può essere true o false. Finchè il controllo è true le istruzioni del blocco continuano ad essere eseguite ciclicamente. Quando il controllo diventa falso vengono eseguite direttamente le istruzioni successive al blocco. Il ciclo while permette di eseguire le istruzioni del blocco un numero di volte non definibile a priori. Il for è invece utile per eseguire un certo gruppo di istruzioni un numero di volte prestabilito. Con un while si può fare il for e viceversa.
La sintassi è la seguente:
Do |
||
{istruzioni} | ||
while (controllo); | ||
viene sempre eseguito un ciclo ma, differentemente dal while, l'istruzione viene eseguita almeno una volta. Quando il controllo diventa false vengono eseguite le istruzioni successive
Break;
è un istruzione che interrompe l'esecuzione del ciclo o dello switch nel punto
in cui si trova e fa eseguire le istruzioni che sono subito fuori del ciclo.
Continue
invece permette di saltare un ciclo all'interno ad esempio di un for: viene
incrementato il contatore senza eseguire il blocco di istruzioni:
for
(int i=0; i<10; i++)
{if
(i==2) continue;
istruzioni}
quando i assume il valore 2 viene eseguito continue: non vengono eseguite per questo ciclo le istruzioni successive e viene incrementato direttamente il contatore i. Alla fine vengono eseguiti 9 cicli invece di 10
Nella
programmazione le funzioni sono utili per vari motivi: frammentano il codice
rendendolo più comprensibile, talvolta fanno risparmiare linee di codice (ad
esempio definendo una funzione che viene richiamata più volte nel programma).
Una
funzione una volta dichiarata e definita può essere richiamata in ogni momento
e con valori diversi in ingresso. Per la dichiarazione e definizione vedi lezione
3-12-2001.
Gli
argomenti di una funzione sono quelli che questa prende in ingresso. Il passaggio
dei parametri alla funzione viene effettuato alla chiamata:
int f (int , int ); | // dichiarazione | ||
int f (int a, int b) | // definizione |
||
{a=a+b; | |||
return a;} | |||
x=f(y,z); | //chiamata
a funzione |
||
I parametri (y
e z, che sono variabili di tipo int) sono passati per valore: in a e b vengono
copiati i valori delle variabili x e y. I parametri possono però essere passati
anche per riferimento, cioè si passa alla funzione un puntatore ad un indirizzo
di memoria:
int f (int *, int * ); |
// dichiarazione |
||
int f (int *a, int *b) | // definizione |
||
{*a=*a+*b; | |||
return *a;} | |||
x=f(y,z); | //
chiamata a funzione |
||
Questa
volta in a e b vengono copiati gli indirizzi delle celle di memoria in cui sono
memorizzati i valori di y e z. Il simbolo *a è il valore contenuto nella cella
di memoria di indirizzo a. Se viene modificato il valore contenuto nella cella
di indirizzo a viene in pratica modificato il valore di y. In questo caso quindi,
all’uscita della funzione, in y c'è y+z, mentre nell'esempio precedente i valori
di y e z non vengono modificati.
Un modo equivalente per fare una funzione di questo tipo è il seguente:
int f (int& , int& ); | // dichiarazione |
||
int f (int& a, int& b) | // definizione |
||
{a=a+b; | |||
return a;} | |||
x=f(y,z); | // chiamata a funzione | ||
L'operatore & estrae l'indirizzo della variabile passata: in &a c'è l'indirizzo di y mentre in a c'è il valore contenuto in tale indirizzo. Quindi anche stavolta, dopo l'esecuzione della funzione in y c'è il valore della somma y+z.
vedi anche: Costanti e Funzioni (lezione 9-1-2002)