User Tools

Site Tools


appunti3s:programmi_procedurali

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
appunti3s:programmi_procedurali [2018/04/25 07:55] – external edit 127.0.0.1appunti3s:programmi_procedurali [2020/06/08 22:19] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +====== Introduzione ======
 +Se il computer potesse comprendere il linguaggio umano, si potrebbe chiedere:
 +  * Ehi Mario, calcola questo per me e restituiscimi il risultato
 +  * Ehi Anna, esegui questo gruppo di istruzioni per me
  
 +Questo genere di ordini sono stati impartiti raggruppando le istruzioni, in modo da poterle riutilizzare più volte.
 +Un programma che utilizza questo tipo di struttura viene detto "procedurale".
 +
 +
 +====== Procedure e funzioni ======
 +Il termine //procedura// è legato al termine //funzione// (anche se vi sono piccole differenze di significato). 
 +Per capire cosa sia una funzione in un programma basta pensare ad una funzione matematica, dove c'è la variabile indipendente //x// e quella dipendente //y//, dove si trova il risultato //y=f(x)//. Ad esempio, la funzione //y=x<sup>2</sup>// calcola il quadrato dei valori forniti tramite //x//.
 +
 +Nella programmazione procedurale, ad ogni funzione viene affidata l'esecuzione di un compito specifico e ogni volta che si deve svolgere quel compito si chiama in esecuzione quella funzione.
 +
 +Tra parentesi possono essere specificati degli argomenti che la funzione può utilizzare. Alcune funzioni, come //main()//, possono essere prive di argomenti.
 +
 +È utile eseguire questi programmi in modalità [[appunti3s:gdb|debug]] e visualizzare il contenuto delle variabili in runtime. 
 +
 +<file cpp 11.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Serve a calcolare il triplo di un numero
 +// scrivendo tutto il codice nella funzione principale.
 +#include <iostream> //che cosa contiene il file iostream e iostream.h?
 +
 +int main ()
 +{
 +  int mioNumero;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> mioNumero;
 +
 +  std::cout << "il triplo di " << mioNumero << " vale " 
 +            << 3*mioNumero << endl;
 +  return 0;
 +}
 +</file>
 +
 +====== Passaggio per valore ======
 +
 +
 +<file cpp 12.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Come nel programma precedente calcola il triplo di un numero, ma
 +// ora usando una semplice funzione chiamata triplicare().
 +#include <iostream>
 +
 +// questo modo di passare il valore crea una nuova variabile locale (int x)
 +// questa funzione restituisce un int (return)
 +int triplicare(int x) // definizione della funzione con parametro formale 'x'
 +{
 +  return 3*x;
 +}
 +
 +int main()
 +{
 +  int mioNumero,mioTriplo;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> mioNumero;
 +  
 +  mioTriplo = triplicare(mioNumero); // chiamata della funzione con il 
 +                                     // parametro effettivo 'mioNumero'
 +  
 +  std::cout << "il triplo di " << mioNumero << " vale "
 +            << mioTriplo << endl;
 +  return 0;
 +}
 +</file>
 +
 +  * //main()// è una funzione (la funzione principale) che (di solito) restituisce un valore intero. 
 +  * //triplicare()// è una funzione che restituisce un valore intero.
 +Dentro la //definizione// della funzione //triplicare()// tra parentesi c'è scritto //int x//
 +questo permette di passare alla funzione una copia di una variabile, e questo meccanismo si chiama appunto //passaggio per valore//.
 +Per parlare in termini semplificati, sarebbe, più o meno, come se ci fosse scritto il seguente codice "invisibile"...
 +<code>
 + int x;         // definizione di una nuova variabile locale
 + x = mioNumero; // assegnazione del valore passato come argomento
 +</code>
 +Questo codice serve solo per capire cosa accade dentro la funzione, e non va preso alla lettera, cioè non vanno copiate quelle istruzioni...
 +
 +===== Visibilità =====
 +
 +Ecco una tabella che mostra i valori contenuti nelle aree di memoria utilizzate durante l'esecuzione dell'ultimo esempio:
 +^ mioNumero ^ mioTriplo ^ x ^
 +|  6  |  -  |    |
 +|  6  |  -  |  6  |
 +|  6  |  18  |  - |
 +Questo tipo di tabella che tiene la traccia delle variabili si può paragonare allo strumento di [[appunti3s:gdb|debug]]. Come si può notare la vita della variabile locale della funzione //triplicare()// (il parametro formale //x//) è più breve, rispetto alle variabili della funzione //main()// (il parametro effettivo //mioNumero//). Queste due funzioni vengono eseguite in aree di memoria separate, che non sono reciprocamente visibili. Per questo motivo le variabili delle funzioni sono dette //variabili locali//. a comunicazione tra le due funzione avviene solo grazie alla copia del valore dentro //x// e grazie al comando //return//.
 +
 +Questo programma contiene un'istruzione che non rispetta la visibilità delle variabili. Provare a compilare il seguente programma:
 +
 +<file cpp 13.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Serve a dimostrare la visibilità delle variabili locali.
 +#include <iostream>
 +
 +// questo modo di passare il valore crea una nuova variabile locale (int x)
 +// questa funzione restituisce un int (return)
 +int triplicare(int x) 
 +{
 +  return 3*x;
 +}
 +
 +int main()
 +{
 +  int mioNumero,mioTriplo;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> mioNumero;
 +  
 +  mioTriplo = triplicare(mioNumero); // chiamata della funzione
 +  
 +  std::cout << "il triplo di " << mioNumero << " vale "
 +            << x << std::endl;
 +  return 0;
 +}
 +</file>
 +
 +Si dovrebbe ottenere questo errore 
 +<code>
 +   In function ‘int main()’:
 +        : error: ‘x’ was not declared in this scope </code>
 +
 +===== Classificazione =====
 +
 +Esistono due diversi tipi di funzioni: 
 +  * quelle che restituiscono un valore (uno!) a chi le chiama;
 +  * quelle che non restituiscono nessun valore (tipo void) a chi le chiama.
 +
 +Il valore restituito dalle prime (vedi //return//) può essere usato per ottenere il risultato di un calcolo.
 +NOTA sul C: a volte i programmatori C usano il valore restituito da una funzione per stabilire se questa è stata eseguita senza errori (restituendo 0) oppure se ha prodotto un errore (restituendo ad esempio 5). In C++ il valore restituito non dovrebbe essere usata per questo scopo, perché, per stabilire se ci sono errori, si usano le //exception// (vedi gestione delle [[appunti3s:eccezioni]]).
 + 
 +Le funzioni si possono anche classificare in //ispettori// e //modificatori//:
 +  * le prime non modificano il contenuto delle variabili passate, quindi di solito, per avere un effetto al loro esterno, devono restituire un valore (quindi non sono di tipo void)
 +  * le seconde possono modificare il contenuto delle variabili passate, quindi possono anche essere di tipo void
 +
 +Spiegare i termini //variabile locale//, //argomento//, //parametro formale//, //parametro effettivo//
 +
 +<file cpp 14.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Serve a dimostrare l'ambito di visibilità delle variabili locali
 +// usando due funzioni
 +
 +#include <iostream>
 +
 +int triplicare() 
 +{
 +  return 3*mioNumero; // ERRORE 
 +}
 +
 +int main()
 +{
 +  int mioNumero,mioTriplo;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> mioNumero;
 +  
 +  mioTriplo = triplicare(); // chiamata della funzione
 +  
 +  std::cout << "il triplo di " << mioNumero << " vale "
 +            << mioTriplo << endl;
 +  return 0;
 +}
 +</file>
 +
 +
 +  la variabile mioTriplo NON era necessaria... riscrivere il programma 12.cpp
 +
 +  
 +<file cpp 15.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Dimostra l'uso di una funzione dentro l'operatore di inserimento.
 +
 +#include <iostream>
 +
 +int triplicare(int x)
 +{
 +  return 3*x;
 +}
 +
 +int main()
 +{
 +  int mioNumero;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> mioNumero;
 +
 +// la chiamata della funzione (triplicare) dentro insertion 
 +  std::cout << "il triplo di "<< mioNumero << " vale "
 +            << triplicare(mioNumero) << std::endl;
 +  return 0;
 +}
 +</file>
 +
 +<file cpp 16.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Contiene una funzione di "tipo" void
 +// ed inoltre mostra l'effetto del passaggio per valore.
 +
 +#include <iostream>
 +
 +// questa funzione non restituisce nulla (manca return)
 +void triplicare(int x)
 +{
 +  x= 3*x; // ERRORE? Ha effetto sul parametro reale?
 +}
 +
 +int main()
 +{
 +  int mioNumero;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> mioNumero;
 +  std::cout << "il triplo di " << mioNumero << " vale "
 +
 +  triplicare();  // chiamata della funzione
 +  std::cout  << mioNumero << std::endl;
 +  return 0;
 +}
 +</file>
 +
 +
 +<file cpp 17.cpp>
 +// questo programma è stato scritto da Fabio
 +// Serve a calcolare la media (valore intero) tra due interi
 +#include <iostream>
 +
 +int media(int x, int y)
 +{
 +  return (x+y)/2;
 +}
 +
 +int main()
 +{
 +  int numero1,numero2;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> numero1;
 +  std::cout << "Per favore scrivi un altro numero intero: ";
 +  std::cin >> numero2;
 +  
 +  std::cout <<  "La media vale" << media(numero1,numero2) << endl;
 +  return 0;
 +}
 +</file>
 +
 +<file cpp 18.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Dimostra l'utilità delle funzioni per riutilizzare il codice
 +// effettuando più chiamate della stessa funzione. 
 +// 
 +// Serve a calcolare la media di 4 numeri.
 +
 +#include <iostream>
 +
 +int mediare(int x, int y)
 +{
 +  return (x+y)/2;
 +}
 +
 +int main()
 +{
 +  int numero1,numero2,numero3,numero4,media;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> numero1;
 +  std::cout << "Per favore scrivi un altro numero intero: ";
 +  std::cin >> numero2;
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> numero3;
 +  std::cout << "Per favore scrivi un altro numero intero: ";
 +  std::cin >> numero4;
 +
 +  media = mediare(mediare(numero1,numero2),mediare(numero3,numero4));
 +  std::cout <<  "La media vale " << media << endl;
 +
 +  return 0;
 +
 +}
 +
 +</file>
 +===== Dichiarazioni =====
 +Ora che è chiaro l'importanza delle funzioni per il riutilizzo del codice, bisogna capire anche che il compilatore ha bisogno di controllare la correttezza delle chiamate delle funzioni, che cioè vengano chiamate con il giusto numero e tipo di parametri. Nei precedenti esempi questo controllo era reso possibile dal fatto che le nuove funzioni erano definite all'inizio del file. 
 +
 +Le funzioni possono essere definite anche dopo, ma bisogna comunque dichiarare o "annunciare" la loro forma. Vedere il seguente esempio
 +<file cpp 19.cpp>
 +// Questo programma è stato scritto da Fabio.
 +// Dimostra la differenza tra concetto di dichiarazione e di definizione 
 +
 +#include <iostream>
 +
 +int mediare(int x, int y); // qui dichiarazione senza definizione!
 +
 +int main()
 +{
 +  int numero1,numero2,numero3,numero4,media;
 +
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> numero1;
 +  std::cout << "Per favore scrivi un altro numero intero: ";
 +  std::cin >> numero2;
 +  std::cout << "Per favore scrivi un numero intero: ";
 +  std::cin >> numero3;
 +  std::cout << "Per favore scrivi un altro numero intero: ";
 +  std::cin >> numero4;
 +
 +  media = mediare(mediare(numero1,numero2),mediare(numero3,numero4));
 +  std::cout <<  "La media vale " << media << endl;
 +
 +  return 0;
 +
 +}
 +
 +int mediare(int x, int y)
 +{
 +  return (x+y)/2;
 +}
 +</file>