Barninga Z
a- a+

Il flusso elaborativo: for

for

Tra le istruzioni C di controllo dei ciclo, la for è sicuramente la più versatile ed efficiente. La for è presente in tutti (o quasi) i linguaggi, ma in nessuno ha la potenza di cui dispone in C. Infatti, in generale, i cicli di tipo while e derivati sono utilizzati nelle situazioni in cui non è possibile conoscere a priori il numero esatto di iterazioni, mentre la for, grazie alla sua logica "punto di partenza; limite; passo d'incremento" , si presta proprio ai casi in cui si può determinare in partenza il numero di cicli da compiere. 

Nella for del C è ancora valida la logica a tre coordinate, ma, a differenza della quasi totalità dei linguaggi di programmazione, esse sono reciprocamente svincolate e non necessarie. Ciò significa che, se in Basic[5] la for agisce su un'unica variabile, che viene inizializzata e incrementata (o decrementata) sino al raggiungimento di un limite prestabilito, in C essa può manipolare, ad esempio, tre diverse variabili (o meglio, tre espressioni di diverso tipo); inoltre nessuna delle tre espressioni deve necessariamente essere specificata: è perfettamente lecita una for priva di condizioni di iterazione. 

A questo punto, tanto vale esaurire le banalità formali, per concentrarsi poi sulle possibili modalità di definizione delle tre condizioni che pilotano il ciclo. Sia subito detto, dunque, che anche la for vuole che le condizioni siano specificate tra parentesi tonde e che se il blocco di codice del ciclo comprende più di una istruzione sono necessarie le solite graffe, aperta e chiusa. Anche nei cicli for possiamo utilizzare le istruzioni break e continue: la prima per "saltar fuori" dal ciclo; la seconda per tornare "a bomba" alla valutazione del test. Anche i cicli for possono essere annidati, e va tenuto presente che il ciclo più interno compie una serie completa di iterazioni ad ogni iterazione di quello che immediatamente lo contiene. 

E vediamo, finalmente, qualche ciclo for dal vivo: nella sua forma banale, quasi "Basic­istica" , può assumere il seguente aspetto: 

for(i = 1; i < k; i++) {
        ....
    }

Nulla di particolare. Prima di effettuare la prima iterazione, la variabile i è inizializzata a 1. Se essa risulta minore della variabile k il ciclo è eseguito una prima volta. Al termine di ogni iterazione essa è incrementata e successivamente confrontata con la k; se risulta minore di quest'ultima il ciclo è ripetuto. 

Vale la pena di evidenziare che le tre coordinate logiche stanno tutte quante all'interno delle parentesi tonde e sono separate tra loro dal punto e virgola (";"); solo la sequenza (;;) deve obbligatoriamente essere presente in un ciclo for

In effetti possiamo avere una for come la seguente: 

for( ; ; ) {
        ....
    }

Qual è il suo significato? Nulla è inizializzato. Non viene effettuato alcun test. Non viene modificato nulla. Il segreto consiste nel fatto che l'assenza di test equivale a condizione sempre verificata: la for dell'esempio definisce quindi un'iterazione infinita. Il programma rimane intrappolato nel ciclo finché si verifica una condizione che gli consenta di abbandonarlo in altro modo, ad esempio con l'aiuto di una break

Ma si può fare di meglio... 

for(i = 0; string[i]; )
        ++i;

Il ciclo dell'esempio calcola la lunghezza della stringa (terminatore nullo escluso). Infatti i è inizializzata a 0 e viene valutato se il carattere ad offset 0 in string è nullo; se non lo è viene eseguita l'unica istruzione del ciclo, che consiste nell'incrementare i. A questo punto è valutato se è nullo il byte ad offset 1 in string, e così iterando finché string[i] non è proprio il NULL finale. L'esempio appena presentato è del tutto equivalente a 

for(i = 0; string[i]; i++);

Il punto e virgola che segue la parentesi tonda indica che non vi sono istruzioni nel ciclo. Le sole cose da fare sono, perciò, la valutazione della condizione e l'incremento di i finché, come nel caso precedente, string[i] non punta al NULL che chiude la stringa. Se poi volessimo includere nel calcolo anche il NULL, ecco come fare: 

for(i = 0; string[i++]; );

Sissignori, tutto qui. Anche questo ciclo non contiene alcuna istruzione; tuttavia, in questo caso, l'incremento di i fa parte della condizione e (trattandosi di un postincremento) viene effettuato dopo la valutazione, quindi anche (per l'ultima volta) quando string[i] punta al NULL. E che dire della prossima? 

for( ; *string++; ) {
        ....
    }

Nulla di particolare, in fondo: viene verificato se *string è un byte non nullo e string è incrementato. Se la verifica dà esito positivo viene eseguito il codice del ciclo. Viene poi nuovamente effettuata la verifica, seguita a ruota dall'incremento, e così via. Quanti si sono accorti che questo ciclo for è assolutamente equivalente a un ciclo while? Eccolo: 

while(*string++) {
        ....
    }

In effetti si potrebbe dire che l'istruzione while, in C, è assolutamente inutile, in quanto può essere sempre sostituita dalla for, la quale, anzi, consente generalmente di ottenere una codifica più compatta ed efficiente dell'algoritmo. La maggiore compattezza deriva dalla possibilità di utilizzare contestualmente alla condizione, se necessario, anche un'istruzione di inizializzazione ed una di variazione. La maggiore efficienza invece dipende dal comportamento tecnico del compilatore, il quale, se possibile, gestisce automaticamente i contatori dei cicli for come variabili register

Gli esempi potrebbero continuare all'infinito, ma quelli presentati dovrebbero essere sufficienti per evidenziare, almeno a grandi linee, le caratteristiche salienti dei cicli definiti mediante l'istruzione for. E' forse il caso di sottolineare ancora una volta che il contenuto delle parentesi tonde dipende fortemente dal ciclo che si vuole eseguire e dall'assetto elaborativo che gli si vuole dare, ma l'uso dei due punto e virgola è obbligatorio. Il primo e l'ultimo parametro non devono essere necessariamente inizializzare ed incrementare (o decrementare) il contatore (o il medesimo contatore), così come il parametro intermedio non deve per forza essere una condizione da valutare. Ciascuno di questi parametri può essere una qualunque istruzione C o può venire omesso. Il compilatore, però, interpreta sempre il parametro di mezzo come una condizione da verificare, indipendentemente da ciò che è in realtà: detto parametro è quindi sempre valutato come vero o falso[6], e da esso dipendono l'ingresso nel ciclo e le successive iterazioni.

 



Ti potrebbe interessare anche

commenta la notizia

C'è 1 commento
Marcello
Ti è piaciuto l'articolo?