Informatica 7 Sottoprogrammi: funzioni e procedure Definizione di sottoprogramma • Sappiamo che un programma è un algoritmo scritto in un linguaggio comprensibile al calcolatore • Un algoritmo è una sequenza finita e deterministica di istruzioni per risolvere un problema • Un problema può essere talvolta scomposto in parti, chiamate sottoproblemi, che possono essere risolte in maniera indipendente per ottenere una soluzione al problema di partenza • Se un programma è suddiviso in diverse parti, ognuna delle quali risolve un sottoproblema, allora ciascuna parte è chiamata sottoprogramma se esplicitamente separata dalle altre Esempio: calcolo della media • Problema: chiedere all’utente 3 interi, calcolarne la media aritmetica, e stamparla su schermo • Il problema può essere scomposto nei seguenti sottoproblemi: – richiesta numeri – calcolo media – stampa del risultato Funzioni e procedure • Un sottoprogramma è un algoritmo per la soluzione di un sottoproblema scritto in un linguaggio di programmazione • Sottoprogrammi che restituiscono un risultato parziale tramite l’istruzione return prendono il nome di funzioni • Sottoprogrammi che prevedono solo l’esecuzione di un blocco di istruzioni senza l’esplicita restituzione di un risultato si chiamano procedure Funzioni e procedure per il calcolo della media • Modelliamo come funzione il sottoprogramma per: – calcolo media • Risolviamo il seguente sottoproblema per mezzo di una procedura: – stampa del risultato • La scrittura di questi sottoprogrammi in riferimento allo stesso programma principale (main) riflette il fatto che essi sono parte della soluzione a un unico problema nome della funzione Funzione: esempio float media (int a, int b, int c){ int somma = a + b + c; float risultato = somma/3; return risultato; } tipo del risultato restituito fine del blocco di istruzioni della funzione inizio del blocco di istruzioni della funzione lista dei tipi e dei nomi dei parametri formali istruzione return con cui si conclude l’esecuzione della funzione e si restituisce il risultato Procedura: esempio void stampa(int m){ cout << “La media è: ” << m << “\n”; } non c’è alcun risultato restituito dal sottoprogramma, quindi il tipo del risultato è void (vuoto) non c’è alcun risultato da restituire, e infatti il blocco di istruzioni non include una istruzione return Uso della funzione e della procedura nel programma finale … float media (int a, int b, int c){ int somma = a + b + c; float risultato = somma/3; return risultato; } void stampa(int m){ cout << “La media è: ” << m << “\n”; } int main(){ int x,y,z; float r; cout << “inserisci 3 numeri:\n”; cin >> x >> y >> z; r = media(x,y,z); stampa(r); … } il risultato restituito dalla funzione va salvato in una variabile l’esecuzione di una procedura, invece, non prevede alcun risultato se non l’effetto delle istruzioni che la compongono Passaggio dei parametri • Nell’esempio precedente, a, b, e c sono i parametri formali della funzione media, a cui, al momento della chiamata della funzione nel main, vengono associati i valori dei parametri attuali x, y, e z • Tale corrispondenza è posizionale: ad a viene associato il valore di x perché sono entrambi i primi della lista, e così via Passaggio di parametri per valore • Il passaggio del valore di x ad a consiste, di fatto, nella creazione di una variabile temporanea con lo stesso valore di x che viene usata nelle istruzioni della funzione al posto di a • Per tutta l’esecuzione della funzione, la variabile x, quindi, non viene minimamente modificata: al termine della funzione sarà rimasta come prima Possibile problema • A volte, il fatto che un parametro attuale non subisca modifiche da parte della funzione può non essere ciò che desideriamo • Ad es: void azzera (int n){ n = 0; } int main(){ … azzera(x); /* x rimane uguale e non viene azzerato*/ … Passaggio di parametri per indirizzo • Si ha questo tipo di passaggio quando alla funzione non è fornita una copia del valore del parametro attuale (come nel passaggio per valore) bensì l’indirizzo della cella di memoria contenente il parametro attuale • In questo modo, la funzione non esegue le sue istruzioni su una copia, ma direttamente sul parametro attuale, cosicché ogni modifica del suo valore ha effetto Esempio void azzera (int& n){ n = 0; } int main(){ … azzera(x); cout << x; … il simbolo & indica che il passaggio del parametro è per indirizzo questa volta la variabile x è veramente azzerata e su schermo compare ‘0’ Passaggio di parametri strutturati • Attenzione: nel linguaggio C++, se un parametro è un dato strutturato, viene sempre passato per indirizzo, per risparmiare la memoria che verrebbe occupata da una copia del parametro attuale • Data questa regola, nella scrittura della lista dei parametri formali di un sottoprogramma si omette il simbolo ‘&’ Array come parametri • In particolare, quando un array viene passato come parametro, l’informazione che il sottoprogramma riceve è solo l’indirizzo della prima cella dell’array • Sarà cura del programmatore aggiungere un altro parametro che indichi la dimensione dell’array in modo che il sottoprogramma possa eseguire le istruzioni sull’array in maniera corretta Esempio int somma_valori (int v[], int dim){ int i; int somma = 0; viene segnalato che il for (i = 0; i < dim; i++) parametro è un array, somma = somma + v[i]; ma la sua dimensione è return somma; un parametro separato } int main(){ int vettore[10]; int s; … s = somma_valori(vettore, 10); cout << “la somma dei valori dell’array e’: ” << s << “\n”; … } nel parametro attuale, solo il nome dell’array viene specificato