Funzioni: passaggio di parametri per indirizzo; puntatori in C
Funzioni: passaggio di parametri per indirizzo; puntatori
Scambio
Testo
Scrivere
una funzione in grado di scambiare il contenuto delle due variabili
intere passate come parametri.
Implementazione
#include
<stdio.h>
void
swapInt (int
*p1, int
*p2)
{
int
tmp;
tmp
= *p1;
*p1
= *p2;
*p2
= tmp;
}
void
main ()
{
int
n1, n2;
printf
("Inserisci
i due numeri interi: ");
scanf
("%d
%d",
&n1, &n2);
swapInt
(&n1, &n2);
printf
("n1=%d,
n2=%d",
n1, n2);
}
Leggi intero
Testo
Scrivere
una funzione in grado di leggere un numero intero inserito
dall’utente, controllando che rientri in un intervallo predefinito.
Implementazione
#include
<stdio.h>
void
leggiInt (int
*pInt, int
limInf, int
limSup)
{
int
dato;
do
{
scanf
("%d",
&dato);
}
while
(dato < limInf || dato > limSup);
*pInt
= dato;
}
void
main ()
{
const
int
LIMINF = -20,
LIMSUP = 30;
int
n;
printf
("Inserisci
numero da %d a %d: ",
LIMINF, LIMSUP);
leggiInt
(&n, LIMINF, LIMSUP);
printf
("n=%d",
n);
}
Nota: in questo
caso, poiché la funzione ha bisogno di restituire
un solo dato (il numero inserito dall’utente), avrei potuto
sfruttare il meccanismo del valore di ritorno (il return).
Ecco la versione che passa tutti i parametri per copia e usa il
meccanismo del valore di ritorno.
#include
<stdio.h>
int
leggiInt (int
limInf, int
limSup)
{
int
dato;
do
{
scanf
("%d",
&dato);
}
while
(dato < limInf || dato > limSup);
return
dato;
}
int
main ()
{
const
int
LIMINF = -20,
LIMSUP = 30;
int
n;
printf
("Inserisci
numero da %d a %d: ",
LIMINF, LIMSUP);
n
= leggiInt
(LIMINF, LIMSUP);
printf
("n=%d",
n);
}
Indovina numero
Testo
Scrivere un
programma che, utilizzando le funzioni, implementi il gioco nel quale
l’utente deve indovinare un numero
segreto entro un numero massimo di tentativi.
La funzione
indovinaNumero():
- Permette di inserire un numero
- Confronta il numero da individuare con quello inserito e visualizza il messaggo “troppo grande” o “troppo piccolo”
- Se il numero inserito è corretto, la funzione ritorna vero, altrimenti ricomincia il ciclo per un numero di volte fissato da un parametro
- Se, esauriti i tentativi permessi, il numero segreto non è stato individuato, la funzione ritorna falso.
Implementazione
#include
<stdio.h>
typedef
enum {falso,
vero}
Booleano;
Booleano
indovinaNumero (unsigned
int *ripetiz,
unsigned int maxRipetiz,
unsigned long int numero)
unsigned int maxRipetiz,
unsigned long int numero)
{
unsigned
long int
tentativo;
unsigned
int
n = 0;
Booleano
trovato = falso;
do
{
printf
("Tentativo
%u: ",
n + 1);
scanf
("%lu",
&tentativo);
n++;
if
(tentativo == numero)
{
trovato
= vero;
}
else
if
(tentativo > numero)
{
printf
("Troppo
grande!\n");
}
else
{
printf
("Troppo
piccolo!\n");
}
}while
(!trovato && n < maxRipetiz);
*ripetiz
= n;
return
trovato;
}
void
main()
{
const
unsigned long int
NUMERO = 999,
MAXRIP = 3;
Booleano
indovinato;
unsigned
int
nRip;
indovinato
= indovinaNumero (&nRip,MAXRIP,NUMERO);
if
(!indovinato)
{
printf
("Tentativi
esauriti");
}
else
{
printf
("Ok
al tentativo %u",
nRip);
}
}
Area
Testo
Scrivere un programma che, sfruttando
le funzioni, permetta di calcolare l’area di un cerchio o di un
quadrato.
L’utente inserisce
un numero, dichiarando
se si tratta del raggio di un cerchio o del lato di un quadrato. Se
l’utente inserisce un numero negativo viene visualizzato un errore,
altrimenti il sistema calcola l’area in modo appropriato.
Implementazione
#include
<stdio.h>
#define
PI 3.1415
#define
NUMERO_NEGATIVO -1;
#define
NO_ERRORE 0;
typedef
enum
{quadrato,
cerchio}
Forma;
typedef
struct
{
Forma
qualeForma;
float
a;
float
area;
}
InfoFigura;
int
calcolaArea (InfoFigura *f)
{
if
((*f).a < 0)
{
return
NUMERO_NEGATIVO;
}
if
((*f).qualeForma == quadrato)
{
f->area
= f->a * f->a;
}
else
{
f->area
= f->a * f->a * PI;
}
return
NO_ERRORE;
}
void
main()
{
InfoFigura
figura;
int
errore;
printf
("Figura
(0=quadrato, 1=cerchio)? ");
scanf
("%u",
&figura.qualeForma);
printf
("lato
o raggio: ");
scanf
("%f",
&figura.a);
errore
= calcolaArea (&figura);
if
(errore == NO_ERRORE)
{
printf
("Area:
%f\n",
figura.area);
}
else
{
printf
("Errore!\n");
}
}
Notare le due
sintassi equivalenti per accedere ai campi di una struct attraverso
un puntatore: (*f).a
f->a
Nella soluzione
dell’esercizio sono state utilizzate entrambe le sintassi ma in
genere è bene sceglierne una e usare sempre quella.
Funzioni: parametri array
Media e varianza
Testo
- Scrivere un programma che, utilizzando le funzioni, calcoli la media e la varianza di un array di numeri reali
- Utilizzare le funzioni:
- leggi(): permette di inserire il vettore di numeri
- media(): calcola e ritorna la media
- varianza(): calcola e ritorna la varianza
- scrivi(): visualizza il vettore, la media e la varianza
Implementazione
#include
<stdio.h>
#include
<math.h>
void
leggi (float
vet[], unsigned
int
lungh);
float
media (float
vet[], unsigned
int
lungh);
float
varianza (float
vet[], unsigned
int
lungh, float
media);
void
scrivi (float
vet[], unsigned
int
lungh, float
media,
float var);
float var);
void
main()
{
const
unsigned int MAX = 3;
float
array[MAX], copia[MAX];
float
m, v;
int
i;
leggi
(array, MAX);
m
= media (array, MAX);
for
(i = 0; i < MAX; i++) /*
Per rimediare al side effect */
{
/*
che varianza() avrà su array */
copia[i] = array[i];
}
v
= varianza (array, MAX, m);
scrivi
(copia, MAX, m, v);
}
void
leggi (float
vet[], unsigned
int
lungh)
{
unsigned
int
i;
for
(i = 0;
i < lungh; i++)
{
printf
("Numero:
");
scanf
("%f",
&vet[i]);
}
}
float
media (float
vet[], unsigned
int
lungh)
{
unsigned
int
i;
float
m = 0;
for
(i = 0;
i < lungh; i++)
{
m
= m + vet[i];
}
return
m / lungh;
}
/*
Dopo la chiamata a questa funzione, cosa conterrà il vettore passato
come parametro attuale? */
float
varianza (float
vet[], unsigned
int
lungh, float
media)
{
unsigned
int
i;
float
v = 0;
for
(i = 0;
i < lungh; i++)
{
vet[i]
= pow (vet[i] - media, 2.0);
/*
Modifico vet[]*/
}
for
(i = 0;
i < lungh; i++)
{
v
= v + vet[i];
}
return
v / (lungh – 1);
}
void
scrivi (float
vet[], unsigned
int
lungh, float
med,
float var)
float var)
{
unsigned
int
i;
for
(i = 0;
i < lungh; i++)
{
printf
("%f\n",
vet[i]);
}
printf
("Media:
%f, varianza: %f",
med, var);
}
In questo caso,
conoscendo il side effect che varianza()
ha su array,
abbiamo preso delle “contromisure” nel main().
In generale però è
bene cercare di ridurre al minimo i side effect. Quindi, una
soluzione migliore si può trovare se è possibile modificare
l’algoritmo della funzione che provoca il side effect. Nel caso
particolare di questo esercizio, è possibile modificare varianza()
in modo che non provochi effetti indesiderati su array.
Vediamo le nuove versioni di varianza()
e del main():
/*
Versione che non provoca side effect */
float
varianza (float
vet[], unsigned
int
lungh, float
media)
{
unsigned
int
i;
float
v = 0;
for
(i = 0;
i < lungh; i++)
{
v
= v + pow (vet[i] - media, 2.0);/*Non
modifico vet[]*/
}
return
v / (lungh – 1);
}
void
main()
{
const
unsigned int MAX = 3;
float
array[MAX];
float
m, v;
int
i;
leggi
(array, MAX);
m
= media (array, MAX);
v
= varianza (array, MAX, m); /*
Adesso non ho side effect */
scrivi
(array, MAX, m, v);
}
Si tenga presente
che in generale non è possibile eliminare
questo tipo di side effect perché gli array sono sempre
passati per indirizzo e quindi qualsiasi modifica effettuata
all’interno della funzione si riflette all’esterno.
fonte: http://corsi.dei.polimi.it/infoA/
Link per esercizi sulle funzioni: http://lia.deis.unibo.it/Courses/FondT-0809-ELT/materiale/esercizi.funzioni.pdf
Link per esercizi sulle funzioni: http://lia.deis.unibo.it/Courses/FondT-0809-ELT/materiale/esercizi.funzioni.pdf
Commenti
Posta un commento