Sei sulla pagina 1di 10

19/02/2019

UNIVERSITÀ DEGLI STUDI Puntatori


DEL SANNIO Benevento • Un puntatore è una variabile che contiene l’indirizzo di
DING un’altra variabile
DIPARTIMENTO DI INGEGNERIA

• I puntatori sono “type bound”, cioè ad ogni puntatore è


associato il tipo della variabile che può essere riferita
CORSO DI "PROGRAMMAZIONE I"
• Nella dichiarazione di un puntatore bisogna specificare un
asterisco (*) prima del nome della variabile puntatore
Prof. Franco FRATTOLILLO • Esempio:
Dipartimento di Ingegneria • int *pointer; // puntatore a intero
Università degli Studi del Sannio • char *punCar; // puntatore a carattere
• float *fltPnt; // puntatore a float
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 1
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 2

Inizializzazione di puntatori Puntatori ed array …


• Prima di poter usare un puntatore è necessario • Il nome di un array costituisce il puntatore alla testa
inizializzarlo, ovvero deve contenere l’indirizzo di un dell'array, cioè al primo elemento dell'array
oggetto • Pertanto, i puntatori ed gli array sono strettamente correlati,
• Per ottenere l’indirizzo di un oggetto si usa l’operatore al punto da poter essere interscambiati nel loro uso
unario & (referenziazione)
• int volume, *volPtr;
• Qualunque operazione eseguita usando un array ed un
• volPtr = &volume; indice può essere implementata usando i puntatori
• Il puntatore volPtr contiene ora l’indirizzo della variabile • Ad esempio:
volume • int arr[10], *arr_ptr, num;
• Per assegnare un valore all’oggetto puntato da volPtr • arr_ptr = &arr[0]; // equivale a scrivere arr_ptr = arr;
occorre utilizzare l’operatore di dereferenziazione *: • num = arr[0]; (num = *arr_ptr)
• *volPtr = 15;
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 3 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 4

1
19/02/2019

Puntatori ed array Differenze tra puntatori ed array

• Se arr_ptr punta ad un particolare elemento di un vettore, • Esiste una differenza sostanziale tra puntatore ed
allora arr_ptr+1 punterà all’elemento successivo del array:
vettore, arr_ptr-1 a quello precedente ed arr_ptr+i allo i- • il puntatore è comunque una variabile, mentre il nome di
esimo elemento successivo un array è una costante e riferisce una collezione di
oggetti di ugual tipo
• Il valore di una variabile di tipo array è, per definizione,
l’indirizzo dell’elemento zero dell'array stesso, per cui: • Ciò comporta che espressioni del tipo:
• arr_ptr = &arr[0] equivale a arr_ptr = arr • arr_ptr = arr ed arr_ptr++ sono legali, mentre
espressioni del tipo:
• È possibile riferire l’elemento i-esimo di un array a[i] nella arr = arr_ptr ed arr++ sono illegali !!
seguente forma: • Il nome di un array non può mai figurare alla sinistra di
un'assegnazione
*(a + i)
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 5 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 6

Aritmetica dei puntatori Aritmetica dei puntatori

• Sui puntatori sono lecite le seguenti operazioni: • Assegnamento di un puntatore con lo zero
• int *ptr1;
• assegnamento tra puntatori dello stesso tipo • ptr1 = 0; /*indica che ptr1 non punta a nulla */
• int *ptr1, *ptr2, val=1;
• ptr1 = &val;
• Confronto di un puntatore con lo zero
• int *ptr1;
• ptr2 = ptr1; /* ptr2 punta al valore 1 */ • ptr1 = 0;
• addizione e sottrazione tra puntatori ed interi • if (ptr1 == 0) printf(“Il puntatore non è inizializzato\n”);
• int *ptr, arr[10]; • Da notare che il C garantisce che lo zero non sia un
• ptr = &arr[0]; oppure ptr = arr; indirizzo valido per i dati, per cui il riferimento a zero si usa
• ptr = ptr + 4 /* punta al quinto elemento dell’array arr[4] */ spesso per indicare un puntatore non inizializzato
• ptr = ptr - 2 /* punta al terzo elemento dell’array arr[2] */ • spesso lo zero viene sostituito dalla costante simbolica NULL
definita nella libreria standard
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 7 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 8

2
19/02/2019

Aritmetica dei puntatori Cosa non è consentito ai puntatori


• Sottrazione tra due puntatori ad elementi di uno stesso • Non è ASSOLUTAMENTE consentito:
array • sommare, moltiplicare o dividere due puntatori
• int *ptr1, *ptr2, arr[10]; • sommare e sottrarre quantità float o double ad un
• ptr1 = ptr2 = arr; puntatore
• ptr1 += 10; /* punta fuori dall'array*/ • assegnare ad un puntatore di un tipo un puntatore di un
• ptr1 - ptr2 /* indica la lunghezza dell'array: 10 */ tipo differente, a meno di:
• Confronto tra puntatori ad elementi di uno stesso array • utilizzare un puntatore a void
• int *ptr1, *ptr2, arr[10]; • utilizzare l’operatore cast
• ptr1 = ptr2 = arr; • void *ptr1; int *ptr2; char *ptr3;
• ……
• ptr1 += 5; • ptr1 = ptr3;
• ptr1 > ptr2 /* è vero se ptr1 punta ad un elemento che • ptr2 = (int *) ptr1;
nell'array è successivo all’elemento puntato da ptr2 */
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 9 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 10

Esempi Esempi
• /* Dichiarazioni */ • /* azzera l’intero puntato da v_ptr */
• int v1, v2, *v_ptr; • *v_ptr = 0;
• /* moltiplica v2 per il valore puntato da v_ptr */ • /* incrementa di uno l’oggetto puntato da v_ptr */
• v1 = v2* (*v_ptr); • ++*v_ptr;
• /* somma v1, v2 e il contenuto di v_ptr */ • /* azzera l’intero puntato da v_ptr e incrementa il pointer
• v1 = v1+v2+ *v_ptr; di un intero */
• /* assegna a v2 il valore che si trova tre interi dopo v_ptr */ • *v_ptr++ = 0;
• v2 = *(v_ptr + 3); • /* incrementa il pointer e azzera l’intero puntato da v_ptr
*/
• /* incrementa di uno l’oggetto puntato da v_ptr*/
• (*v_ptr++) = 0;
• *v_ptr += 1;
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 11 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 12

3
19/02/2019

Esempi Puntatore a void


int *int_ptr, v_int, ar[10]; • Variabili di tipo void* contengono puntatori generici
float *float_ptr, v_float, ar_flt[10]; • contengono un riferimento ad un indirizzo di memoria,
int_ptr = ar; ma non l’informazione sul numero di byte utilizzati per
float_ptr = &ar_flt[9]; ogni oggetto e sul tipo di rappresentazione dell’oggetto
v_int = *(int_ptr+5); /* elemento ar[5] */ • queste informazioni si ottengono solo se si converte,
tramite casting, un puntatore void in un puntatore di un
v_int = *(int_ptr++ + 5); /* elemento a[5], int_ptr punta a tipo specifico
ar[1] */
v_float = *(--float_ptr – 5);
/* elemento ar_flt[3], float_ptr punta a ar_flt[8] */
*int_ptr = ar[7] // equivale a *int_ptr=*(ar+7);
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 13 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 14

Puntatori e stringhe di caratteri Inizializzazione di array e puntatori a caratteri


• Spesso vengono usati i puntatori a caratteri in luogo degli • Esempio di inizializzazione di array di caratteri:
array di caratteri (stringhe), perché il C non fornisce il tipo • char caratteri[4] = { ‘a’, ‘A’, ‘H’, ‘k’ };
predefinito stringa
• Esiste una differenza sostanziale tra array di caratteri e • Esempio di inizializzazione di stringa di caratteri:
puntatori a carattere. Ad esempio in: • char stringa_2[ ] = “MMMM”;
char *ptr_chr = “Salve mondo”; • è aggiunto il terminatore '\0'
• il compilatore non crea una copia della stringa costante • Ecco alcuni esempi di inizializzazione di puntatori a
“Salve mondo”, ma semplicemente crea un puntatore ad caratteri:
una locazione di memoria in cui risiede il primo carattere
della stringa costante • char c = ‘a’;
• Ciò significa che posso utilizzare il puntatore in modo che • char *carattere;
punti a qualcosa di diverso senza modificare il contenuto • carattere = &…..; *carattere = c;
della stringa costante • char *stringa_1 = “MMMM”;
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 15 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 16

4
19/02/2019

Puntatori come argomenti di funzioni Esempio


void swap(int x, int y) { main( ) {
• Se l’argomento di una funzione è una variabile int temp; int a = 3;
puntatore, il passaggio della variabile avviene per temp = x; int b = 5;
riferimento (per indirizzo), ossia la funzione chiamata x = y; swap(a, b);
sarà in grado di modificare il valore della variabile che y = temp; printf(“%d %d\n”, a, b);
} }
riceve
• Passaggio argomenti per valore: • Qual è l’output del programma ?
int numero; •3 5
… • Ciò accade perché la funzione swap agisce solo su una
square(numero); copia delle variabili a e b
• Per far sì che la funzione agisca sulle variabili stesse e non
• Passaggio per indirizzo: su delle copie, occorre passare gli indirizzi delle variabili
SquareR(&numero);
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 17 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 18

Esempio Esempio
void swap(int *x_ptr, int *y_ptr) { /* Codice della funzione main */
int temp;
temp = *x_ptr; void main( ) {
*x_ptr = *y_ptr; const int N = 100;
*y_ptr = temp; char linea[N]; int numero;
}
printf(“Inserisci una linea di testo\n”);
main( ) { LeggiLinea(linea, N);
int a = 3; int b = 5;
ContaDigit(linea, &numero);
swap(&a, &b);
printf(“%d %d\n”, a, b); printf(“La linea %s contiene %d numerici”, linea, numero);
} }
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 19 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 20

5
19/02/2019

Esempio Esempio
/* Legge una linea in input */ /*Conta il numero di cifre numeriche*/

void LeggiLinea (char *s , int max) { void ContaDigit (char *s, int *times) {
char c; int i = 0; *times = 0;
while ((c=getchar())!=‘\n’ && (i<max-1)) {
for( ; *s != ‘\0’ ; s++)
(*s) = c; s++; i++;
if ((*s >= ‘0’) && (*s <= ‘9’))
}
*s = ‘\0’; (*times)++;
} }
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 21 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 22

Esempi Array di puntatori


/* Versione con i puntatori della strlen */ • Un array di puntatori è un array i cui elementi sono
int strlen(char *s) { dei puntatori a variabili:
int n; • int *arr_int[10]
for (n = 0 ; *s != ‘\0’ ; s++) n++; • arr_int[0] contiene l’indirizzo della locazione di memoria
return n; contenente un valore intero
} • I puntatori a caratteri vengono usati per
/* Versione con i puntatori della cpy */ rappresentare il tipo stringa, che non risulta definito
void cpy (char *target, char *source) { nel linguaggio, e gli array di puntatori per
while((*target++ = *source++) != ‘\0’); rappresentare array di stringhe
} • char *arr_str[10]
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 23 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 24

6
19/02/2019

Array di puntatori a carattere Esempio

• Ad esempio: #include <stdio.h>


main( ) {
• char *term[100]; const int GIORNI=7;
• indica che gli elementi di term sono dei puntatori a char *giorni[GIORNI] = {“Lunedi”, “Martedi”, “Mercoledi”,
“Giovedi”, “Venerdi”, “Sabato”, “Domenica”};
carattere, cioe term[0] è l’indirizzo di un carattere
int i;
• Ad esempio, * term[0] = ‘c’ indica che il contenuto for( i=0; i<GIORNI; i++ ) printf(“%s\n”, giorni[i]);
della locazione di memoria puntata da term[0] è ‘c’; }
• term[7] = “Ciao” invece indica che il contenuto di Lunedi
term[7] è il puntatore alla stringa “Ciao” Martedi
...........
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 25 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 26

Esempio grafico Argomenti sulla linea di comando


• Il main è una funzione a cui è possibile passare degli
argomenti mediante i parametri in linea di comando
• Esiste una modalità ben precisa di passaggio dei
parametri. In particolare, la funzione main riceve due
Rappresentazione argomenti:
a vettore di • int main (int argc, char *argv[ ])
puntatori
• argc contiene il numero degli argomenti passati in
linea di comando, mentre argv è un vettore di
stringhe che contiene gli argomenti passati, uno per
stringa
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 27 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 28

7
19/02/2019

Argomenti sulla linea di comando Esempio


• Gli argomenti passati in linea di comando devono essere • Il programma echo stampa a video i parametri passati
separati da spazi bianchi
int main(int argc, char *argv[ ]) {
• Il nome del programma rappresenta il primo parametro
passato, per cui l’argomento argc vale sempre almeno 1 e int i;
l’elemento argv[0] contiene sempre il nome del for(i = 1; i < argc; ++i)
programma invocato
• Se argc vale 1, il main non ha argomenti, altrimenti argv[1] printf(“%s%s”, argv[i], (i < argc-1) ? “ ” : “”);
contiene il primo argomento ed argv[argc-1] contiene printf(“\n”);
l’ultimo argomento
• Si assume che il contenuto di argv[argc] sia un puntatore return 0;
nullo }
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 29 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 30

Puntatori a funzioni Uso dei puntatori a funzioni

• È possibile definire puntatori a funzioni • È possibile definire una variabile "puntatore a funzione"
• ciò che contraddistingue una funzione è la coppia di secondo la seguente sintassi:
parentesi tonde ( ) : func( ); • <return type> <(* name_ptr)> <(arg type, …)>
• le citazione del nome della funzione non seguite dalle • Ad esempio:
parentesi tonde viene interpretata dal compilatore come int (*function_ptr)(char *, float);
l’indirizzo della funzione • indica che function_ptr è un puntatore a funzione che
• Il puntatore ad una funzione può essere manipolato, ritorna un intero e che riceve due argomenti,
passato a funzioni ed inserito in un array rispettivamente di tipo char* e float
int abc(); • Poiché un puntatore a funzione è un oggetto che contiene
main() { l’indirizzo di una funzione, sarà possibile richiamare una
printf(“l’indirizzo di abc() è %u”, abc);
} funzione anche attraverso il suo riferimento a puntatore
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 31 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 32

8
19/02/2019

Esempio Dichiarazione
• Una volta conosciuto l’indirizzo di una funzione, la si può invocare • La dichiarazione "void (*abcpunt)( );" significa che abcpunt è
mediante il suo indirizzo una variabile puntatore ad una funzione che ritorna un void
• Esempio:
• Con l’assegnazione
void abc( ) {
abcpunt = abc;
printf (“A B C “);
} • si rende effettivo l’uso del puntatore
main( ) { • ATTENZIONE: L’uso delle parentesi è importante, in quanto
void (*abcpunt)( ); l’operatore * ha una precedenza inferiore alla coppia di
abcpunt = abc;
parentesi ()
abc( ); • La notazione
(*abcpunt)( ); void *abcpunt( );
} • per effetto della precedenza alle parentesi, porta alla
definizione di una funzione che restituisce un puntatore a void
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 33 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 34

Esempio Esempio
void main (int argc, char *argv[ ]) {
• Scrivere un programma "eleva" che riceve, tramite la int (*funz)(int); int i = 1;
eleva quadrato 4 cubo 3 qualsiasi 99
16 27 0
linea di comando, delle coppie <operazione, intero>, while (i<argc) {
dove operazione specifica il quadrato o il cubo, ed if (!strcmp(“quadrato”, argv[i]))
applica l’operazione all’intero; nel caso di errore funz = quadrato;
else if (!strcmp(“cubo”, argv[i]))
sull’operazione, il risultato è 0 funz = cubo;
else
int cubo(int x) { int quadrato(int x) { int nulla(int x) { funz = nulla;
return(x*x*x); return(x*x); return 0; printf(“%d ”, (*funz)(atoi(argv[i+1])));
} } } i += 2;
}
}
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 35 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 36

9
19/02/2019

Funzioni di manipolazione di stringhe strlen( )

• Alcune funzioni importanti per la manipolazione di • L’intestazione di questa funzione è:


stringhe: • int strlen(char *stringa);
• strlen() lunghezza di una stringa • La funzione restituisce il numero di caratteri che
• strcmp() confronto fra due stringhe compongono la stringa argomento, escluso il
• strcpy() copia di una stringa in un’altra carattere terminatore
La lunghezza è 16
• fanno parte della libreria standard string.h • Esempio:
• Esistono molte altre funzioni di manipolazione di main( ) {
stringhe in ambiente C char *stringa = “Esempio di frase”;
printf(“La lunghezza è %d”, strlen(stringa));
}
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 37 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 38

strcmp( ) strcpy( )
• La funzione strcmp ha una intestazione del tipo: • L’intestazione di strcpy è la seguente:
• int strcmp(char *str1, char *str2); • char* strcpy(char *str1, char *str2);
• Le due stringhe passate come argomento vengono • La stringa puntata dal secondo parametro viene ricopiata,
confrontate carattere per carattere carattere per carattere, nello spazio di memoria della prima
• se sono uguali, il valore restituito è 0, altrimenti la funzione stringa, restituendo il puntatore alla nuova stringa
restituisce la differenza numerica tra i primi due caratteri • Esempio:
responsabili della differenza tic tac, drin drin a b c
main( ) {
• Esempio: char stringa[20];
0 3
main( ) { strcpy(stringa, “tic tac, drin drin”);
printf(“ %d\t ”, strcmp(“salve”,“salve”)); printf(“%s ”, stringa);
printf(“ %d ”, strcmp(“valve”,“salve”)); printf(“%s”, strcpy(stringa,“a b c”));
} }
Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 39 Franco FRATTOLILLO – Dipartimento di Ingegneria – Università degli Studi del Sannio Corso di "Programmazione I" – Corso di Laurea in Ingegneria Informatica / ExAT 40

10

Potrebbero piacerti anche