Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D Le Miniguide all'orientamento Gli eBook di Federica La Corte in Rete
 
I corsi di Scienze Matematiche Fisiche e Naturali
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Silvia Rossi » 10.Astrazione procedurale: Procedure e Funzioni -parte seconda


C++ funzioni → dichiarazione

La dichiarazione di una funzione (prototipo) ha la sintassi:

tipo nome (argomenti);

Dove:

  • tipo, nome, argomentihanno lo stesso significato della sintassi delle definizione
    • La dichiarazione è formalmente identica alla prima riga della definizione di funzione, salvo il fatto che deve terminare con un punto e virgola
  • i nomi degli argomenti sono fittizi e opzionali (non devono coincidere con quelli dalla definizione); i tipi sono obbligatori (devono coincidere nello stesso ordine con quelli della definizione)

Esempio:

char MiaFunz(int dato, float valore);
char MiaFunz(int, float);

Se in un file di codice sorgente una funzione é chiamata prima di essere definita, bisogna dichiararla prima di chiamarla.

C++ funzioni → osservazioni

Nello sviluppo di librerie di funzioni è molto utile l’uso delle dichiarazioni di funzioni

  • Come default il corpo di una funzione può invocare solo le funzioni definite prima
  • A priori non si sa la sequenza di chiamate di funzioni
  • Anteponendo le dichiarazioni a iniziodel file, tutte le altre

C++ funzioni → argomenti

Gli argomenti di una funzione (o procedura) possono essere:

  • di input, cioè i dati passati alla funzione perché essa possa effettuare calcoli
  • di output, cioè le variabili non inizializzate passate alla funzione che assumeranno un valore al termine della funzione (procedura)
  • di input-output, cioè le variabili passate alla funzione che hanno un loro valore prima della chiamata della procedura e che al termine della procedura possono assumere un valore diverso

C++ funzioni → argomenti

Problema: Calcolare la somma di due frazioni n1/d1, n2/d2 e ridurla ai minimi termini.

Primo raffinamento:
leggi(n1,d1,n2,d2)
calcola il numeratore, num, ed il denominatore, den, della somma
riduci num e den ai minimi termini
stampa(num e den)

I quattro numeri in input non possono essere quattro interi qualsiasi perché un denominatore non può mai essere zero.
Quindi precondizioni: d1≠0 e d2≠0
Per ridurre num e den ai minimi termini dobbiamo prima trovare il massimo comun divisore k, e successivamente effettuare le operazioni num←num/k, den←den/k.

C++ funzioni → argomenti

Nella procedura leggi i quattro parametri della procedura sono tutti di output.

Nella procedura calcolasomma gli stessi sono invece parametri di input mentre num e den sono parametri di output.

Nella procedura riduci num e den sono parametri di input-output.

Nella procedura stampa sono parametri di input.

C++ funzioni → argomenti


C++ funzioni → argomenti


C++ funzioni → argomenti

Nella funzione mcd le variabili a,b si riferiscono al loro valore (right value), mentre nella funzione riduci le variabili num e den al loro indirizzo (left value).

C++ funzioni → argomenti

Interfacciamento: l’insieme di operazioni che occorre fare per rendere possibili le due fasi dell’invocazione di funzione

1. chiamata della funzione: passaggio di parametri dalla funzione chiamante alla funzione chiamata (come suoi argomenti)
controllo dalla funzione chiamante alla funzione chiamata

2. ritorno della funzione: passaggio di valore di ritorno della funzione chiamata alla funzione chiamante
controllo dalla funzione chiamata (al suo termine) alla funzione chiamante


C++ funzioni → argomenti

Record di Attivazione

La memoria effettivamente usata dal programma a runtime è organizzata come una pila o stack.

Inizialmente una certa area di memoria è riservata al main.

Una chiamata ad una function corrisponde alla allocazione di una opportuna area di memoria detta record di attivazione della function.

Nel record di attivazione è assegnato uno spazio opportuno, dipendente dal tipo, ad ognuno dei parametri della function e ad ogni variabile locale (cioè definita all’interno della function).

C++ funzioni → argomenti

Il C++ usa una struttura di memoria detta stack per gestire l’interfacciamento tra funzione chiamante e funzione chiamata
Lo stack è formato da una pila di aree di memoria detti record di attivazione, uno per ogni chiamata di funzione, contenente:

  • le variabili automatiche della funzione chiamata;
  • la lista degli argomenti della funzione in cui sono copiati i valori trasmessi dalla funzione chiamante;
  • l’indirizzo di rientro, cioè il riferimento all’istruzione della funzione chiamante che deve essere eseguita una volta completata la funzione chiamata (trasferendovi l’eventuale valore di ritorno)

C++ funzioni → argomenti

Quando il controllo deve tornare dalla funzione chiamata alla chiamante, il programma fa riferimento all’ultimo record dello stack per:
conoscere l’indirizzo di rientro nella funzione chiamante

eseguita tale operazione, rimuove lo stesso record dallo stack (cancellando di conseguenza anche le variabili automatiche)


C++ funzioni → argomenti

passaggio dei parametri per valore: come argomento viene assegnato una copia del valore del parametro

  • La funzione può anche modificarne il valore senza che nessuna delle variabili del processo chiamante ne risulti modificata
    • Le modifiche hanno effetto solo nell’ambito dell’esecuzione della funzione

C++ funzioni → argomenti

passaggio dei parametri per riferimento (per indirizzo): come parametro della funzione viene passato l’indirizzo di una variabile

  • L’argomento deve essere di tipo puntatore (&) al tipo del dato su cui si opera
  • L’argomento (il suo nome) si comporta come un sinonimo (alias) del corrispondente parametro passato

C++ funzioni → argomenti

Suggerimento:

  • Tutto i dati che servono ad una procedura per poter effettuare i suoi calcoli (parametri di input), devono essere passati per valore.
  • Tutte le variabili definite nel processo chiamante che la procedura deve modificare o inizializzare (parametri di input-output, parametri di output), devono essere passati per riferimento.

C++ funzioni → argomenti

Regola

E’ errato dichiarare due parametri dello stesso tipo nella forma double x, y anziché nella forma double x, double y. Si commette un errore di sintassi. Ogni parametro deve essere specificato con il tipo di dato a cui appartiene.

C++ funzioni → argomenti

riduci(int &n,int &d)

Viene segnalato un errore in corrispondenza della chiamata:

riduci(num+1,den);

Infatti num+1 è un’espressione cui dovrebbe corrispondere nella intestazione della function un parametro per passaggio di valore mentre il primo argomento di riduci è un riferimento.
Una soluzione può essere:

num++;
riduci(num,den);

C++ funzioni → argomenti

E’ sempre possibile trasformare una funzione in una procedura (e viceversa):

  • aggiungendo un parametro t di output dello stesso tipo del valore di ritorno della funzione
  • il corpo della procedura si ottiene dal corpo della funzione, sostituendo ogni enunciato del tipo return espr; con l’enunciato t=espr;

Esempio:

int calcola(int p,... ,float q,int &r,...,float &s)
void calcola(int p,... ,float q,int &r,...,float &s,int &t)

Suggerimento:
Scrivere una funzione che ritorna un valore solo se tutti suoi parametri devono essere passati per valore. In tutti gli altri casi scrivere una procedura.

C++ funzioni → esercizio


C++ funzioni → esercizio


C++ funzioni → esercizio

leggi:
precondizioni: le quattro variabili devono essere di tipo intero;
postcondizioni: le quattro variabili hanno ricevuto i valori che l’utente ha inserito e d1 e
d2 devono essere dei numeri diversi da zero.

calcolasomma:
precondizione: n1,d1,n2,d2 devono avere i valori inseriti dall’utente;
postcondizione: num e den devono rappresentare il numeratore ed il denominatore della somma.

riduci:
precondizione: num e den rappresentano numeratore e denominatore di una frazione;
postcondizione: num e den rappresentano il numeratore ed il denominatore della stessa
frazione, ma ridotta ai minimi termini.

stampa:
precondizione: num e den sono i valori della frazione ridotta ai minimi termini;
postcondizione: che questi siano stampati a video.

Per le prime tre procedure dopo la loro chiamata lo stato del sistema cambia mentre per l’ultima l’insieme delle variabili del sistema non subisce alcun cambiamento.

C++ funzioni → esercizio

3. Verifica e raffinamento: ogni macroazione va raffinata

  • La consideriamo come un sottoproblema di quello generale e per ogni sottoproblema cerchiamo un algoritmo (punto 2.)

C++ funzioni → esercizio

3. Verifica e raffinamento: ogni macroazione va raffinata

  • La consideriamo come un sottoproblema di quello generale e per ogni sottoproblema cerchiamo un algoritmo (punto 2.)

esercizio10.1.cpp


C++ funzioni → esercizio


C++ funzioni → esercizio

3. Verifica e raffinamento: grazie al metodo dei raffinamenti successivi (e dell’astrazione procedurale) possiamo

  • modificare l’algoritmo del singolo task della somma di frazioni
  • … lasciando inalterate le altre parti (e il codice) dell’algoritmo

esercizio10.2.cpp


C++ funzioni → osservazioni

l’astrazione procedurale consente di evitare inutili duplicazioni di codice (semplicità e leggibilità del codice)

  • Codificando l’intero programma senza far uso di funzioni si incorre spesso in duplicazioni
  • L’eccesso di chiamate funzionali penalizza le prestazioni (efficienza)

C++ funzioni → osservazioni

l’astrazione procedurale consente di separare il programma in moduli indipendenti (modularità) fornendo la possibilità

  • di estensione/modifica di ogni modulo senza condizionare gli altri moduli del programma (estendibilità del codice)

l’astrazione procedurale consente di separare il programma in moduli indipendenti (modularità) fornendo la possibilità

C++ funzioni → esercizio

Problema
Assegnata una quantità di centesimi di euro, suddividerla nel numero minimo di monete da 50, 20, 10, 5, 1

1. Analisi del problema:
Chiamiamo X la quantità in centesimi da convertire (input utente)

  • Consideriamo k=5 monete di valore Mi centesimi:

M1=50, M2=20, M3=10, M4=5, M5=1

  • Calcolare il numero massimo npezzi1 di monete da M1 centesimi in cui possiamo suddividere la quantità X, e diciamo resto il rimanente numero di centesimi. Evidentemente si ha: npezzi1 = X / M1, resto = X % M1
  • per calcolare il numero di pezzi di valore M2 successivo (più basso) in cui possiamo suddividere quanto resta, assegnamo resto a X e calcoliamo:

npezzi2 = X / M2, resto = X % M2

  • e così via … finché resto è nullo npezzii

C++ funzioni → esercizio

2. Individuare un algoritmo (G), ossia una successione finita di azioni che, in prima approssimazione, risolve il problema

Costruiamo una procedura che accetti in ingresso i centesimi e il valore della moneta e ci restituisca in uscita sia il numero di pezzi di tale tipo di moneta che il numero di centesimi rimasti (dato in input 74 centesimi e 20 come valore della moneta, ci fornisca in uscita 3 ed il numero di centesimi rimasti 14).

Parametri?


C++ funzioni → esercizio

4. Implementazione: scriviamo il programma principale e i prototipi delle funzioni

Mostra codice

C++ funzioni → esercizio

4. Implementazione: scriviamo il codice per il corpo delle funzioni di cui abbiamo già il prototipo

Mostra codice

C++ funzioni → esercizio

Osservazioni:
Calcolapezzi potrebbe essere una funzione ma la presenza di centesimi che è un parametro di input-output impone di scrivere una procedura.

Abbiamo visto un altro uso molto comune dei sottoprogrammi. Codificando direttamente l’algoritmo iniziale avremmo dovuto scrivere più volte del codice sostanzialmente simile. L’utilizzo della procedura CalcolaPezzi ce lo ha evitato.

Si sarebbero potuto anche fondere in una unica procedura CalcolaPezzi e Stampa, la quale, dopo aver calcolato Npezzi, provvedesse anche a stamparlo. Tuttavia così come è scritta CalcolaPezzi risulta più facilmente riutilizzabile in un altro programma.

Non abbiamo ancora scritto il corpo delle due function. Ma questo programma incompleto può essere compilato. Inoltre introducendo nel corpo delle function un opportuno messaggio di stampa si può verificare se il flusso del programma è quello voluto. Ad esempio si potrebbe inserire in stampa:

cout<<''sono in stampa''
ed in CalcolaPezzi:

cout<<Tpezzo

C++ funzioni → esercizio

4. Implementazione: scriviamo il codice per il corpo delle funzioni di cui abbiamo già il prototipo.

esercizio10.3.cpp


C++ funzioni → argomenti array

Se gli argomenti di una funzione sono nomi di array il passaggio di parametri avviene sempre per riferimento
Non occorre anteporre l’operatore & nella dichiarazione degli argomenti

Nella definizione di funzione la variabile (identificatore) dell’array è preceduta dal tipo e seguita dalla coppia di parentesi quadre
Esempio:
void sommavet(const int A[], const int B[], int k, int C[]) {
for (int i=0; i < k; i++)
C[i] = A[i] + B[i];
}

non serve specificare la dimensione perché é già stata dichiarata nel programma chiamante
se l’array é multidimensionale l’unico indice che si può omettere é quello a sinistra
Lo specificatore const serve a indicare che il parametro è solo in lettura (ogni tentativo di modica nel corpo della funzione è un errore del compilatore)

C++ funzioni → argomenti array

Nella dichiarazione di funzione (o prototipo) ogni argomento è dichiarato solo con il tipo affiancato dalle parentesi quadre
Esempio:
void sommavet(const int[], const int[], int, int[]);

Per trasmettere un intero array a una funzione bisogna inserire nella chiamata il nome dell’array (senza parentesi quadre):
Esempio:
int vet1[100], vet2[100], vet3[100]
sommavet(vet1, vet2, 100, vet3)

Nel corpo della funzione tutte le modifiche fatte ai singoli elementi dell’array vengono riprodotte sull’array del programma chiamante

C++ funzioni → argomenti array

Nel caso di passaggio di parametri come singoli elementi di un array non ci sono eccezioni alla regola generale.
Esempio:

Mostra codice

I materiali di supporto della lezione

esercizio10.1

esercizio10.2

esercizio10.3

  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion