Linguaggio C (1)
Stefano Petrarca
Conservatorio S. Cecilia - Roma
Altre istruzioni di controllo
- Cicli enumerativi
Nel caso di cicli enumerativi cioè quelli in cui si conosce a priori il numero di ripetizioni, è possibile usare l'istruzione for(<inizializzazione>;<condizione>;<incremento>) che è più compatta ed efficiente rispetto agli altri tipi di ciclo (ad esempio do....while); il primo campo contiene, normalmente, l'inizializzazione dell'indice del ciclo, il secondo la condizione di permanenza nel ciclo, il terzo l'incremento dell'indice. La figura sottostante mostra un esempio relativo all'inizializzazione dei valori di un array.
Ciclo enumerativo | In C usando do ... while(); | In C usando for() |
![]() |
void main() { int i=0, N=10; do { scanf("%d",&x[i]); i++; } while(i< N); } |
void main() { int i, N=10; for(i=0;i< N;i++) { scanf("%d",&x[i]); } } |
Pertanto, in tutti i programmi che prevedono l'elaborazione ciclica di array di dimensione nota è conveniente usare il ciclo for.
- Selezioni multiple
L'istruzione di selezione che già conosciamo permette di creare una diramazione nel flusso del programma in conseguenza della verità o falsità di una proposizione logica. Nel caso in cui vogliamo creare una diramazione con più di 2 bracci in dipendenza dai valori che può assumere una variabile possiamo usare l'istruzione switch(). Ad esempio se vogliamo realizzare un programma che visualizzi un certo messaggio fra 4 disponibili introducendo da input un valore numerico compreso fra 1 e 4, possiamo agire come segue:
Selezione multipla |
In C usando if ... else | In C usando switch() |
int x; scanf("%d",&x); if(x==1) printf("Ciao"); else if(x==2) printf("Hi"); else if(x==3) printf("Bye"); else if(x==4) printf("Ave"); |
.... int x; scanf("%d",&x); switch(x) { case 1: printf("Ciao"); break; case 2: printf("Hi"); break; case 3: printf("Bye"); break; case 4: printf("Ave"); break; } .... |
Dall'esempio possiamo vedere la maggiore concisione e pulizia del codice usando l'istruzione switch() rispetto all'uso di una catena di istruzioni if ... else. Ogni volta che conosciamo a priori tutti i casi possibili associati ad una variabile di controllo possiamo usare tale istruzione. Da notare la complessa sintassi dell'istruzione: ogni gruppo di istruzioni relativo ad ogni caso è indipendente dagli altri casi; inoltre, l'istruzione break (non obbligatoria) che compare alla fine del gruppo associato ad ogni caso serve per saltare tutti gli altri gruppi ed evitare eventuali malfunzionamenti dovuti ad un uso scorretto della variabile di controllo.
- Funzioni
Quando la struttura del programma è molto complessa
conviene suddividere il codice usando i sottoprogrammi. L'uso di questi
ultimi è consigliabile anche quando, all'interno del programma, esistono gruppi identici
di istruzioni ripetuti che eseguono lo stesso compito. Un sottoprogramma è una parte di
codice indipendente che svolge un determinato compito e viene mandato in esecuzione da un programma
chiamante (che, a sua volta, può essere un sottoprogramma). Al termine
dell'esecuzione del sottoprogramma, il controllo ritorna al programma chiamante che
prosegue nel suo lavoro partendo dall'istruzione successiva a quella di chiamata al
sottoprogramma.
All'atto della chiamata a sottoprogramma possono essere passati a questo degli argomenti
all'interno di variabili; queste ultime e quelle che sono dichiarate all'interno del
sottoprogramma, sono dette variabili locali e sono visibili
(cioè possono essere usate) solo all'interno del sottoprogramma. Le variabili
globali, al contrario, sono visibili dappertutto nel programma e sono dichiarate
al di fuori di tutti i moduloi di programma.
Normalmente si fa distinzione fra funzioni e procedure;
un sottoprogramma viene chiamato funzione se, al termine della sua esecuzione,
restituisce un valore al chiamante; viene invece detto procedura se non
restituisce valori. Nel linguaggio C esistono solo funzioni il cui corpo consiste di
moduli di programma separati dal programma principale (il main()); una funzione va definita
in base al tipo del suo valore di ritorno: ci saranno, quindi, funzioni di tipo intero,
floating-point, carattere, etc. che restituiranno rispettivamente un valore intero, reale,
carattere, etc. Una funzione che non restituisce valori (una procedura) va dichiarata di
tipo void.
La definizione ANSI del C richiede, inoltre, che ogni funzione abbia un prototipo
che definisca a priori il tipo del valore di ritorno e il tipo di ogni argomento passato
dal chiamante.
Già conosciamo l'uso delle funzioni; ad esempio, quando scriviamo
#include <stdio.h> void main() { printf("Hello world\n"); }
printf() è una funzione di libreria, cioè una particolare categoria di funzioni fornite insieme al compilatore C e, quindi, sempre disponibili; i loro prototipi sono definiti negli header file che sono anch'essi forniti dai realizzatori del compilatore; ad es., il prototipo di printf() fa parte del file stdio.h. Anche main() stessa va considerata una funzione anche se molto particolare; normalmente è di tipo void e può avere degli argomenti di passaggio; questi ultimi saranno analizzati quando parleremo dei puntatori. Vediamo un esempio di funzione realizzando un programma che permette di visualizzare, a richiesta, una potenza di 2; sarà definita allo scopo una funzione che calcola la potenza n-ma di un numero e sarà chiamata dal main() con gli argomenti introdotti dall'utente tramite la tastiera.
#include <stdio.h> //prototipi delle funzioni di libreria #include <conio.h> // '' double potenza2(int); //prototipo della funzione void main() { int esponente; double p2; char c; printf("Calcolo delle potenze positive e negative di 2\n\n"); do { printf("Introduci l'esponente: "); scanf("%d",&esponente); //input argomento da tastiera p2 = potenza2(esponente); //chiamata della funzione printf("2^%d = %lf\n",esponente,p2); printf("Un'altra potenza?[s/n] "); c = getch(); //attesa di un carattere dalla tastiera } while(c == 's'); //continua a richiedere calcolo se si risponde con il carattere 's' } //intestazione della funzione (i tipi devono corrispondere a quelli del prototipo) double potenza2(int espo) { int i,n; double p = 1; if(espo < 0) n = -espo; else n = espo; for(i=0;i<espo;i++) { p*=2; //calcolo della potenza di 2 } if(espo < 0) p = 1/p; return(p); //istruzione che restituisce il valore calcolato al chiamante }
Da notare l'uso dell'istruzione return alla fine della funzione
per consentire il passaggio del valore di ritorno al chiamante. L'istruzione p*=2 è equivalente a p = p * 2.
L'output del programma sarà il seguente nel caso che venga usato il Visual C++ in
console mode