Menu

Variabili in C: dichiarare, inizializzare e assegnare

Come dichiarare una variabile in C, la differenza tra dichiarazione e inizializzazione, le regole per i nomi, dichiararne più di una alla volta e perché una variabile non inizializzata è il bug più comune tra i principianti.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

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: total2 va bene, 2total no.
  • Non può essere una parola chiave di C: nessuna variabile chiamata int, return, for o double.
  • Case sensitive: count, Count e COUNT sono 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.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA