Perché dobbiamo inizializzare una variabile prima di usarla?

Possibile duplicato:
Cosa succede a una variabile dichiarata, non inizializzata in C? Ha un valore?

Ora sto leggendo Teach Yourself C in 21 Days . Nel capitolo 3, c’è una nota come questa:

NON usare una variabile che non è stata inizializzata. I risultati possono essere imprevedibili.

Per favore, spiegami perché questo è il caso. Il libro non fornisce ulteriori chiarimenti a riguardo.

Quando una variabile viene dichiarata, punta a un pezzo di memoria.

Accedere al valore della variabile ti darà il contenuto di quel pezzo di memoria.

Tuttavia, finché la variabile non viene inizializzata, quel pezzo di memoria potrebbe contenere qualsiasi cosa. Questo è il motivo per cui l’uso è imprevedibile.

Altre lingue possono aiutarti in quest’area inizializzando automaticamente le variabili quando le assegni, ma come programmatore C stai lavorando con un linguaggio di basso livello che non fa ipotesi su cosa vuoi fare con il tuo programma. Tu come programmatore devi dire esplicitamente al programma di fare tutto.

Ciò significa inizializzare le variabili, ma significa anche molto di più. Ad esempio, in C devi stare molto attento a deselezionare tutte le risorse assegnate una volta che hai finito con esse. Altre lingue si ripuliranno automaticamente dopo che avrai finito il programma; ma in C se si dimentica, si finisce con perdite di memoria.

C ti permetterà di ottenere molte cose che sarebbero difficili o impossibili in altre lingue. Ma questo potere significa anche che devi assumerti la responsabilità per i compiti di pulizia che tu dai per scontato in quelle altre lingue.

Perché, a meno che la variabile non disponga di spazio di archiviazione statico, il suo valore iniziale è indeterminato. Non puoi fare affidamento sul fatto che sia qualcosa in quanto lo standard non lo definisce. Anche le variabili allocate staticamente dovrebbero essere inizializzate. Basta inizializzare le variabili ed evitare un potenziale mal di testa in futuro. Non c’è una buona ragione per non inizializzare una variabile, molte buone ragioni per fare il contrario.

Una nota a margine, non fidarti di nessun libro che afferma di insegnarti il ​​linguaggio di programmazione X in 21 giorni. Stanno mentendo, prenditi un libro decente.

Si potrebbe finire per utilizzare una variabile dichiarata al di fuori dell’ambito del metodo corrente.

Considera quanto segue

 int count = 0; while(count < 500) { doFunction(); count ++; } ... void doFunction() { count = sizeof(someString); print(count); } 

In C, utilizzando i valori delle variabili automatiche non inizializzate (locals non parametrici e variabili di parametro) che soddisfano il requisito di essere una variabile di register è un comportamento indefinito, poiché tali valori di variabili possono essere stati recuperati da un registro e alcune piattaforms possono interrompere il programma se leggi questi valori non inizializzati. Questo include variabili di tipo unsigned char (questo è stato aggiunto a una specifica C successiva, per ospitare queste piattaforms).

L’uso di valori di variabili automatiche non inizializzate che non soddisfano il requisito di essere una variabile di register , come le variabili che hanno gli indirizzi presi, va bene finché l’implementazione C che usi non ha rappresentazioni di trap per il tipo di variabile che usi. Ad esempio, se il tipo di variabile è unsigned char , lo standard richiede che tutte le piattaforms non presentino rappresentazioni di trap memorizzate in tali variabili e una lettura di un valore indeterminato da esso avrà sempre esito positivo e non è un comportamento non definito. Tipi come int o short non hanno tali garanzie, quindi il tuo programma potrebbe bloccarsi, a seconda dell’implementazione C che usi.

Le variabili di durata di archiviazione statica sono sempre inizializzate se non lo fai esplicitamente, quindi non devi preoccuparti qui.

Per le variabili della durata di archiviazione allocata ( malloc …), lo stesso vale per le variabili automatiche che non soddisfano i requisiti per essere una variabile di register , perché in questi casi le implementazioni C interessate devono rendere il programma letto dalla memoria, e non si imbatterà nei problemi in cui la lettura dei registri può sollevare eccezioni.

In C il valore di una variabile non inizializzata è indeterminato. Ciò significa che non si conosce il suo valore e che può variare a seconda della piattaforma e del compilatore. Lo stesso vale anche per composti come struct e union types.

Perché? A volte non è necessario inizializzare una variabile mentre la si passa a una funzione che la riempie e che non interessa ciò che è nella variabile. Non vuoi che il sovraccarico dell’inizializzazione ti sia imposto.

Come? I tipi primitivi possono essere inizializzati da valori letterali o valori restituiti dalla funzione.

 int i = 0; int j = foo(); 

Le strutture possono essere inizializzate a zero con la syntax dell’intializzatore aggregato:

 struct Foo { int i; int j; } struct Foo f = {0}; 

A rischio di essere pedante, la dichiarazione

NON usare una variabile che non è stata inizializzata.

non è corretto. Se fosse meglio express:

Non utilizzare il valore di una variabile non inizializzata.

Il linguaggio distingue tra inizializzazione e assegnazione , quindi il primo avviso è, in questo senso, cauto: non è necessario fornire un inizializzatore per ogni variabile, ma è necessario assegnare o inizializzare una variabile con un valore utile e significativo prima di eseguire qualsiasi operazioni che successivamente utilizzano il suo valore.

Quindi quanto segue va bene:

 int i ; // uninitialised variable i = some_function() ; // variable is "used" in left of assignment expression. some_other_function( i ) ; // value of variable is used 

anche se quando si chiama some_function () i non è inizializzato. Se stai assegnando una variabile, la stai sicuramente “usando” (per memorizzare il valore restituito in questo caso); il fatto che non sia inizializzato è irrilevante perché non stai usando il suo valore.

Ora se ti aderisci

Non utilizzare il valore di una variabile non inizializzata.

come ho suggerito, la ragione di questo requisito diventa ovvia: perché dovresti prendere il valore di una variabile senza sapere che contiene qualcosa di significativo? Una domanda valida potrebbe quindi essere “perché C non inizializza le variabili auto con un valore noto e le possibili risposte potrebbero essere:

  • Qualsiasi valore fornito dal compilatore arbitrario non deve essere significativo nel contesto dell’applicazione o, peggio, può avere un significato contrario allo stato reale dell’applicazione.

  • C è stato appositamente progettato per non avere overhead nascosti a causa delle sue radici come linguaggio di programmazione dei sistemi: l’inizializzazione viene eseguita solo se esplicitamente codificata, poiché richiede ulteriori istruzioni della macchina e cicli della CPU da eseguire.

Si noti che static variabili static sono sempre inizializzate a zero. I linguaggi .NET, come C #, hanno il concetto di valore nullo o una variabile che non contiene nulla e che può essere esplicitamente testato e persino assegnato. Una variabile in C non può contenere nulla , ma ciò che contiene può essere indeterminato, e quindi il codice che usa il suo valore si comporterà non deterministicamente.