Tipi, operatori ed espressioni nel linguaggio in C
Il linguaggio C (come qualsiasi altro linguaggio di programmazione) consente la realizzazione di programmi adoperando un insieme di "parole chiave" (keywords).
Lo standard ANSI ha definito il seguente insieme di 32 parole chiave:
asm, break, case, catch, char, continue, default, delete, do, double, else, extern, float, for, goto, if, inline, int, long, register, return, short, signed, sizeof, static, struct, switch, typedef, union, unsigned, void.
Tipi di Dati e Dimensioni
modificaConcettualmente, le variabili si possono definire come contenitori di dati. Esse infatti corrispondono a locazioni di memoria di determinate dimensioni, contenenti un certo dato. Il tipo di dato e la dimensione della locazione di memoria sono definiti durante la definizione della variabile.
Ogni variabile ha un tipo che indica appunto il tipo di dato che la variabile può contenere. In c i tipo di dati fondamentali sono i seguenti:
- char
- int
- float
- double
Il tipo di dato char occupa in memoria un singolo byte, ed è in grado di rappresentare uno qualsiasi dei caratteri del set locale; il range di valori che può contenere, va da 0 a 255 se senza segno, oppure da -128 a 127 se con segno.
Il tipo di dato int è utilizzato per contenere numeri interi. La dimensione di questa variabile dipende dall'implementazione: nei moderni compilatori, il dato di tipo int ha dimensione 4 byte, ovvero 32 bit. Il range di valori per questo tipo va da 0 a (2^32)-1 se senza segno, altrimenti da -2^31 a +(2^31) - 1.
Il tipo di dato float è utilizzato per contenere valori in virgola mobile, a singola precisione. La dimensione di una variabile float è di 32 bit (ovvero 4 byte).
Il tipo di dato double è utilizzato per contenere valori in virgola mobile a doppia precisione. La dimensione di una variabile double è di 64 bit (ovvero 8 byte).
I nomi delle variabili in C devono seguire delle regole ben precise: il primo carattere del nome deve essere una lettera maiuscola o minuscola oppure un 'underscore' ('_'); non possono iniziare con un numero. Inoltre il C è case-sensitive: in poche parole, il C, contrariamente al Basic per esempio, distingue le lettere minuscole da quelle maiuscole. Questo vuol dire che se chiamate una variabile per esempio pRova, non potete poi chiamarla prova perché sono due nomi diversi.
La definizione di variabili in C, si effettua in questo modo:
tipo nome_variabile; tipo nome_variabile = valore;
tipo corrisponde ovviamente ad uno dei tipi elencati sopra. Mentre valore è un valore del tipo tipo. In queste due righe di codice, abbiamo dichiarato una variabile di nome nome_variabile in due modi differenti. Nella prima riga abbiamo solo dichiarato una variabile, ma non le è stato assegnato alcun valore. Ciò non ci permette di utilizzarla in modo sicuro, poiché potrebbe contenere un valore qualunque. Il secondo metodo ci permette invece di inizializzare la variabile al momento della dichiarazione; questo è il metodo che si dovrebbe sempre utilizzare per dichiarare una variabile.
Da quanto detto fino ad ora, è evidente che il C non definisce un tipo per il dato stringa. Questa però non vuol dire che non si possono gestire stringhe: le stringhe vengono infatti definite come array di caratteri, terminati da un carattere nullo. In seguito parleremo degli array e dei puntatori soffermandoci particolarmente sulle stringhe e la loro manipolazione.
Costanti
modificaLe costanti sono celle di memoria nelle quali si scrive un'informazione che non si pò modificare fino alla fine del programma. In C le costanti non sono quasi mai usate poiché esiste il comando del preprocessore #define che sostituisce, ogni volta che viene incontrata la costante con il suo contenuto. Se per esempio scriviamo
#define SETTE 7
il precompilatore ogni volta che incontra la stringa SETTE la sostituisce con 7.
È buona abitudine usare i caratteri maiuscoli in modo da riconosciere subito all'interno di un programma cosa il precompilatore modificherà.
Operatori
modificaIl C fornisce svariati tipi di operatori: Aritmetici, Relazionali e Logici, di incremento e decremento, bit a bit e di Assegnamento. Cercheremo di vederne la maggior parte anche se alcuni molto importanti come l'operatore -> freccina verrà introdotto in lezioni successive
Operatori Aritmetici
modificaGli operatori aritmetici sono:
- * Prodotto
- / Rapporto
- % Modulo. Calcola il resto di una divisione intera. Es. 9 % 5 = 4
- + Somma
- - Differenza (negativo)
Da notare che la divisione intera tronca qualsiasi parte frazionaria; mentre l'espressione x % y ritorna il resto della divisione di x per y, e quindi restituisce 0 se x è un multiplo di y. Per esempio, un anno è bisestile se è divisibile per 4 ma non per 100, fatta eccezione per gli anni divisibili per 400, che sono bise-stili. Quindi
if ((year%4==0 && year%100!=0) || year%400==0)
printf(“Il %d è un anno bisestile\n”, year);
else
printf(“Il %d non è un anno bisestile\n”, year);
L'operatore % non è applicabile ai float ed ai double. Per i numeri negativi, la direzione di troncamento per / ed il segno del risultato di % dipendono dalla macchina, analogamente a quanto accade per le azioni intraprese in caso di overflow o di underflow. Gli operatori binari + e - hanno la stessa precedenza, che è inferiore a quella di *, / e %, a loro volta aventi precedenza inferiore agli operatori unari + e -. Tutti gli operatori aritmetici sono associativi da sinistra a destra.
Operatori Relazionali e Logici
modificaGli operatori relazionali hanno tutti la stessa precedenza e sono:
- > Maggiore
- >= Maggiore o uguale
- < Minore
- <= Minore o uguale
Gli operatori relazionali hanno precedenza inferiore agli operatori aritmetici, perciò un'espressione come i<m-1 viene interpretata come i<(m-1).
Immediatamente sotto di loro, nella scala delle precedenze, troviamo gli operatori di uguaglianza:
- == (uguale a)
- != (diverso da)
Molto importanti sono gli operatori logici && e ||. Le espressioni connesse da && e || vengono valutate da sinistra a destra, e la valutazione si blocca non appena si determina la verità o la falsità dell'intera espressione.
Conversioni di tipo
modificaQuando un operatore ha operandi di tipo diverso, questi vengono convertiti in un tipo comune. In generale, le uniche conversioni automatiche sono quelle che trasformano un operando “più piccolo” in uno “più grande” in modo da non avere perdite di informazione, come nel caso della conversione di un intero in un floating-point. Espressioni prive di senso, come per esempio l'uso di un float come indice, non sono consentite. Espressioni che possono provocare una perdita di informazione, come l'assegnamento di un float ad un intero, producono al più un messaggio di warning, ma non sono illegali, anche se devono esser usate con cautela.
Ci sono funzioni apposite per la conversione da stringe a numeri e viceversa, ma vedremo il loro utilizzo solo quando avremo spiegato le stringe.
Operatori di Incremento e Decremento
modificaIn C è possibile utilizzare gli operatori ++ e -- i quali permettono rispettivamente di incrementare o decrementare di uno una determinata variabile o anche i puntatori che vedremo più avanti. Questi operatori possono essere messi sia a sinistra che a destra di una variabile, ma attenzione non sono la stessa cosa. Se un operatore di incremento o decremento viene messo prima di una variabile l'operazione di incremento e decremento verrà fatta prima di qualsiasi altra operazione della stessa riga di codice; al contrario se l'operatore viene messo di seguito l'operazione verrà fatta per ultima. Un esempio semplice ci permette di togliere qualsiasi dubbio, evitando errori in futuro.
int num = 2;
printf(“prima la variabile num vale %d\n”, num++);
printf(“dopo la variabile num vale %d\n”, ++num);
Questo esempio produce il seguente output:
Prima la variabile num vale 2 Dopo la variabile num vale 4
Operatori di Assegnamento ed Espressioni
modifica- *= Moltiplica il valore della variabile a sinistra per il valore a destra e lo riassegna alla variabile
- /= Come il precedente, ma con il rapporto
- %= Come il precedente, ma con l'operatore modulo
- += Aggiunge alla variabile a sinistra il valore a destra
- -= Sottrae alla variabile a sinistra il valore a destra
- = Assegnamento
- == Confronto tra due valori
La differenza tra l'operatore = e l' operatore == è molto importante, poiché se si vogliono confrontare due variabili e si usa l'operatore =, il risultato sarà solo l'assegnazione alla variabile a sinistra del valore della variabile a destra e verrà restituito tale valore. Questo è un classico errore di programmazione, dovuto soprattutto alla fretta o ad una tastiera difettosa.
Operatori bit a bit
modificaPer la manipolazione dei bit, il C fornisce sei operatori, applicabili soltanto ad operandi interi, cioè char, short, int e long, con o senza segno.
- & AND
- | OR inclusivo bit a bit
- ^ OR esclusivo bit a bit
- << shift a sinistra
- >> shift a destra
- ~ complemento a uno (unario)
Gli operatori &= e |= funzionano nello stesso modo degli operatori +=, -=, *=, /=.
Precedenza ed Ordine di Valutazione
modificaÈ molto importante tener conto delle precedenze poiché un errato uso degli operatori può portare ad errori difficili da riscontrare soprattutto in grossi programmi, questo poiché sintatticamente il programma è corretto, e quindi il compilatore non segnala nessun errore. Inoltre le precedenze tra le chiamate di funzioni ed operatori possono dipendere da compilatore a compilatore, ed è quindi buona cosa separare le righe di codice ambigue.