Lezione 4 di 7 · 20 min di lettura
Variabili e tipi
Come un programma ricorda le cose. Numeri interi, decimali, vero/falso, testo, e le regole per dare i nomi.
Una scatola con un’etichetta
Un programma che stampa sempre la stessa frase non è molto utile. Per fare qualcosa di interessante deve ricordare dei valori e lavorarci sopra. Il posto dove un programma ricorda le cose si chiama variabile.
Immagina una scatola con un’etichetta. L’etichetta è il nome, dentro c’è il valore, e la forma della scatola è il tipo: una scatola per numeri interi non può contenere del testo.
int eta = 34;Leggila così: “creo una scatola di tipo int (numero intero), la chiamo eta, e ci metto dentro 34”. Da questo momento, ogni volta che scrivi eta nel codice, il programma usa quel valore.
import std::io;
fn void main()
{
int eta = 34;
io::printn(eta);
eta = 35; // cambio il contenuto della scatola
io::printn(eta);
}34
35Nota la seconda assegnazione: eta = 35; senza int davanti. Il tipo si dichiara una volta sola, quando la variabile nasce. Dopo, si usa solo il nome. (Scrivere int eta = 35; una seconda volta sarebbe un errore: “variabile già dichiarata”.)
Zero di default
Cosa c’è in una variabile appena creata, se non le assegni niente?
int contatore;
io::printn(contatore);0In C3 le variabili nascono azzerate. Sempre. Sembra ovvio, ma non lo è affatto: in C una variabile locale non inizializzata contiene spazzatura (qualsiasi cosa ci fosse in quella zona di memoria prima), ed è la fonte di una quantità impressionante di bug. C3 ha chiuso la porta a questa categoria di errori.
I tipi numerici interi
int è il tipo intero “normale”: 32 bit, quindi va da circa −2 miliardi a +2 miliardi. Basta quasi sempre. Quando non basta, ci sono i suoi fratelli:
| Tipo | Bit | Intervallo | Quando usarlo |
|---|---|---|---|
int | 32 | −2 147 483 648 … 2 147 483 647 | Il default. Contatori, indici, quantità. |
long | 64 | ±9,2 trilioni | Numeri grandi: timestamp, byte di un disco, popolazione mondiale al quadrato. |
short | 16 | −32 768 … 32 767 | Raro. Quando la memoria conta davvero. |
ichar | 8 | −128 … 127 | Raro. Un byte con segno. |
int128 | 128 | Enorme | Crittografia, matematica esotica. |
E per ogni tipo con segno esiste il gemello senza segno (solo positivi, ma con il doppio dello spazio in alto): uint, ulong, ushort, char, uint128.
Sì, hai letto bene: char in C3 è un intero senza segno a 8 bit (0…255). Si chiama così per tradizione, perché un byte è spesso usato per rappresentare un carattere, ma il compilatore lo tratta come un numero. Ci torniamo tra poco.
Scrivere i numeri
Un numero scritto nel codice si chiama letterale. C3 ne accetta parecchie forme:
int decimale = 1_000_000; // il trattino basso è ignorato: serve agli occhi
int esadecimale = 0xFF; // 255, base 16
int binario = 0b1010; // 10, base 2
int ottale = 0o755; // 493, base 8
long grande = 3_000_000_000; // non entra in un int, ma in un long sìI trattini bassi sono un regalo: 1_000_000 si legge al volo, 1000000 no.
✏️ Quiz
Cosa succede compilando int x = 3_000_000_000;?
I numeri con la virgola
Per i numeri decimali (con la virgola, che nel codice è un punto) ci sono due tipi:
| Tipo | Bit | Precisione | Quando usarlo |
|---|---|---|---|
double | 64 | ~15 cifre significative | Il default. Quasi sempre. |
float | 32 | ~7 cifre significative | Grafica, audio, quando la memoria conta. |
double pi = 3.14159;
double avogadro = 6.022e23; // notazione scientifica: 6,022 × 10²³
float peso = 72.5f; // il suffisso f dice "questo è un float"
double intero_ma_decimale = 7; // un intero può diventare double senza problemiVero o falso: bool
Il tipo bool ha solo due valori possibili: true e false. Sembra poco, ma è il tipo con cui il programma decide: “l’utente ha vinto?”, “il file esiste?”, “il numero è pari?“.
bool piove = true;
bool ho_ombrello = false;
io::printn(piove);trueVedremo nella prossima lezione che i confronti (5 > 3) producono proprio un bool, e nel Modulo 2 che if lo usa per scegliere quale strada prendere.
Testo: String
Il testo si tiene in una String:
String nome = "Ada";
io::printn(nome);
io::printn(nome.len);Ada
3.len è la lunghezza della stringa, cioè quanti byte contiene. (Per il testo con accenti la faccenda è più sottile: "caffè" ha 6 byte, non 5, perché la è ne occupa due in UTF-8. Ci torneremo; per ora usa .len su testo semplice.)
Dentro le virgolette puoi usare delle sequenze di escape, che iniziano con \:
| Scrivi | Ottieni |
|---|---|
\n | a capo |
\t | tabulazione |
\" | una virgoletta doppia |
\\ | una barra rovesciata |
io::printn("Riga uno\nRiga due");
io::printn("Ha detto: \"ciao\"");Riga uno
Riga due
Ha detto: "ciao"Se gli escape ti danno fastidio (percorsi Windows, espressioni regolari), esistono le stringhe grezze tra apici inversi, dove \ è solo una barra:
String percorso = `C:\Utenti\ada\file.txt`;Un singolo carattere: char
Un carattere tra apici singoli, 'A', è un letterale di tipo char. E come abbiamo detto, char è un numero: 'A' vale 65, secondo la tabella ASCII che assegna un numero a ogni simbolo.
char lettera = 'A';
io::printn(lettera);
io::printfn("%c", lettera);65
ALa seconda riga usa printfn con %c, che dice “trattalo come carattere, non come numero”. Impareremo printfn per bene nella lezione 6; per ora ti basta il concetto: un char è un byte, e come lo stampi dipende da te.
✏️ Quiz
Qual è la differenza tra 'A' e "A"?
Costanti: valori che non cambiano
Alcuni valori non devono mai cambiare durante l’esecuzione: il numero massimo di giocatori, la velocità della luce, l’IVA. Per questi c’è const:
const int MAX_GIOCATORI = 4;
const double IVA = 0.22;
const NOME_GIOCO = "Briscola"; // il tipo si può omettere: lo deduce dal valoreLe costanti si scrivono in MAIUSCOLO_CON_TRATTINI. Non è un vezzo: è una regola del linguaggio, e il compilatore rifiuta const int max = 4;. Il vantaggio è che, leggendo il codice, sai a colpo d’occhio cosa è una costante e cosa no.
Provare a modificarla è un errore di compilazione:
MAX_GIOCATORI = 5; // errore: non puoi assegnare a una costanteLe regole dei nomi
C3 è severo sui nomi, e questa severità è un dono: guardando un nome sai cos’è.
| Cosa | Regola | Esempi validi |
|---|---|---|
| Variabili, funzioni, parametri | Iniziano con minuscola | eta, nome_utente, contaPunti |
Tipi (struct, enum, …) | Iniziano con Maiuscola e contengono almeno una minuscola | Giocatore, String, ListaSpesa |
| Costanti | Tutto MAIUSCOLO | MAX_VITE, PI_GRECO |
| Moduli | Tutto minuscolo, con _ | std::io, mio_gioco |
In tutti i casi: solo lettere a-z, A-Z, cifre 0-9 e _. Niente accenti, niente spazi, e non si può iniziare con una cifra.
Lo stile raccomandato (non obbligatorio, ma usato dalla libreria standard) è snake_case per variabili e funzioni: nome_utente, non nomeUtente. In questo corso seguiamo lo stile della libreria standard.
✏️ Quiz
Quale di queste dichiarazioni non compila?
Una dichiarazione alla volta
Un’ultima differenza dal C, piccola ma che evita malintesi: ogni variabile ha la sua riga.
int a, b = 4; // errore in C3: che valore ha a?int a;
int b = 4; // così è chiaroMettiamo tutto insieme
import std::io;
const int ANNO_CORRENTE = 2026;
fn void main()
{
String nome = "Ada";
int anno_nascita = 1815;
double altezza = 1.65;
bool programmatrice = true;
char iniziale = 'A';
int eta = ANNO_CORRENTE - anno_nascita;
io::printn(nome);
io::printn(eta);
io::printn(altezza);
io::printn(programmatrice);
io::printfn("%c", iniziale);
}Ada
211
1.650000
true
AHai notato 1.650000? Quando stampi un double con printn, C3 usa sei cifre decimali. Nella lezione 6 vedremo come scegliere quante cifre mostrare.
Guarda la riga int eta = ANNO_CORRENTE - anno_nascita;: il valore iniziale di una variabile può essere un calcolo, non solo un numero scritto a mano. È il ponte verso la prossima lezione.
🛠️ Esercizio · sul tuo computer
La tua scheda
Scrivi un programma scheda.c3 con queste variabili, esattamente con questi valori e tipi:
- una
Stringanimalecon valore"Cane"; - un
inteta_canecon valore7; - un
inteta_umanauguale aeta_canemoltiplicato per7(l’operatore è*); - un
boolvaccinatocon valoretrue.
Stampa ognuna delle quattro variabili con io::printn, una per riga, nell’ordine dato. Riporta qui l’output.
🔒 Mostra una soluzione (prima prova da solo!)
import std::io;
fn void main()
{
String animale = "Cane";
int eta_cane = 7;
int eta_umana = eta_cane * 7;
bool vaccinato = true;
io::printn(animale);
io::printn(eta_cane);
io::printn(eta_umana);
io::printn(vaccinato);
}Ricapitolando
- Una variabile è una scatola con un nome, un tipo e un valore:
int eta = 34;. - Le variabili nascono azzerate. Sempre.
- Interi:
int(default),long(grandi),char(un byte senza segno). Decimali:double(default),float. - Da intero a decimale si passa gratis; il contrario richiede un cast
(int). boolètrueofalse.Stringè testo tra virgolette.'A'è unchar, cioè un numero.constper i valori fissi, in MAIUSCOLO.- Nomi: minuscola per variabili e funzioni, Maiuscola per i tipi, MAIUSCOLO per le costanti.
Prossima lezione: facciamo i conti. Somme, divisioni (con una trappola famosa), confronti e le regole di precedenza che C3 ha cambiato rispetto al C.