Politecnico di Milano Esercizi Puntatori, struct con campi puntatore, puntatori a struct, rapporto tra array e puntatori. FUNZIONI Passaggio di parametri per indirizzo, passaggio di array. #include <stdio.h> La funzione swapint() primo tentativo 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 locali a1 e a2 Nessun effetto sulle variabili n1 e n2-2 - 1
Definizione: Parametri per indirizzo 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. - 3 - #include <stdio.h> La funzione swapint() versione corretta 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); - 4-2
Indovina numero Scrivere un programma che, utilizzando le funzioni, implementi un gioco nel quale l utente deve indovinare un 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. - 5 - #include <stdio.h> Indovina numero 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++; - 6-3
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; - 7 - 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); - 8-4
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 f a b c - 9 - 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. - 10-5
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;. - 11 - 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;. - 12-6
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); - 13 -. 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! */ - 14-7
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[]) Passaggio per indirizzo! - 15 - 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. - 16-8
#include <stdio.h> #include <math.h> Media e varianza 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. - 17 - 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;. - 18-9
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);. - 19 - 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); - 20-10
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. - 21 - 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]; Side effect su array v = varianza (array, MAX, m); scrivi (copia, MAX, m, v); Adesso scrivi() stampa il vettore corretto - 22-11
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; x y a b 7 8 a b 7 8 w 5 6 Avrò un alias (x.a e y.a puntano alla stessa variabile). - 23 - 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). - 24-12