sabato, novembre 04, 2006

Funzioni


#include <stdio.h>

/*
Concettualmente ci sono due tipi fondamentali di sottoprogrammi: le procedure e le funzioni.

Le procedure sono semplicemente delle porzioni di codice che offrono i vantaggi di:
- evitare la ripetizione di codice simile o uguale all'interno dello stesso programma
- facilitare la modularita' della programmazione (metodo top-down)
- permettere la ri-usabilita' del codice (procedure come building-block) anche per nuovi programmi

Le funzioni sono delle procedure che "restituiscono" un valore al termine della loro esecuzione.
Il significato del termine "restituire" risiede nella possibilita' che hanno le funzioni
(a differenza delle procedure) di poter comparire al lato destro di un'assegnazione: al lato
sinistro dell'assegnazione, cioe', verra' assegnato proprio il valore "restituito" dalla funzione.

In C++ non c'e' differenza (sintattica) fra funzione e procedura.
La dichiarazione di una funzione e' la seguente:

tipo_restituito nome_funzione(lista dei parametri) {
istruzioni;
}

Per le procedure, semplicemente il tipo_restituito sara' "void" (letteralmente: vuoto, nullo, vacante).

Le funzioni si dichiarano fuori dal main (che rappresenta una funzione anch'essa!), eventualmente su
un file diverso da includere o linkare (vedi lezioni successive...)

Per una agevole "lettura" di questo codice, cominciare a leggere direttamente il main,
ed usarlo come "indice"; tornare sopra a leggere le singole funzioni quando
quando ciascuna viene richiamata (e commentata) nel main
*/


int i,j;



//ESEMPIO DI FUNZIONE
int quadrato_di(int a) {
int res; //dichiaro una variabile che conterra' il valore "restituito"
res = a*a; //calcolo il valore che voglio "restituire"
return res; //e lo "restituisco"
//return causa l'uscita dalla funzione e la restituizione del valore che segue
}


//ESEMPIO DI PROCEDURA

void quadrami(int &a) {
a = a*a;
}

//VARIANTI ED ESEMPI ULTERIORI:


//ancora sulla differenza: "per valore", e "per riferimento"
void doppio_quadrato(int a, int &b) {
//notate che per poter usare i e j dentro questa funzione, ho dovuto dichiararle fuori dal main!
//di piu': ho dovuto dichiararle PRIMA di dichiarare questa funzione (dove voglio usarle...)
printf("Dentro \"doppio_quadrato()\", all'inizio, i e j valgono (ancora) %d e %d\n",i,j);
printf(
"Dentro \"doppio_quadrato()\", all'inizio, a e b valgono (ugualmente) %d e %d\n",a,b);
a = a*a;
b = b*b;
printf(
"Dentro \"doppio_quadrato()\", dopo la quadratura, i e j valgono (attenzione!) %d e %d\n",i,j);
printf(
"Dentro \"doppio_quadrato()\", dopo la quadratura, a e b valgono (udite udite!) %d e %d\n",a,b);
}


//funzione (procedura!!!) senza parametri (mettere comunque le parentesi tonde!!!)
void vaiAcapo() {
printf(
"\n");
}

//funzione con valore di default per alcuni parametri:
//se vengono forniti meno parametri, i paramentri mancanti assumono il valore
//dei parametri piu' a destra (vedi main...)
int somma(int a, int b=0, int c=0, int d=0) {

int res;
res = a + b + c + d;
}

//Esempio di overload di funzioni
//(dichiarazione di due funzioni con lo stesso nome, ma con parametri diversi: il C++ le considera
//funzioni diverse!

void stampa(int a) {
printf(
"%d\n",a);
}

void stampa(float a) {
printf(
"%g\n",a);
}


//Esempio di funzione ricorsiva: il fattoriale
int fattoriale(int n) {
if (n<=0)
return 1;
else
return n*fattoriale(n-1);
}


int main() {


i =
3;
j = quadrato_di(i);
printf(
"i = %d e j = %d\n",i,j);
//se non specificato in modo diverso (vedi, ad esempio, la procedura), il parametro e' considerato "per valore"
//cioe' non si passa alla funziona "la variabile", ma "il contenuto della" variabile.
//Tant'e' che possiamo addirittura NON usare alcuna variabile, come parametro:
printf("il quadrato di 3 e' %d\n",quadrato_di(3));

//diverso e' il caso se esplicitamente dichiaramo il parametro come "per riferimento" (con un & davanti alla variabile)
//In questo caso non passiamo il VALORE della variabile, ma la variabile stessa:
i = 3;
printf(
"prima di \"quadrami\", i vale %d\n",i);
quadrami(i);
printf(
"dopo \"quadrami\", i vale %d\n",i);
//e quindi, ovviamente, non posso chiamare "quadrami" con un valore al posto di una variabile:
//quadrami(3); darrebbe un errore in compilazione!

/*
notate, poi, il diverso uso delle due funzioni: la prima (vera FUNZIONE in senso astratto) compare
sempre come "lato destro" di una qualche espressione: o a destra di un uguale, o come parametro di printf
che non assume la funzione stessa, come parametro, ma il suo risultato!!!
la seconda (tecnicamente una PROCEDURA) viene semplicemente richiamata nel flusso del programma
principale come "statement" a se' stante.
*/

printf("\n\n\n");


//Vediamo meglio la differenza fra parametri "per valore" e "per riferimento":
i = 10;
j =
20;
printf(
"All'inizio i e j valgono %d e %d\n",i,j);
doppio_quadrato(i,j);
printf(
"Dopo (fuori da) \"doppio_quadrato()\", i e j valgono %d e %d\n",i,j);
printf(
"E a e b, dopo (fuori da) \"doppio_quadrato()\", quanto valgono?!?\n");


printf(
"\n\n\n");

printf(
"Ciao!"); //NON METTO IL \n DENTRO PRINTF!
vaiAcapo(); //Notare che una funzione senza parametri vuole comunque le parentesi tonde ()
vaiAcapo();

int s;
s = somma(
1,1,1,1); //a,b,c,d tutte assegnate!
printf("somma 4 unita': %d",s);
vaiAcapo();
s = somma(
1,1,1); //manca un parametro: d assume il suo valore di default (stabilito sopra!)
printf("somma 3 unita': %d",s);
vaiAcapo();
s = somma(
1,1); //mancano due paramteri: c, d prendono il default
printf("somma 2 unita': %d",s);
vaiAcapo();
s = somma(
1); //b, c e d: default
printf("somma 1 unita': %d",s);
vaiAcapo();

printf(
"Prova dell'overload delle funzioni:\n");
stampa(
1);
float prova=1.01;
stampa(prova);



printf(
"prova fattoriale: dammi un numero intero (non esagerare: il fattoriale esplode subito!\n");
scanf(
"%d",&i);
do {
printf(
"Il fattoriale di %d e':%d\n",i,fattoriale(i));
printf(
"ancora? (dammi un numero negativo per uscire)\n");
scanf(
"%d",&i);
}
while (i>0);

printf(
"Bye!\n\n");
printf(
"\aPS\nCome mai il fattoriale di 14 e' minore del fattoriale di 13?\nTe ne eri accorto?\nProva!\n\n");
return 0;

}


2 commenti:

Alioth ha detto...

Grazie mille è un ottimo riassunto, utile per colmare le eventuali lacune...volevo solo avvertire che alcune frasi nel postarle sono state tagliate, come a volte capita incollando da DevC++... Giusto nel caso sia possibile rimediare!
Buona serata!!

hronir ha detto...

Meglio ora?
Buon lavoro!