Una variabile è un pezzo di memoria con un nome che contiene un valore che il tuo programma può leggere e modificare. In C dichiari sempre in anticipo che tipo di valore contiene, e questa scelta resta valida per tutta la vita della variabile.
Dichiarare una variabile
La forma è tipo, nome, punto e virgola:
int age;
double price;
char grade;
Ogni riga riserva abbastanza memoria per quel tipo di dato e le associa un nome. Non è ancora stato salvato niente: lo spazio esiste, ma il suo contenuto è quello che ci ha lasciato il codice eseguito in precedenza.
Puoi assegnare un valore nello stesso momento, e questo si chiama inizializzazione:
Nota gli specificatori di formato: %d per int, %f per double, %c per char. printf non ispeziona i valori che riceve: si fida della tua stringa di formato, quindi una discrepanza stampa valori senza senso invece di un errore.
Assegnazione dopo la dichiarazione
Una volta che una variabile esiste, la modifichi con =:
In C = è assegnazione, non uguaglianza. score = score + 10 si legge come "prendi quello che c'è in score, aggiungi 10 e rimetti il risultato in score". L'operatore di confronto è ==, e confonderli è un bug così comune da avere una sezione tutta sua nella pagina sui booleani.
La forma abbreviata score += 10 fa la stessa cosa con meno caratteri; gli operatori di assegnazione composta coprono tutta l'aritmetica.
La trappola della variabile non inizializzata
Questo è il bug più comune in assoluto tra chi inizia con C, e non produce alcun errore:
Eseguilo. Potresti vedere 15, che è la risposta giusta. Potresti vedere un enorme numero casuale. Potresti vedere qualcosa di diverso a una seconda esecuzione o su un'altra macchina. Sono tutti comportamenti "corretti", perché leggere una variabile locale non inizializzata è comportamento indefinito: lo standard C non impone alcun requisito su ciò che succede.
A differenza di molti linguaggi, C non azzera le tue variabili locali. Una variabile locale è una porzione dello stack, e lo stack è pieno di avanzi delle chiamate a funzione precedenti. A volte quegli avanzi sono proprio zero, ed è questo che rende il bug così pericoloso: spesso funziona nei test e si rompe in produzione.
La correzione è di pochi caratteri:
Fanne un'abitudine: inizializza ogni variabile nel punto in cui la dichiari. Se davvero non hai ancora un valore sensato, 0 o NULL sono meglio della spazzatura. E compila con -Wall, che intercetta la maggior parte dei casi:
warning: 'total' is used uninitialized in this function
Le variabili globali e static sono l'eccezione: loro vengono inizializzate a zero automaticamente. Contarci va bene, ma scrivere comunque = 0 rende esplicita la tua intenzione.
Dichiararne più di una alla volta
Variabili dello stesso tipo possono condividere una dichiarazione, con o senza inizializzatori:
È legale e comune per valori strettamente collegati come x, y, z. Ma è anche lì che si nasconde un classico errore di lettura:
int a = 0, b = 0, c = 0; /* tutte e tre valgono 0 */
int d, e, f = 0; /* solo f vale 0: d ed e sono spazzatura */
L'inizializzatore si lega a un nome, non alla riga. Quando i valori hanno significati diversi, dai a ciascuno la sua riga: si legge meglio e produce diff più puliti.
Dichiarare dei puntatori sulla stessa riga nasconde la stessa trappola in forma ancora più insidiosa:
int *p, q; /* p è un puntatore a int; q è un semplice int */
L'* si lega al nome, non al tipo. Dichiara i puntatori uno per riga.
Regole e convenzioni per i nomi
Le regole del compilatore:
- Solo lettere, cifre e underscore.
- Non può iniziare con una cifra:
total2va bene,2totalno. - Non può essere una parola chiave di C: nessuna variabile chiamata
int,return,forodouble. - Case sensitive:
count,CounteCOUNTsono tre variabili distinte. - I nomi che iniziano con un underscore, o che contengono un doppio underscore, sono riservati all'implementazione. Non crearli.
int itemCount; /* legale */
int item_count; /* legale: lo stile abituale in C */
int _count; /* legale ma riservato: evitalo */
int item-count; /* errore: '-' è l'operatore di sottrazione */
int 3rd_place; /* errore: inizia con una cifra */
int float; /* errore: parola chiave */
Le convenzioni seguite dalla maggior parte del codice C: snake_case per variabili e funzioni, MAIUSCOLO per le costanti definite come macro, e nomi che dicono cosa significa il valore invece che di che tipo è. elapsed_ms è meglio di t; customer_count è meglio di n2.
I nomi brevi vanno comunque bene quando lo scope è minuscolo: i come contatore di un ciclo lo capiscono tutti, e nessuno vuole scrivere for (int indice_di_iterazione_del_ciclo = 0; ...).
Dove vive una variabile
Il punto in cui dichiari una variabile determina chi può vederla e quanto a lungo esiste. Questo è lo scope, e in breve funziona così:
Una variabile è visibile dalla sua dichiarazione fino alla graffa di chiusura del blocco che la contiene. Le globali vivono per tutta la durata del programma e sono visibili ovunque, il che sembra comodo ed è proprio il motivo per cui creano problemi: qualsiasi funzione può modificarle, quindi scoprire chi l'ha fatto diventa una ricerca nell'intero file. Preferisci le variabili locali e passa i valori alle funzioni come parametri.
Dichiarare ovunque (C99 e successivi)
Nel C89 originale ogni dichiarazione doveva precedere qualsiasi istruzione del blocco:
int main(void) {
int i, sum = 0; /* prima tutte le dichiarazioni */
printf("Inizio\n");
for (i = 0; i < 10; i++) { sum += i; }
return 0;
}
Dal C99 puoi dichiarare una variabile dove ti serve per la prima volta, anche nell'intestazione del for:
È uno stile migliore: la dichiarazione sta accanto al primo utilizzo, e i non può trapelare nel resto della funzione. Compila con -std=c17 (o qualsiasi impostazione da C99 in poi) e funziona ovunque.
Domande frequenti
Come si dichiara una variabile in C?
Scrivi il tipo, poi il nome, poi un punto e virgola: int age;. Puoi assegnarle un valore nello stesso momento, int age = 30;: si chiama inizializzazione ed è quasi sempre quello che vuoi.
Qual è la differenza tra dichiarare e inizializzare una variabile?
Dichiarare riserva lo spazio e gli dà un nome (int count;). Inizializzare ci mette dentro un valore nel momento in cui viene creata (int count = 0;). Una variabile locale dichiarata ma non inizializzata contiene i byte che si trovavano già a quell'indirizzo: leggerla è comportamento indefinito.
Quali sono le regole per i nomi delle variabili in C?
Solo lettere, cifre e underscore; non può iniziare con una cifra; non può essere una parola chiave come int o for; ed è case sensitive, quindi total e Total sono variabili diverse. I nomi che iniziano con un underscore sono riservati: evitali.
Si possono dichiarare variabili in qualsiasi punto di una funzione C?
Dal C99 sì: dichiara ogni variabile proprio dove ti serve per la prima volta. Nello standard originale C89 ogni dichiarazione doveva stare all'inizio di un blocco, ed è per questo che il codice più vecchio ha un muro di dichiarazioni prima di qualsiasi lavoro vero.