240 likes | 406 Views
Esercizi. Puntatori, struct con campi puntatore, puntatori a struct, rapporto tra array e puntatori. FUNZIONI Passaggio di parametri per indirizzo, passaggio di array. La funzione swapInt() primo tentativo. #include <stdio.h> void swapInt ( int a1, int a2) { int tmp; tmp = a1;
E N D
Esercizi Puntatori, struct con campi puntatore, puntatori a struct,rapporto tra array e puntatori.FUNZIONIPassaggio di parametri per indirizzo, passaggio di array.
La funzione swapInt()primo tentativo • #include <stdio.h> • void swapInt (int a1, int a2) • { int tmp; tmp = a1; a1 = a2; a2 = tmp; • } • void main () • { int n1 = 3, n2 = 4; swapInt (n1, n2); printf ("n1=%d,n2=%d",n1,n2); • } • Passando i parametri per valore, il risultato non è quello atteso! • wrongSwapInt() scambia il contenuto delle variabili localia1 e a2 • Nessun effetto sulle variabili n1 e n2
Parametri per indirizzo • Definizione:void funzione (float *p1, char *p2){ *p1 = 1.125; *p2 = 'z';} • Chiamata:float x;char y;funzione (&x, &y); • I parametri formali puntano ai parametri attuali • Le modifiche effettuate sui parametri formali sono in realtà eseguite sui parametri attuali.
La funzione swapInt()versione corretta • #include <stdio.h> • void swapInt (int *p1, int *p2) • { int tmp; tmp = *p1; *p1 = *p2; *p2 = tmp; • } • void main () • { int n1 = 3, n2 = 4; swapInt (&n1, &n2); printf ("n1=%d,n2=%d",n1,n2); • }
Indovina numero • Scrivere un programma che, utilizzando le funzioni, implementi un gioco nel quale l’utente deve indovinareun numero segreto entro un massimo di tentativi • La funzione indovinaNumero(): • Permette di inserire un numero • Confronta il numero inserito con quello da individuare e visualizza il messaggo “troppo grande” o “troppo piccolo” • Se il numero inserito è corretto, la funzione ritorna vero, altrimenti ricomincia il ciclo (un parametro fissa il numero max di tentativi) • Se, esauriti i tentativi permessi, il numero segreto non è stato individuato, la funzione ritorna falso.
Indovina numero • #include <stdio.h> • typedef enum {falso, vero} Booleano; • Booleano indovinaNumero (unsigned int *ripetiz,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++;
Indovina numero 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; • }
Indovina numero • 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); • } • }
f a b c Puntatore a struct • Due modi equivalenti di accedere ad un campo di una struct, usando un puntatore: • Esempio, evendo questo tipo strutturato:typedef struct{int a;int b;int c;} MioTipo;MioTipo *f; • Accedo al campo a attraverso *f usando: • (*f).a oppure • f->a
Area 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.
Area • #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; .
Area • 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; • } .
Area • 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", figura.area); • } • } .
Richiamo: array e puntatori • Il nome dell’array, usato senza le parentesi, rappresenta l’indirizzo in memoria della prima cella(ovvero, un puntatore ad essa) • L’indirizzo non può essere modificato (ovvero, il nome rappresenta un puntatore costante) • E’ possibile definire un puntatore ed usarlo come array! • int vettA[4], vettB[4]; • int *pIntero; • … • pIntero = vettA; /* Corretto: pIntero punta a vettA */ • pIntero[1] = 3; /* Corretto: pIntero come array */ • vettB = vettA; /* Errore di compilazione! */ • vettA = pIntero; /* Errore di compilazione! */
Passaggio per indirizzo! Parametri array • Sfrutta le caratteristiche di puntatori e array • Definizione:void funzione (float *v1, char *v2){ v1[3] = 1.125; /* v1 come array */ v2[15] = 'z'; /* v2 come array */} • Chiamata:float a[10];char b[20];funzione (a, b); /*senza & perché nome è puntatore*/ • Definizione equivalente: void funzione (float v1[], char v2[])
Media e varianza • 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.
Media e varianza • #include <stdio.h> • #include <math.h> • void leggi (float vet[], unsigned int lungh) • { • unsigned int i; • for (i = 0; i < lungh; i++) • { • printf ("Numero: "); • scanf ("%f", &vet[i]); • } • } • Non si usa return perché vet è passato per indirizzo.
Media e varianza • 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; • } .
Media e varianza • 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); • } • for (i = 0; i < lungh; i++) • { • v = v + vet[i]; • } • return v / (lungh – 1); • } .
Media e varianza • void scrivi (float vet[], unsigned int lungh,float med, float var) • { • unsigned int i; • for (i = 0; i < lungh; i++) • { • printf ("%f\n", vet[i]); • } • printf ("Media: %f, varianza: %f", med, var); • }
Media e varianza • void main() • { • const unsigned int MAX = 3; • float array[MAX]; • float m, v; • leggi (array, MAX); /* non uso & */ • m = media (array, MAX); • v = varianza (array, MAX, m); • scrivi (array, MAX, m, v); • } Side effect su array Cosa visualizza la funzione scrivi() ? • Non funziona! Serve un altro vettore in cui salvare array prima che venga modificato.
Media e varianza • void main() • { • const unsigned int MAX = 3; • float array[MAX], copia[MAX]; • float m, v; • unsigned int i; • leggi (array, MAX); /* non uso & */ • m = media (array, MAX); • for (i = 0; i < MAX; i++) • { • copia[i] = array[i]; • } • v = varianza (array, MAX, m); • scrivi (copia, MAX, m, v); • } Side effect su array Adesso scrivi() stampa il vettore corretto
x w 5 6 a 7 8 b y a 7 8 b Copia di struct con campi puntatore Se la struct contiene dei puntatori:typedef struct{int *a;int b[2];}Tipo;int w[2]={5,6};Tipo x, y;x.a = w;x.b[0] = 7;x.b[1] = 8;y = x; • Avrò un alias (x.a e y.a puntano alla stessa variabile).
Riassumendo: quando usare… • Passaggio parametri per copia (o per valore): • La funzione deve ritornare un solo valore (e quindi basta usare il return); i parametri sono “parametri di input” • Passaggio parametri per indirizzo: • La funzione deve ritornare più valori (e quindi non basta usare il return) e non voglio usare variabili globali;i parametri sono “parametri di input/output” • Caso particolare: gli array • Il nome dell’array rappresenta l’indirizzo in memoria della prima cella • Passando l’array come parametro, ne passo in realtà l’indirizzo • Quindi, gli array sono sempre passati per indirizzo e non per copia (possibili side effect).