Elementi di Informatica 1 Prof. G. A. Di Lucca - Univ. del Sannio
Sottoprogrammi in C
• Un sottoprogramma in C viene definito nel seguente modo:
Esempio:
float Calcola ([<lista parametri formali>]) { <parte dichiarativa>
<corpo del sottoprogramma>
[return <espressione>;]
}
Un sottoprogramma può avere o meno una lista di argomenti (parametri)
<tipo> <nome_sottoprogramma >([<lista parametri formali>]) { sezione dichiarativa
corpo del sottoprogramma [return <espressione>;]
}
Elementi di Informatica 2 Prof. G. A. Di Lucca - Univ. del Sannio
• Ogni funzione presenta un valore di ritorno che può essere di un qualsiasi tipo predefinito dal linguaggio o definito
dall’utente.
• Se nella dichiarazione viene omesso il tipo ritornato, esso viene considerato automaticamente un intero.
Funzioni in C
Procedure in C
• In C non esistono le procedure
• Essa è definita come una funzione con il tipo predefinito void
come valore di ritorno; ovvero non è ritornato alcun valore
associato al nome di quella funzione (ma solo ai parametri
passati per riferimento).
Elementi di Informatica 3 Prof. G. A. Di Lucca - Univ. del Sannio
Controllo dell’esecuzione
• All’atto della chiamata di una funzione, il controllo
dell’esecuzione viene passato alla prima istruzione del corpo della funzione stessa.
• Esistono due modi per restituire il controllo al programma chiamante:
– termine dell’esecuzione della funzione (quando si incontra la “}” finale)
– attraverso l’istruzione: return [<espressione>];
• E’ opportuno controllare sempre che la chiamata di una funzione ed il suo valore di ritorno siano consistenti.
Lista dei parametri formali
• La lista dei parametri è usata per scambiare dati tra una funzione chiamante e quella chiamata. La lista può essere anche vuota.
• I parametri devono essere specificati tra parentesi e separati da virgole, dopo il nome della funzione.
• Per ciascun parametro deve essere dichiarato il suo tipo.
• Esempio:
float Calcola (int x, float y , char z) {
<parte dichiarativa>
<corpo della funzione >
[return <espressione>;]
}
Elementi di Informatica 5 Prof. G. A. Di Lucca - Univ. del Sannio
Parametri di una funzione
• Il metodo di passaggio dei parametri, per default, è per valore (la funzione chiamata opererà su una copia locale dei parametri attuali passati e non ne modifica il loro valore nel chiamante)
• è possibile passare i parametri per riferimento, utilizzando variabili di tipo puntatore
• E’ responsabilità del programmatore controllare che il numero ed il tipo degli argomenti passati ad una funzione corrisponda con quanto specificato nella dichiarazione della funzione stessa.
Elementi di Informatica 6 Prof. G. A. Di Lucca - Univ. del Sannio
Notazione per lo scambio di parametri per riferimento
• Il meccanismo di scambio dei parametri per riferimento (per indirizzo) avviene tramite l’uso di variabili di tipo puntatore;
in tal caso la funzione chiamata sarà in grado di modificare direttamente il valore del parametro effettivo che riceve.
• Notazione nella dichiarazione di una funzione C di un argomento passato per riferimento:
<tipo> <nome_funzione> (
*
<nome_parametro>)Es:
void proc1(int * A, int B)
passato per riferimento passato per valore
Elementi di Informatica 7 Prof. G. A. Di Lucca - Univ. del Sannio
• Anche i parametri effettivi nella chiamata alla funzione avranno una forma diversa se passati per valore o riferimento
• Passaggio per indirizzo:
<nome_funzione_chiamata> (&<nome_parametro>) Es.:
pippo(&numero); // chiamata della funzione pippo con parametro // effettivo numero passato per riferimento riferendosi all’esempio precedente: void proc1(int *A, int B) int x, y;
proc1(&y, x); // chiamata della funzione proc1 con parametro effettivo // y passato per riferimento al parametro formale A // e x passato per valore al parametro formale B
Notazione per scambio di parametri per riferimento
[<direttive di inclusione>]
[<dichiarazioni sottoprogrammi>]
main ( ) {
<corpo del programma>
}
Struttura di un programma con sottoprogrammi in linguaggio C
Le dichiarazioni dei sottoprogrammi vanno fatte prima del main
Elementi di Informatica 9 Prof. G. A. Di Lucca - Univ. del Sannio
Struttura di un programma con sottoprogrammi in C
#include <stdio.h>
float Area_Tr(int W, int Y) { float Area_triangolo;
Area_triangolo = (W*Y)/2;
return Area_triangolo;
}
main ( )
{ float base, altezza;
printf (“Immetti valore base\n”);
scanf (“%f”, &base);
printf (“Immetti valore altezza\n”);
scanf (“%f”, &altezza);
if ((base>0)&&(altezza>0))
printf(“Area Triangolo = %f \n”, Area_Tr(base,altezza));
else
printf(“Errore: valore base e/o altezza non maggiori di zero !! \n”);
}
Esempio:
Elementi di Informatica 10 Prof. G. A. Di Lucca - Univ. del Sannio
Esempio di funzione
#include <stdio.h>
// funzione che calcola il cubo di una variabile int cube(int x)
{ int a = x*x*x;
return a; // il valore di a è associato al nome ‘cube’
// della funzione e ‘ritornato’ al main
}
main () {
int I;
printf("Immetti numero per calcolarne il cubo ”);
scanf(“%d”, &I);
printf("Cubo = %d \n”, cube(I));
}
Elementi di Informatica 11 Prof. G. A. Di Lucca - Univ. del Sannio
Esempio di procedure
#include <stdio.h>
// procedure che calcola il cubo di una variabile // il valore del cubo calcolato è associato al // parametro formale a passato per riferimento
void cube(int x, int *a) {*a = x*x*x; }
main ()
{ int I, I_al_cubo;
printf("Immetti numero per calcolarne il cubo\n ");
scanf("%d", &I);
cube (I, &I_al_cubo);
printf("Cubo di I= %d \n", I_al_cubo);
}
… notare la differente modalità di chiamata e di ‘uso’ del risultato …
Conseguenze di errato uso del meccanismo di scambio parametri
#include <stdio.h>
void swap(int x, int y) { int temp;
temp = x;
x = y;
y = temp;
}
main() { int a = 3;
int b = 5;
swap(a, b);
printf(“a= %d b= %d\n”,a,b);
}
… un programma che attiva un sottoprogramma per effettuare lo scambio (swap) dei valori di due variabili
Essendo, a = 3 e b = 5 il risultato atteso è: a = 5 e b = 3
All’attivazione della funzione si ha ax = 3 , b y = 5
L’esecuzione del sottoprogramma produce x = 5 , y = 3
L’output del programma è:
a = 3 b = 5 ovvero nessuno scambio
Motivo: i parametri sono scambiati per valori per cui swap agisce su x e y, una ‘copia’ delle variabili a e b i cui valori restano immutati nel main
Elementi di Informatica 13 Prof. G. A. Di Lucca - Univ. del Sannio
Esempio con il corretto scambio per riferimento
#include <stdio.h>
void swap(int *x, int *y) { int temp;
temp = *x;
*x = *y;
*y = temp;
} main() { int a = 3;
int b = 5;
swap(&a, &b);
printf(“a= %d b= %d\n”,a,b);
}
… e l’output del programma è:
a=5 b=3
… scambio dei valori tra le variabili correttamente effettuato !!
la funzione deve agire direttamente sulle variabili stesse e quindi occorre passare gli indirizzi delle variabili, ovvero usare scambio per riferimento.
Ora x e y sono parametri formali passati per riferimento
Elementi di Informatica 14 Prof. G. A. Di Lucca - Univ. del Sannio
Prototipo di una funzione
Il prototipo di una funzione rappresenta una dichiarazione di funzione (indicandone la sola intestazione) che precede la sua completa definizione.
Es. : int functionPluto(int x, char c);
L’uso dei prototipi è obbligatorio quando la definzione completa di una funzione avviene successivamente al suo utilizzo nel codice del chiamante.
Il prototipo agevola la decomposizione tramite l’astrazione funzionale: si indica che ci sarà una funzione (sottoprogramma) per svolgere una certa elaborazione, senza dover subito specificare come essa è implementata.
Lo scopo dei prototipi delle funzioni è quello di permettere al compilatore di compiere il controllo sui nomi della funzione e dei tipi degli argomenti che vengono passati ad una funzione quando essa viene chiamata.
In un prototipo può essere indicato il solo tipo dei parametri formali:
int functionPluto (int,char); // indicati solo i tipi // dei parametri formali
Elementi di Informatica 15 Prof. G. A. Di Lucca - Univ. del Sannio
Esempio uso prototipo
#include <stdio.h>
int cube(int x); //PROTOTIPO della funzione
main () {int I;
printf(" Immetti numero per calcolarne il cubo ”);
scanf(“%d”, &I);
printf("Cubo = %d \n”, cube(I));
}
// definizione della funzione int cube(int x)
{ int a=x*x*x;
return a;
}
Prototipi di funzione
• L’inserimento dei prototipi prima della definizione di una funzione, permette al compilatore, quando incontra la dichiarazione del prototipo di conoscere e controllare il numero ed i tipi degli argomenti.
• La dichiarazione e la successiva definizione di una funzione devono essere consistenti sia nel numero che nel tipo dei parametri.
• Attenzione: se prototipo e definizione di funzione si trovano nello stesso file sorgente eventuali non corrispondenze nei tipi degli argomenti saranno rilevati dal compilatore, in caso contrario al più ci sarà un warning.
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 17
Esercizio
Analisi e Specifica
Definizione del problema: dati due numeri interi NON negativi ed un segno di un’operazione aritmetica (+, -, *, /) calcolare e visualizzare il risultato
dell’operazione indicata dal segno applicato ai due numeri, secondo l’ordine di immissione (ovvero l’operatore è applicato tra il primo ed il secondo numero immesso); per la divisione visualizzare anche il resto.
N.B. Nel calcolo di ciascuna operazione aritmetica usare solo le operazioni di somma e differenza (anche per moltiplicazione e divisione).
Sviluppare il programma definendo due opportuni sottoprogrammi per le operazioni di moltiplicazione e di divisione.
Definizione dei dati del problema:
I: due numeri interi; il segno dell’operazione aritmetica Pi: i due operandi sono NON negativi
U: il risultato dell’operazione di tipo intero Pu: nessuna
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 18
Esempio
Nome variabile Descrizione Tipo
OP1, OP2 i due operandi INT Segno segno dell’operazione CHAR
Nome variabile Descrizione Tipo
Risultato risultato dell’operazione INT
Resto resto della divisione INT
Tabella delle variabili di ingresso
Tabella delle variabili di uscita
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 19
Progettazione
Descrizione del metodo di elaborazione:
E’ letto il segno dell’operazione, se esso è diverso da ‘+’, ‘-’, ‘*’, ‘/’ si richiede la ripetizione dell’immissione.
Sono letti i valori dei due operandi e si verifica che essi siano NON negativi, altrimenti si richiede la ripetizione dell’immissione
Quando segno e operandi sono validi si analizza il segno dell’operazione e:
• nel caso il segno è ‘+’ fare la somma dei due operandi;
• nel caso il segno è ‘-’ fare la differenza dei due operandi;
• nel caso il segno è ‘*’ calcolare il prodotto con somme successive;
• nel caso il segno è ‘/’ calcolare il quoziente intero con differenze successive:
Si sottrae al primo operando (dividendo) il valore del secondo operando immesso (divisore), il risultato della sottrazione è ancora diminuito del dividendo e si continua così fin quando si avrà un risultato della sottrazione minore del divisore; il quoziente è pari al numero di sottrazioni effettuate Calcolare il resto applicando l’operatore modulo ai due operandi
Si stampa il valore del Risultato, e del Resto nel caso della divisione, e si termina il programma
#include <stdio.h>
// prototipi delle funzioni
int moltiplicazione (int O1, int O2);
void divisione(int O1, int O2, int *Ris, int *resto);
main ()
{ // programma scegli operazione e calcola int OP1, OP2, Risultato, I, Resto;
char Segno;
do
{ printf ("immetti segno operazione \n");
scanf(“\n%c", &Segno);}
while((Segno!='+')&& (Segno!='-')&& (Segno!='*')
&& (Segno!='/'));
Esempio
“scegli operazione e calcola”
con sottoprogrammi
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 21
do {
printf("immetti i due operandi \n");
printf(" operando 1 \n");
scanf ("%d", &OP1);
printf (" operando 2 \n");
scanf ("%d", &OP2);
}
while ((OP1<0)||(OP2<0));
Esempio - con sottoprogrammi
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 22
switch (Segno)
{case '+' : Risultato = OP1 + OP2; break;
case '-' : Risultato = OP1 - OP2; break;
case '*' : { Risultato = moltiplicazione(OP1, OP2);
break;
}
case '/':{divisione(OP1, OP2, &Risultato, &Resto);
break;
}
} // fine switch - case
Esempio - con sottoprogrammi
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 23
if ((Segno == '/')&& (OP2==0))
printf("\n Divisione IMPOSSIBILE \n
Immesso zero come divisore \n");
else
{ printf("risultato = %d \n", Risultato);
if (Segno == '/')
printf("Resto = %d \n", Resto);
}
system("Pause");
} // fine programma principale
Esempio con sottoprogrammi
Esempio con sottoprogrammi int moltiplicazione (int O1, int O2)
{ int Risultato, I;
Risultato=0;
for (I=1; I <= O2; I++)
Risultato=Risultato + O1;
return Risultato;
}
Elementi di Informatica
Prof. G. A. Di Lucca - Univ. del Sannio 25
void divisione(int O1, int O2, int *Ris, int *resto) {int TEMP = O1;
*Ris=0;
if (O2!=0)
{ while (O2 <= O1)
{ O1 = O1 - O2;
*Ris = *Ris + 1;}
*resto = TEMP – (*Ris * O2) ; }
}
Esempio con sottoprogrammi
Elementi di Informatica 26 Prof. G. A. Di Lucca - Univ. del Sannio
Sottoprogrammi in file separati
• I sottoprogrammi possono essere inseriti in file sorgenti separati/differenti da quello con il main( ); i file dei sorgenti dei sottoprogrammi possono essere compilati separatamente
• nel main, o nei sottoprogrammi che ne chiamano altri memorizzati in file differenti, dovrà essere indicata una
direttiva di inclusione (#include) che indica il file sorgente da includere contenente il/i sottoprogramma/i chiamato/i.
• Il file che contiene il codice sorgente del sottoprogramma ha
tipicamente .h come estensione. Un file .h può contenere più
sottoprogrammi, formando in tal modo una libreria di
sottoprogrammi
Elementi di Informatica 27 Prof. G. A. Di Lucca - Univ. del Sannio
Sottoprogrammi in file separati
#include <stdio.h>
#include <C:\cube.h> /* include il file cube.h, registrato sul disco C:
contenente il codice della funzione cube */
main () {
int I;
printf("Immetti numero per calcolarne il cubo
”);
scanf(“%d”, &I);
printf("Cubo = %d \n”, cube(I));
}
Sottoprogrammi in file separati
int cube(int x) {
int a=x*x*x;
return a;
}
La funzione cube è memorizzata nel file sorgente cube.h
Attenzione: i file inclusi vanno memorizzati nella libreria di default dei file di inclusione altrimenti va indicato per intero il path di memorizzazione
per DevC++ la libreria di inclusione di default è la cartella include
Elementi di Informatica 29 Prof. G. A. Di Lucca - Univ. del Sannio
Sottoprogrammi in file separati
#include <stdio.h>
#include <cube.h> /* include il file cube.h, registrato nella cartella include di Dev-C++ */
main () {
int I;
printf("Immetti numero per calcolarne il cubo
”);
scanf(“%d”, &I);
printf("Cubo = %d \n”, cube(I));
}
Elementi di Informatica 30 Prof. G. A. Di Lucca - Univ. del Sannio
Lo studente modifichi il programma del gioco Master Mind con massimo 5, o più, tentativi strutturandolo con dei sottoprogrammi.
In particolare sia definito:
• Un sottoprogramma per generare i valori del codificatore
• Un sottoprogramma per leggere un valore del decodificatore controllando che sia compreso tra 0 e 9 (estremi inclusi)
• Un sottoprogramma per verificare i valori immessi dal decodificatore rispetto a quelli del codice da indovinare
Elementi di Informatica 31 Prof. G. A. Di Lucca - Univ. del Sannio
Esempio Mastermind
- il programma in C con sottoprogrammi -#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//prototipi delle funzioni
// Genera i valori del codificatore
void leggi_Indovina(int *indovina1,int *indovina2,int
*indovina3);
// legge un valore del decodificatore int leggi_indovinato(int i);
// verifica i valori immessi dal decodificatore rispetto // a quelli del codice
void verifica(int indovinatoX, int indovinaX, int indovinaW, int indovinaY, char *pos);
… lo studente potrebbe far riferimento ai prototipi di funzione indicati per definire i
sottoprogrammi …