prof. Nunzio Brugaletta | Programmazione e linguaggio C |
Seguendo il procedimento per scomposizioni successive si arriva alla fine ad un programma principale e ad una serie di sottoprogrammi. Il programma principale chiama in un certo ordine i sottoprogrammi; ogni sottoprogramma oltre che chiamato può anche essere il chiamante di un ulteriore sottoprogramma. Terminato il sottoprogramma l’esecuzione riprende, nel chiamante, dall’istruzione successiva alla chiamata.
Si può dire che tutti i sottoprogrammi fanno parte di un insieme organico: ognuno contribuisce, per la parte di propria competenza, ad una elaborazione finale che è quella fissata dal programma principale. Si tratta in definitiva di un sistema dove l’elaborazione finale richiesta è frutto della cooperazione delle singole parti; ogni sottoprogramma (unità del sistema) riceve i propri input (intesi come somma delle informazioni necessarie all’espletamento delle proprie funzioni) dai sottoprogrammi precedenti, e fornisce i propri output (intesi come somma delle informazioni prodotte al suo interno) ai sottoprogrammi successivi. Per questi ultimi, le informazioni suddette saranno gli input della propria parte di elaborazione.
Quanto detto porterebbe alla conclusione che tutti i sottoprogrammi, facendo parte di un insieme organico, lavorano sulle stesse variabili. D’altra parte se, per esempio, il reparto carrozzeria e il reparto verniciatura operano nella stessa fabbrica di automobili, è ovvio che il reparto verniciatura si occuperà delle stesse carrozzerie prodotte dall’altro reparto. Così in effetti è stato per esempio per i linguaggi di programmazione non strutturati: i sottoprogrammi condividevano le stesse variabili, il sottoprogramma eseguiva una parte limitata di elaborazione ma era fortemente legato al contesto generale. La portabilità di un sottoprogramma, in queste condizioni, è estremamente problematica richiedendo pesanti modifiche al codice stesso (si pensi al fatto che il programma destinazione non usa le stesse variabili del programma che ospitava originariamente il sottoprogramma o, peggio ancora, usa variabili con nomi uguali ma con significati diversi).
Per garantire quanto più possibile la portabilità e l’indipendenza dei sottoprogrammi, i linguaggi strutturati adottano un approccio diverso distinguendo le variabili in base alla visibilità (in inglese scope). In relazione alla visibilità le variabili si dividono in due famiglie principali:
Variabili globali visibili cioè da tutti i sottoprogrammi. Tutti i sottoprogrammi possono utilizzarle e modificarle. Sono praticamente patrimonio comune.
Variabili locali visibili solo dal sottoprogramma che li dichiara. Gli altri sottoprogrammi, anche se chiamati, non hanno accesso a tali variabili. La variabile locale è definita nel sottoprogramma ed è qui utilizzabile. Se viene chiamato un sottoprogramma le variabili del chiamante sono mascherate e riprenderanno ad essere visibili quando il chiamato terminerà e si tornerà al chiamante. L’ambiente del chiamante (l’insieme delle variabili con i rispettivi valori) a questo punto verrà ripristinato esattamente come era prima della chiamata.
Per quanto ribadito più volte sarebbe necessario utilizzare quanto meno possibile (al limite eliminare) le variabili globali per ridurre il più possibile la dipendenza dal contesto da parte del sottoprogramma.
Riguardando però l’elaborazione dati comuni, è necessario che il programma chiamante sia in condizioni di poter comunicare con il chiamato. Devono cioè esistere delle convenzioni di chiamata cioè delle convenzioni che permettono al chiamante di comunicare dei parametri che rappresenteranno gli input sui quali opererà il chiamato. D’altra parte il chiamato avrà necessità di tornare al chiamante dei parametri che conterranno i risultati della propria elaborazione e che potranno essere gestiti successivamente. Queste convenzioni sono generalmente conosciute come passaggio di parametri.
Il passaggio di parametri può avvenire secondo due modalità:
Si dice che un parametro è passato per valore (dal chiamante al chiamato) se il chiamante comunica al chiamato il valore che è contenuto in quel momento in una sua variabile. Il chiamato predisporrà una propria variabile locale che conterrà tale valore. Il chiamato può operare su tale valore, può anche modificarlo ma tali modifiche riguarderanno solo la copia locale su cui sta lavorando. Terminato il sottoprogramma la variabile locale scompare assieme al valore che contiene e viene ripristinata la variabile del chiamante con il valore che essa conteneva prima della chiamata al sottoprogramma.
Si dice che un parametro è passato per riferimento o per indirizzo se il chiamante comunica al chiamato l’indirizzo di memoria di una determinata variabile. Il chiamato può utilizzare, per la variabile, un nome diverso ma le locazioni di memoria a cui ci si riferisce sono sempre le stesse. Viene semplicemente stabilito un riferimento diverso alle stesse posizioni di memoria: ogni modifica effettuata si ripercuoterà sulla variabile originaria anche se il nuovo nome cessa di esistere alla conclusione del sottoprogramma.
Per sintetizzare praticamente su cosa passare per valore e cosa per riferimento, si può affermare che gli input di un sottoprogramma sono passati per valore mentre gli output sono passati per riferimento. Gli input di un sottoprogramma sono utili allo stesso per compiere le proprie elaborazioni mentre gli output sono i prodotti della propria elaborazione che devono essere resi disponibili ai sottoprogrammi successivi.
http://ennebi.solira.org | ennebi@solira.org |