Programmazione modulare
In genere i programmi sono scomponibili in diversi sottoprogrammi; ad es. acquisire i dati, eleborarli, stamparli: sono tre fasi e ad ognuna corrisponde un algoritmo. Per l'implementazione di tali software sono possibili due approcci:
Top-down: inizialmente si individuano la fasi principali e ad ognuna di queste si associa una funzione inizialmente vuota; ogni fase si scompone in ulteriori fasi sempre più piccole (rappresentate da ulteriori funzioni ) fino a quando si arriva ad algoritmi cosi' semplici da essere risolti direttamente.
Bottom-up: inizialmente si individuano e realizzano le operazioni semplici; quindi tali operazioni sono combinate per risolvere il programma totale.
Si tratta di metodologie diverse ed è preferibile la prima. Infatti i programmi risultano più leggibili, si evita la ripetizione di codice, le funzioni si possono usare come “mattoni” per costruire nuovi programmi o impostare il programma diversamente. Aumenta il livello di astrazione del sw, che nasconde i dettagli interni e privilegia l'impostazione globale
Funzioni
Una funzione è un sottoprogramma: è un insieme di istruzioni che esegue un compito specifico, ricevendo e restituendo dati al programma (o funzione) chiamante, senza interferire con altre parti del programma stesso (indipendenza).
Una funzione è identificata con un nome che può essere inserito in qualunque parte del programma: chiamata della funzione.
Ad una funzione sono associabili degli argomenti: sono i dati che il programma chiamante fornisce alla funzione;
Ritorno valore: una funzione può restituire un solo valore;
main(): anche il main è una funzione, la funzione principale che dà inizio all’esecuzione del programma.
libreria: insieme di funzioni, raccolte in un file, di cui in genere si conosce il comportamento ma spesso non il codice interno. Ad es. cin, cout;
Dichiarazione
La funzione, prima della chiamata, deve essere dichiarata in modo tale che il compilatore la possa riconoscere; la sua sintassi è :
<tipo valore restituito> <nome funzione> ( tipo_par1, tipo_par2,...);
questa viene chiamata intestazione o prototipo della funzione.
Es: int massimo(int, int, int); si osserva che, in questa fase, non è necessario associare al tipo di parametro il relativo nome
Definizione
L'insieme delle istruzioni, corpo della funzione, in genere si definisce dopo la chiusura del main, ripetendo il prototipo senza il ; terminatore:
<tipo valore restituito> <nome funzione> ( tipo_p1 nome_p1, tipo_p2 nome_p2,...)
{
istruzioni;
}
All'interno delle parentesi tonde si elencano i dati passati alla funzione dal programma chiamante: gli argomenti completi di tipo e identificatore.
Il numero, il tipo e l’ordine degli argomenti devono coincidere con quelli del prototipo.
Un argomento può essere una qualsiasi espressione del C: una costante, una variabile, un’espressione logica o aritmetica o un’altra funzione (che restituisca un valore).
Se <tipo valore restituito> è void la funzione non restituirà alcun valore e quindi semplicemente eseguirà solo delle istruzioni.
Controllo esecuzione: istruzione return
Restituisce il controllo dell' esecuzione al programma chiamante. Quando un programma chiama una funzione, l'esecuzione delle istruzioni del programma chiamante viene interrotta, si eseguono le istruzioni della funzione e al termine, alla chiusura della parentesi graffa del corpo della funzione o all'esecuzione dell'istruzione return, si riprende con le istruzioni del programma chiamante dal punto precedentemente interrotto;
Se la funzione restituisce un risultato è necessario associare all'istruzione return il valore restituito: return(espressione); in tal caso la funzione coincide con il valore restituito:
int a, b;
int funz( char, int);
…
b=100;
a=funz('a', b);
Una funzione può contenere al suo interno più punti di uscita, ossia più istruzioni return.
Chiamata per valore e per riferimento.
Gli argomenti di una funzione possono essere:
la copia del valore di una variabile del programma chiamante; si parla di chiamata per valore; le modifiche effettuate alla copia all’interno della funzione non interesseranno il valore del programma chiamante. In tal modo si evitano modifiche accidentali.
La variabile effettiva del programma chiamante: si parla di chiamata per riferimento; le modifiche effettuate all’interno della funzione si rifletteranno sulla variabile del programma chiamante.
In C tutte le chiamate sono per valore; è possibile tuttavia simulare la chiamata per riferimento usando i puntatori ( argomento successivo)
Una funzione può richiamare un’altra funzione e il livello di profondità di chiamata dipende dal processore. Una funzione può richiamare se’ stessa (ricorsione).
Visibilità delle variabili.
In generale ogni variabile esiste fino al termine dell'ambiente in cui è stata definita: file (valida per tutte le funzioni), funzione (nel corpo della funzione), blocco (all'interno delle parentesi graffe che definiscono il blocco).
Variabili locali: sono variabili disponibili solo all'interno della funzione in cui sono state dichiarate (nel corpo o nell'intestazione di definizione): nascono e muoiono con la funzione. In tal modo si riduce la memoria occupata, ma aumenta il tempo di elaborazione. Sono distinte da eventuali altre variabili con lo stesso nome dichiarate fuori dalla funzione. Non è opportuno usare nomi uguali per variabili con campi di visibilità diversi.
Variabili globali: le variabili definite all'esterno di tutte le funzioni, compreso il main, sono visibili a tutte le funzioni definite nel file; per mantenere l'indipendenza e la generalità della funzione non è opportuno usare variabili globali tranne nel caso di variabili onerose in termini di occupazione di memoria.