I tipi di variabile

Arrivati a questo punto sappiamo come si crea un programma minimo in C++;
sappiamo che il punto nevralgico di un programma in C++ è la funzione main(), che questa è la procedura principale che viene chiamata quando viene lanciato il programma;
sappiamo come mostrare delle scritte sullo schermo, e come raccogliere dell'input da tastiera per salvarlo in una variabile;
sappiamo come dichiarare una variabile, come inizializzarla e come assegnare ad una variabile dei valori all'interno del nostro codice;
sappiamo inoltre che una variabile ha un tipo specifico, e può contenere solo dati di quel tipo;
sappiamo infine che una variabile non può essere utilizzata se prima non è stata dichiarata.

Sappiamo che una variabile è composta dal tipo, seguito dal nome della variabile. Ma che nome può assumere una variabile? La scelta sta al programmatore, anche se dobbiamo tenere a mente alcune cose.
Infatti il nome di una variabile può contenere solo lettere e numeri, e l'underscore: _
Una variabile non può iniziare con una cifra, e può contenere sia lettere maiuscole che minuscole.
Ricordiamoci però che il C++ è case sensitive, e cioé fa differenza tra minuscole e maiuscole:

int varEtà;

varetà = 24; //ERRATO!

varEtà = 24; //CORRETTO!

Non possiamo assegnare un valore a varetà, per il semplice motivo che la variabile varetà non esiste, non essendo stata dichiarata. La variabile che abbiamo dichiarato si chiama varEtà, e quella "E" maiuscola fa la differenza.

Perciò in teoria questo è legittimo:

int variabile;
int Variabile;

Ricordate cosa abbiamo detto in passato? Che una stessa variabile non può essere dichiarata due volte; o per dirla in un altro modo, che due variabili non possono avere lo stesso nome, perché il compilatore restituisce errore.
Ma in questo caso si tratta di due variabili diverse ed autonome, avendo la prima la "v" minuscola, e la seconda la "V" maiuscola.
Tuttavia è sconsigliabile utilizzare più variabili con nomi simili o addirittura identici tranne la differenza di maiuscole e minuscole, perché rischiamo di confonderci.

Un'altra cosa da ricordare è che non possiamo utilizzare una parola chiave del C++ come nome di una variabile.
Ad esempio:

int float;

Come potrebbe il compilatore capire se ci riferiamo al tipo float e non alla variabile float?

In aggiunta non possiamo far iniziare il nome di una variabile con uno o due underscore, essendo queste forme di nomi riservate alle risorse del compilatore e agli identificatori globali (non ci interessa sapere cosa sono, ci basti ricordare che le nostre variabili non possono iniziare così).

A scopo informativo dobbiamo aggiungere che, mentre in C una variabile può essere composta da massimo 63 caratteri, nel C++ la lunghezza del nome di una variabile non ha limiti.

Detto questo, possiamo introdurre finalmente i tipi di variabile presenti nel C++!

- I tipi int, short, long:

Abbiamo già visto il tipo int in azione. Una variabile di tipo int è una variabile che potrà contenere solo numeri interi.

Tuttavia int non è l'unico tipo di variabile che può contenere interi. Ne esistono altri tre tipi.
In tutto per la prappresentazione di interi abbiamo: short, char, int, long.

Perché usare quattro tipi diversi di interi invece di uno solo? Perché i numeri sono infiniti, mentre la memoria RAM del computer non lo è affatto. Perciò, per risparmiare risorse, sono stati creati diversi tipi di interi, in base alla grandezza del numero da inserire nella variabile.

Ad esempio, soprattutto su programmi che girano su computer datati, è inutile utilizzare il tipo long se sappiamo che la variabile andrà a contenere solo numeri piccoli.

Al contrario se abbiamo a che fare con numeri molto grandi (immaginiamo ad esempio a programmi di astronomia che trattano dati come la distanza delle stelle dalla terra) non possiamo utilizzare il tipo short perché non sarà abbastanza capiente e troncherà il numero.

Questo succede perché, nel momento in cui inizializziamo una variabile, diciamo al compilatore di riservare uno spazio in memoria grande abbastanza da contenere un valore di una certa grandezza.

La capacità dei vari tipi cambia da architettura ad architettura ma, tralasciando per il momento il tipo char che è un tipo particolare utilizzato per contenere caratteri, l'ordine di grandezza dei rimanenti tipi di intero è il seguente:

short: occupa almeno 16 bit (ma in alcune architetture occupa una memoria maggiore)

int: occupa almeno una memoria equivalente a short, ma può contenere anche di più

long: occupa almeno 32 bit, e comunque mai meno di int

Abbiamo detto che la memoria occupata varia in base al tipo di computer, ad esempio nei comuni Intel short e int occupano entrambi 16 bit, quindi all'atto pratico sono equivalenti e non ha senso usare l'uno al posto dell'altro; mentre sempre negli Intel il tipo long occupa 32 bit.

Quanto abbiamo detto ha una validità più teorica che pratica, dal momento che il più delle volte ci limiteremo ad utilizzare il tipo int.

Tuttavia è importante capire bene che cosa succede durante la dichiarazione di una variabile.
Lo ripeto perché ci servirà in futuro per capire meglio il funzionamento dei puntatori (è un argomento piuttosto avanzato, per ora non ha senso preoccuparcene):

durante la dichiarazione di una variabile, il compilatore riserva alla stessa variabile uno spazio di memoria atto a contenere dei valori di quel tipo.

Ad esempio su un Intel, la seguente dichiarazione riserverà alla variabile uno spazio in RAM equivalente a 16 bit:

int variabile1;

Mentre la seguente dichiarazione riserverà alla variabile uno spazio di 32 bit:

long variabile2;

L'atto di riservare un tot di memoria per una variabile è detto allocazione di memoria.
Da quel momento in poi, quella variabile punterà alla locazione di memoria riservata ad essa.
In altre parole la variabile è solo un'etichetta che diamo ad uno spazio in memoria RAM. Sarebbe scomodo, nonché rischioso, per un programmatore utilizzare il codice binario per riferirsi allo spazio in memoria dove sono salvati i dati.
Scomodo perché il programmatore dovrebbe ricordare tutti i codici delle varie locazioni di memoria, per potervi accedere (ad esempio 00101001 01101110).
Pericoloso perché un programmatore non può sapere se quell'area di memoria è vuota o contiene già dei dati, come ad esempio il codice macchina dell'istruzione di un programma o di una parte del sistema operativo.
Per fortuna è il sistema operativo ad assegnare la memoria ogni volta che eseguiamo un programma, al programmatore basta indicare lo spazio che ci serve (con i vari identificatori di tipo, appunto) perché il sistema operativo sappia quanto spazio allocare per i vari dati del programma.

La variabile è quindi un semplice riferimento ad una locazione di memoria, con un nome facile da ricordare per il programmatore.
Nel momento in cui utilizziamo una variabile precedentemente dichiarata, il programma non fa altro che sostituire il nome della variabile con la locazione della memoria a cui essa punta, e ad inserire o prelevare il contenuto di tale locazione di memoria.
Ovviamente il programmatore di C++, a differenza del programmatore in Assembler, non deve sapere niente di questi particolari.

Ora che abbiamo chiaro cosa avviene durante la definizione di una variabile, e del perché è necessario specificare il tipo della variabile (mi raccomando non lo dimenticate, affronteremo di nuovo l'argomento quando parleremo dei puntatori), vediamo gli altri tipi di variabile.

Prima però dobbiamo parlare dei modificatori di tipo.
Uno di questi è il modificatore unsigned, che dice al compilatore che la variabile andrà a contenere solo valori positivi (unsigned significa senza segno).
Ad esempio:

unsigned int miaVariabile2;

Ora miaVariabile2 potrà contenere solo valori interi positivi.
Questo è necessario per il discorso fatto prima. Abbiamo detto che le variabili di tipo int avranno allocato uno spazio in memoria di 16 bit. In pratica questo significa che una variabile int potrà contenere dei numeri che oscillano tra -32768 e +32768.
Se invece siamo certi di dover trattare degli interi solo positivi, e se siamo altrettanto certi di dover utilizzare numeri maggiori di 32768, possiamo utilizzare il modificatore unsigned.
Nel momento in cui lo utilizziamo, diremo al compilatore che la variabile non conterrà mai valori minori di zero, liberando così lo spazio che normalmente viene allocato per dare la possibilità di contenere i numeri che vanno da -1 a -32768. A questo punto metà dello spazio è disponibile e ci da la possibilità di arrivare a rappresentare dei numeri che vanno dallo 0 sino a +65535.
Avremmo potuto utilizzare "long miaVariabile2", ma in questo modo avremmo occupato inutilmente 32 bit, e cioé una memoria tale da poter memorizzar un range di numeri che va da -65535 a +65535. In entrambi i casi possiamo rappresentare numeri che superano il +32768, ma nel secondo caso occupiamo 32 bit, mentre nel primo caso ne occupiamo solo 16. Ovviamente se dobbiamo trattare anche numeri negativi non possiamo contare sul modificatore unsigned e dovremo optare per un long al posto di int.

Il modificatore unsigned vale anche per gli altri tipi, quindi non solo per int.

- Il tipo char:

Come ho già accennato prima, il tipo char è un tipo di intero che serve per memorizzare i caratteri. Come forse saprete ad ogni carattere corrisponde un codice numerico, chiamato codice ASCII (purtroppo no, non si fuma). Un sistema può avere al massimo 256 caratteri tra lettere, numeri e simboli.
Il tipo char serve ad allocare in memoria uno spazio tale da poter contenere uno di questi codici numerici, tra i quali il più grande è il 255 che in binario si scrive 11111111.
Come potete vedere, è composto da 8 cifre, che corrispondono ad 1 Byte.
Come tutti voi saprete 1 Byte equivale a 8 bit, quindi la dichiarazione di una variabile di tipo char allocherà in memoria uno spazio di 8 bit.
Solitamente le variabili di tipo char sevono a memorizzare i caratteri, ma nessuno ci vieta di utilizzarle per memorizzare piccoli numeri (nello specifico da 0 a 255).

Abbiamo detto che le stringhe vengono racchiuse tra doppi apici " ", mentre per i singoli caratteri la convenzione è quella di usare un singolo apice ' (l'apostrofo).

sting varStringa = "questa è una stringa"; //vedremo in seguito il tipo string

char varChar = 'A'; //come vedete non ho scritto "A" ma 'A'

Prima di proseguire è bene sapre che alcuni caratteri non possono essere stampati direttamente a schermo, semplicemente scrivendoli.
Ad esempio mettiamo di voler stampare una stringa che contiene delle virgolette al suo interno:

cout << "questa stringa contiene delle virgolette " al suo interno";

Come potrete intuire le virgolette vengono già utilizzate dal C++ come delimitatori di stringa. Quindi il compilatore, quando incontra il secondo doppio apice, tra le parole virgolette e al, lo interpreta come la fine della stringa, mentre la stringa finisce dopo la parola interno.
Per evitare questo basta far precedere le virgolette da un backslash: \

cout << "questa stringa contiene delle virgolette \" al suo interno";

Ora la stringa sarà stampata correttamente nella sua completezza, comprese le virgolette.
Lo stesso avviene con altri caratteri speciali, il punto interrogativo, gli apici singoli (apostrofo) e lo stesso backslash. Anche qui basterà farli precedere da un backslash per risolvere il problema:

\? stamperà ?
\' stamperà '
\\ stamperà \

Lo stesso vale per alcuni caratteri speciali di formattazione.
Ad esempio per aggiungere una tablatura tra una parola e l'altra basterà inserire \t tra le due parole. Esistono altri simboli speciali per la formattazione del testo, lascio a voi il compito di scoprirli.

Abbiamo detto che una variabile di tipo char può contenere dei numeri che vanno da 0 a 255, e quindi solo numeri positivi.
Se per caso avessimo bisogno di memorizzare anche numeri negativi all'interno della variabile di tipo char, potremmo usare il modificatore signed, che fa esattamente l'opposto di unsigned.

Per completezza dobbiamo aggiungere che esistono dei set di caratteri non standard che vanno oltre il valore 255, e per memorizzarli il C++ ha un nuovo tipo, chiamato wchar_t, che sta a significare widechar.

- I Tipi float e double:

Sino ad ora abbiamo visto solo i tipi per i numeri interi, vediamo ora i tipi per i numeri con la virgola.
Il dicorso è simile a quallo fatto con char, short, int, long.

Il tipo float alloca una memoria di almeno 32 bit.
Il tipo double alloca una memoria di almeno 48 bit, e comunque mai minore di float.
Il tipo long double alloca 80 a 128 bits;

Molto sul loro utilizzo dipende dalla precisione che ci serve, e cioé di quanti numeri dopo la virgola vogliamo rappresentare.
Il tipo float ci permette di rappresentare al massimo 6 cifre dopo la virgola, mentre il tipo double ci permette di rappresentarne 15.
Se poi abbiamo bisogno di una precisione ancora maggiore, possiamo utilizzare il tipo long double.

-Il tipo bool:

Il C++ introduce un nuovo tipo, chiamato bool.
L'algebra boleana è un tipo di algebra che utilizza solo due valori logici, vero o falso.
E' molto utilizzata in elettronica, dove il tutto si riduce alla presenza o assenza di segnale.
In altre parole un segnale può assumere solo due valori, vero o falso, acceso o spento, 0 o 1, e così via...
In C++ una variabile di tipo bool, può assumere quindi solo due valori, indicati dalle parole true e false.
Volendo si possono utilizzare anche i numeri 0 e 1, ma per chiarezza è meglio optare per le parole true e false.

Le variabili di tipo bool sono utili per controllare ad esempio se un'operazione è andata a buon fine o meno. Vedremo meglio il loro utilizzo quando parleremo delle funzioni.

-Il qualificatore const:

Il qualificatore const non è un tipo di variabile ma una parola chiave che, come indica il nome stesso, serve ad indicare che il contenuto di una variabile è costante, e cioè non può essere modificato.
Facciamo un esempio:

const float piGreco = 3,14; //ora piGreco è una costante che contiene il valore 3,14

piGreco = 5,284; //ERRATO! una costante non si può modificare!

Una volta dichiarata e inizializzata, una costante avrà quel valore per tutta la durata del programma, e non potrà essere mai modificata.
Questo è utile quando abbiamo dei dati, come appunto il pi greco 3,14 che sono quelli e basta.
In questo modo nel nostro programma potremo utilizzare il nominativo "piGreco" ogni volta che ci serve il pi greco, senza dover scrivere 3,14.
Può rivelarsi comodo quando abbiamo tanti dati che non cambiano, e non possiamo ricordarli a memoria, o comunque sarebbe dispendioso doverli scrivere a mano ogni volta che ci servono.

La parola chiave const svolge anche altri compiti importanti, che tratteremo quando arriveremo a parlare delle funzioni e poi ancora quando affronteremo la programmazione ad oggetti ed introdurremo le classi.

La parola chiave typedef invece crea un alias di un tipo, e cioè un nome creato da noi da utilizzare al posto del nome originale:

typedef int intero; //crea un alias a int di nome intero

intero var1; //crea una variabile int utilizzando l'alias appena creato con typedef

Rivediamo un attimo il tutto, per assicurarci di aver memorizzato bene tutti i tipi.

Tipi interi: short, int, long e char. Il più delle volte ci troveremo ad utilizzare int, mentre per i singoli caratteri useremo char.

Tipi in virgola mobile: float, double e long double. Il più delle volte ci troveremo ad utilizzare float.

Tipo boleano: bool. Può assumere solo i valori true (0) e false (1).

Modificatori: signed e unsigned. Servono per dire se una variabile conterrà o meno valori negativi.

Costanti: const. La parola chiave del C++ const serve per dichiarare delle costanti, e cioé delle variabili che avranno un valore costante nel tempo, e non potranno mai essere modificate.

ALIAS: typedef. La parola typedef permette di creare un nome alternativo da utilizzare per riferirsi al tipo originale. Ogni volta che utilizzaremo l'alias sarà come utilizzare il tipo originale.

Non abbiamo visto il tipo string perché si tratta di un tipo particolare, ma state tranquilli, lo vedremo in uno dei prossimi post.

Se avete ben chiaro in mente il compito degli identificatori di tipo, e ricordate a memoria i nomi almeno di quelli più usati (int, float, char, bool) potete proseguire al prossimo post.

Nessun commento:

Posta un commento