2000 prentice hall, inc. all rights reserved. capitolo 7 (deitel) i puntatori sommario 7.1 -...

24
2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori 7.3 - Operatori per i puntatori 7.4 - Passare alle funzioni i parametri per riferimento 7.5 - Usare il qualificatore const con i puntatori 7.6 - L’ordinamento Bubble Sort tramite una chiamata per riferimento 7.7 - Le espressioni con i puntatori e l’aritmetica dei puntatori 7.8 - La relazione tra puntatori e vettori 7.9 - Vettori di puntatori 7.10 - Caso di studio: simulare un mescolatore/distributore di carte

Upload: bettina-rocca

Post on 02-May-2015

217 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

Capitolo 7 (Deitel) I puntatori

Sommario

7.1 - Introduzione7.2 - Dichiarare e inizializzare i puntatori7.3 - Operatori per i puntatori7.4 - Passare alle funzioni i parametri per riferimento7.5 - Usare il qualificatore const con i puntatori7.6 - L’ordinamento Bubble Sort tramite una chiamata per riferimento 7.7 - Le espressioni con i puntatori e l’aritmetica dei puntatori7.8 - La relazione tra puntatori e vettori7.9 - Vettori di puntatori 7.10 - Caso di studio: simulare un mescolatore/distributore di carte

Page 2: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.1 - Introduzione

• I puntatori – Sono molto potenti, ma anche difficili da padroneggiare– Consentono il passaggio per riferimento dei parametri alle funzioni (che

di default passerebbero invece per valore)– Sono strettamente correlati a vettori e stringhe

• Le variabili puntatori– Non contengono valori specifici (riferimento diretto)– Contengono indirizzi di memoria di altre variabili, che a loro volta

contengono/immagazzinano dei valori specifici (riferimento indiretto)

– Sono comunque variabili il cui valore sta dentro una cella di memoria– Deriferimento: operazione tramite cui si fa riferimento (si accede) al

valore di una variabile per mezzo del un puntatore che punta ad essa• L’operazione restituisce il valore della cella puntata (nell’esempio sopra dà 7)

count

7

count

7

countPtr

Page 3: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.2 - Dichiarare e inizializzare i puntatori

• Dichiarazioni di puntatori– Si possono dichiarare puntatori a qualsiasi tipo di dato, ma va sempre

specificato quale sia tale tipo• Non ha senso quindi parlare di tipo puntatore, non è un tipo di variabile• E’ il classico esempio di “tipo derivato”• I tipi di dato “puntabili” sono i soliti: char, int, float, double, ecc..

– Per dichiarare una variabile puntatore si usa il simbolo *int *myPtr;

• Dichiara un puntatore myPtr ad int (puntatore di tipo int *)• Può puntare solo ad una cella di memoria che contiene una variabile intera

– Per dichiarare più puntatori in una riga servono molteplici * int *myPtr1, *myPtr2;

– I puntatori si possono inizializzare con 0, NULL, o con un indirizzo• Se si usa 0 o NULL, non fanno riferimento a nessun dato (si preferisce NULL)

• Si può anche inizializzare un puntatore con un indirizzo di una variabile non ancora inizializzata

Page 4: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.3 - Operatori per i puntatori (1/4)

• Operatore di indirizzo: &– Restituisce l’indirizzo di memoria del suo operando, che è una variabile– L’operando può essere un puntatore ma non una costante o un’espressione

int y = 5;int *yPtr; yPtr = &y; //yPtr assume l’indirizzo di y

• Da questo punto in poi yPtr punta a y e quindi yPtr e &y sono alias

– Nota: Il “tipo” pointer non è compatibile con gli altri, quindi assegnamenti come double x = yptr non si possono fare, così come double x=&y

yPtr

y5

yPtr

500000 600000

y

600000 5

L’indirizzo di y è il valore yPtr

Page 5: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.3 - Operatori per i puntatori (2/4)

• Operatore di deriferimento: *– Restituisce il valore contenuto nella variabile puntata dal suo operando,

che è necessariamente una variabile puntatore (mai una costante)

– Di fatto “variabile puntata” e “deriferimento del puntatore” sono alias• Usare *yPtr o y in una istruzione è indifferente (perché yPtr punta a y)

– * può quindi essere usato per eseguire assegnamenti • Essendo un alias, il deriferimento del puntatore alla variabile da assegnare può

essere sostituito alla variabile stessa*yPtr = 7; //aggiorna y a 7, come y=7x = *yPtr; //aggiorna x a 7, come x=y

• Specifica di conversione %p– Serve a stampare a video un indirizzo di memoria, convertito in un formato

che generalmente è un intero esadecimale– Essendo alias, sia &y che yPtr sono quindi stampabili in tale modo

printf(“Indirizzo di y: %p”,&y); //Stampa 001F2BB4printf(“Valore di yPtr: %p”,yPtr); //Stampa 001F2BB4

Page 6: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.3 - Operatori per i puntatori (3/4)

• * e & sono operatori inversi– Se combinati in cascata in qualsiasi ordine si annullano a vicenda

– Se yPtr = &y allora *&yPtr <-> &*yPtr <-> yPtr

• *&yPtr é alias di yPtr– Sapendo che l’indirizzo di qualsiasi variabile coincide con un puntatore a

tale variabile e che questo vale anche per le variabili puntatori stesse

[* (&yPtr)] <-> [* (indirizzo di yPtr)] <-> [* (puntatore a yPtr)] <-> [yPtr]

• &*yPtr é alias di yPtr[& (*yPtr)] <-> [& (y)] <-> [indirizzo di y]

<-> [puntatore a y] <-> [yPtr]

Page 7: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.3 - Operatori per i puntatori (4/4)

1 /* Fig. 7.4: fig07_04.c – Uso degli operatori & e * */

2 #include <stdio.h>

3

4 int main(){5 int a; /* è un intero */6 int *aPtr; /* è un puntatore ad un intero */78 a = 7;9 aPtr = &a; /* Assegna ad aPtr l’indirizzo di a ->Punta ad a */10 printf( "L’indirizzo di a è %p" 11 "\nIl valore di aPtr è %p", &a, aPtr );

12 printf( "\n\nIl valore di a è %d" 13 "\nIl valore di *aPtr è %d", a, *aPtr );14 printf( "\n\nDimostrazione che * e & sono operatori inversi.\n "15 "&*aPtr = %p\n*&aPtr = %p\n", &*aPtr, *&aPtr ); 16 return 0;17 }

1. Dichiara le variabili

2. Inizializza le variabili

3. Stampa le varie casistiche

Visualizzazionedel programma

L’indirizzo di a è 0012FF88Il valore di aPtr è 0012FF88Il valore di a è 7Il valore di *aPtr è 7Dimostrazione che * e & sono operatori inversi.&*aPtr = 0012FF88*&aPtr = 0012FF88

L’indirizzo di a è il valore di aPtr.

L’operatore * restituisce un alias della variabile puntata dall’operando. aPtr punta ad a, quindi *aPtr è alias di a.

Fa notare come * e & siano inverse

Page 8: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.4 - Passare alle funzionii parametri per riferimento (1/2)

• Si passano/usano i puntatori come parametri– Permettono di accedere al valore reale in memoria delle variabili e quindi

alla fine della funzione ogni modifica ai parametri ha effetto sugli originali– Si passa alla funzione l’indirizzo degli argomenti (ogni variabile che è un

parametro attuale da inviare alla funzione) usando l’operatore &– Nel prototipo/definizione della funzione i parametri formali sono puntatori– I vettori non sono passati con & perché il loro nome è già un puntatore

• Passare come parametro attuale vett equivale a passare &vett[0], sono alias• Avere come parametro formale int vett[] equivale ad avere int *vett, sono alias

• Dentro la definizione di funzione, l’operatore * – Si usa per dereferenziare il puntatore (parametro formale) e ottenere così

un alias della variabile passata per indirizzo da usare poi nella funzionevoid raddoppia(int *numero){ //idem per il prototipo in

*numero = 2 * (*numero); //cui si può usare (int *) } //senza il nome del

puntatore• *numero è un alias della variabile passata e come essa contiene quindi un

intero, mentre numero punta alla variabile (contiene un indirizzo di memoria)• Nel caso di vettori, invece, dentro la definizione di funzione * non va usato

Page 9: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.4 - Passare alle funzionii parametri per riferimento (2/2)

1 /* Fig. 7.7: fig07_07.c

2 Eleva al cubo una variabile usando una chiamata per riferimento 3 #include <stdio.h>

4

5 void cuboPerRiferimento( int * ); /* prototipo */

6

7 int main(){8 int numero = 5;

9

10 printf( “Il valore originale del numero è %d", numero );

11 cuboPerRiferimento( &numero );

12 printf( "\nIl nuovo valore del numero è %d\n", numero );13 return 0;

14 }

15

16 void cuboPerRiferimento( int *nPtr ){

17 *nPtr = *nPtr * *nPtr * *nPtr;/* eleva al cubo number nel main */

18 }

Il valore originale del numero è 5Il nuovo valore del numero è 125

1. Prototipo – prende un puntatore a int

2. Chiama la funzione passando “number” per riferimento

3. Definisce la funzione che ha per parametro formale un puntatore

Visualizzazione del programma

Dentro cubeByReference, è usato *nPtr come alias di number.

Si passa l’indirizzo di number - cubeByReference aspetta un puntatore (indirizzo di variabile).Così facendo non serve più che lafunzione ritorni qualcosa.

Page 10: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.5 - Usare il qualificatore const con i puntatori (1/2)

• Qualificatore const– Se anteposto a una variabile nella dichiarazione, essa va inizializzata in

contemporanea alla dichiarazione ed il suo valore non può essere cambiato

– È buona norma usare const per le variabili di una funzione se per certo questa non ha mai bisogno di cambiarne il valore in itinere

– Tentare poi di cambiare una const genera un errore di compilazione

• Puntatori const– Puntano sempre alla stessa locazione di memoria, essa non può cambiare

– Devono essere inizializzati per forza quando vengono dichiarati

int *const myPtr = &x;• Puntatore costante ad int: x può essere modificata, *Ptr no!

const int *myPtr = &x;• Puntatore (non const) a const int: x non può essere cambiata, *Ptr si!

const int *const Ptr = &x;• Puntatore costante a const int: né x nè *Ptr possono essere cambiati

Page 11: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.5 - Usare il qualificatore const con i puntatori (2/2)

1 /* Fig. 7.13: fig07_13.c

2 Tentare di modificare un puntatore costante a dati variabili */

3 #include <stdio.h>

4

5 int main(){

6 int x, y;

7

8 int * const ptr = &x; /* ptr è un puntatore costante a int.

9 Un intero può essere modificato tramite

10 ptr, ma ptr punta sempre alla stessa

11 locazione di memoria. */

12 *ptr = 7;

13 ptr = &y;

14 return 0;

15 }

FIG07_13.c:Error E2024 FIG07_13.c 16: Cannot modify a const object in function main*** 1 errors in Compile ***

1. Dichiara le variabili

2. Dichiara il puntatore const ad int

3. Cambia *ptr (che è alias di x)

4. Tenta di cambiare l’indirizzo in ptr

Visualizzazione del programma

cambiare *ptr è permesso perchè x non è una costante

Cambiare ptr è e dà un errore - ptr è un puntatore costante

Page 12: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

• L’ordinamento a bolle usando i puntatori– Ordina gli elementi due a due per ogni passata, come al solito– Usa la funzione swap fare ordinamenti parziali due a due quando serve– La swap deve ricevere in input gli indirizzi (con &) degli elementi del

vettore da scambiare per farlo direttamente nell’ambiente del chiamante• Gli elementi del vettore sono quindi passati a swap per riferimento

– Usando i puntatori e l’operatore *, swap può ricevere i due elementi del vettore da riordinare e scambiarli direttamente anche nel vettore esterno

• Non necessita di ricevere il vettore, ma solo i due elementi da scambiare• Col passaggio per valore non si potrebbe delegare lo scambio ad una funzione

esterna, l’alternativa è fare anche lo scambio dentro la funzione bubbleSort

• PseudocodiceInizializza il vettore

Stampa i dati nell’ordine originaleChiama la funzione per l’ordinamento a bolle

Stampa il vettore ordinatoDefinisce l’ordinamento a bolle

7.6 - L’ordinamento Bubble Sort tramite

una chiamata per riferimento (1/3)

Page 13: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.6 - L’ordinamento Bubble Sort tramite

una chiamata per riferimento (2/3)1 /* Fig. 7.15: fig07_15.c2 Questo programma inserisce dei valori in un vettore, ordina i3 valori in modo ascendente, e visualizza il vettore risultante. */4 #include <stdio.h>5 #define SIZE 106 void bubbleSort( int *, const int );78 int main(){

9 int i, a[ SIZE ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 };

1011 printf( “Elementi nell’ordine originale\n" );

12 for ( i = 0; i < SIZE; i++ ) printf( "%4d", a[ i ] );

13 bubbleSort( a, SIZE ); /* ordina il vettore */14 printf( "\nElementi in ordine crescente\n" );

15 for ( i = 0; i < SIZE; i++ ) printf( "%4d", a[ i ] );

16 printf( "\n" );16 return 0;17 }18

1. Inizializza il vettore

2. Stampa il vettore originale

3. Invoca bubbleSort

4. Stampa il vettore ordinato

bubbleSort di fatto si aspetta di riceve un puntatore. Non a caso, perchè il nome di un vettore è un puntatore che contiene l’indirizzo del primo elemento del vettore

Page 14: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

21 int pass, j;

22 for ( pass = 0; pass < size - 1; pass++ )

23 for ( j = 0; j < size - 1; j++ )

24 if ( vettore[ j ] > vettore[ j + 1 ] )

25 swap( &vettore[ j ], &vettore[ j + 1 ] );

26 }

27

28 void swap( int *elemento1Ptr, int *elemento2Ptr ){

29 int temp = *elemento1Ptr;

30 *elemento1Ptr = *elemento2Ptr;

31 *elemento2Ptr = temp;

32 }

19 void bubbleSort( int *vettore, const int size ){

20 void swap( int *, int * );5. Definizioni delle funzioni

Visualizzazione del programma

Elementi nell’ordine originale 2 6 4 8 10 12 89 68 45 37Elementi in ordine crescente 2 4 6 8 10 12 37 45 68 89

7.6 - L’ordinamento Bubble Sort tramite

una chiamata per riferimento (3/3)

Dentro la swap uso i puntatori con deferimento per lavorare su alias delle variabili originali perché tali puntatori puntano proprio alle variabili passate.

I singoli elementi di un vettore sono come variabili comuni e quindi passarli per riferimento necessita l’uso di &

Page 15: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.7 - Le espressioni con i puntatori e l’aritmetica dei puntatori (1/3)

• Le operazioni aritmetiche possono agire anche su puntatori– Incrementare/decrementare del puntatore (++ o --)

– Aggiungere/togliere un intero al puntatore ( + o += , - o -=)

– I puntatori possono essere sottratti gli uni dagli altri– Tuttavia, esse hanno senso solo se eseguite su un vettore perché solo in tal

caso si è certi di operare sempre su dati in celle di memoria consecutive

• Somma di un intero ad un puntatore e incremento– Dato un vettore di 5 elementi int su una macchina che usa 4 byte per

ogni intero, se vPtr punta al primo elemento v[0] con locazione 3000 vPtr = 3000 vPtr+=2 pone vPtr = 3008 e quindi da ora

vPtr punta a v[2] (l’elemento con indice incrementato di 2)

 

Variabile puntatore vPtr

v[0] v[1] v[2] v[4]v[3]

3000 3004 3008 3012 3016Locazione

Page 16: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

• Somma di un intero ad un puntatore a vettore– Dopo aver dichiarato un puntatore vPtr al vettore v[], essi diventano alias– Inizialmente vPtr punta a v[0], ma in seguito ad un’istruzione “vPtr+=j;”

• vPtr punterà sempre a v[j], perché conterrà l’indirizzo &v[0]+j*(byte_rapp_tipo)– Ecco perchè l’espressione *(vPtr+j) restituisce sempre un alias di v[j]– L’esito di tale operazione è comunque indipendente dal numero di byte con

cui il calcolatore memorizza il tipo del vettore puntato dal puntatore– Per conoscere la rappresentazione interna di tale tipo si può usare sizeof

• La funzione sizeof– Ritorna la dimensione del suo operando in bytes– Se l’operando è un vettore, ritorna la dimensione in byte di un elemento

moltiplicata per il numero totale di elementi (dimensione del vettore)int mioArray[10];printf( "%d", sizeof( mioArray ) );• Se sizeof(int) restituisce 4 bytes, allora la printf stamperà 40

– Gli operandi di sizeof possono essere nomi di variabili, nomi di tipi (come sopra) o valori costanti

7.7 - Le espressioni con i puntatori e l’aritmetica dei puntatori (2/3)

Page 17: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

• Sottrazione di puntatori– Restituisce il numero degli elementi compresi tra quelli puntati dai due

puntatori (ovvero in pratica tra i due indici del vettore)Dato vPtr2 = &v[2] e vPtr1 = &v[0] vPtr2 – vPtr1 dà 2

• Confronto di puntatori ( <, ==, > )– Si usa per riconoscere quale puntatore punta all’elemento del vettore con

l’indice più alto o per verificare se un puntatore punta a 0(se è NULL)

• Solo se sono dello stesso tipo, i puntatori possono essere assegnati uno all’altro– Se non fossero dello stesso tipo, si deve fare un cast per convertire di

forza il tipo di quello a destra dell’assegnamento nel tipo di quello di sinistra

– Unica eccezione: il puntatore a void (con tipo void *)• E’ un puntatore generico, rappresenta qualsiasi tipo, per cui ad un puntatore a

void si può assegnare qualsiasi altro tipo di puntatore (senza conversioni)• Lo stesso viceversa, un puntatore void può essere assegnato a tutti gli altri tipi

di puntatori senza effettuare alcun cast esplicito• Però sui puntatori void non si può però applicare l’operatore di deriferimento

7.7 - Le espressioni con i puntatori e l’aritmetica dei puntatori (3/3)

Page 18: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.8 - La relazione tra puntatori e vettori

• Vettori e puntatori sono strettamente correlati– Il nome di un vettore può essere visto come un puntatore costante al vettore– I puntatori possono essere usati per svolgere operazioni che coinvolgono gli

indici di un vettore, compresa l’indicizzazione del vettore stesso– Ad un puntatore posso assegnare o (con &) l’indirizzo di un elemento di un

vettore o il vettore intero stesso

• Dato un vettore b[] e un puntatore bPtr, è equivalente– Assegnare bPtr = b; dato che il nome è l’indirizzo del primo elemento– Assegnare bPtr = &b[0]; usando l’indirizzo del primo elemento

• Essendo b e bPtr alias, l’elemento b[n] si può accedere– Con la notazione puntatore + offset: *( bPtr + n ) dove n è l’offset

– Usando sul vettore l’aritmetica dei puntatori, dato che anch’esso lo è:

*(b + n), equivalente a *(bPtr + n) somma di un intero al puntatoreDa cui l’indirizzo di un elemento del un vettore si ottiene con lo stesso principio: &b[n] equivale a bPtr + n per l’auto-annullamento tra * e & combinati

– Con la notazione puntatore + indice: bPtr[n] equivale a *(bPtr + n)• I puntatori possono essere indicizzati come i vettori corrispondenti

Page 19: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.9 - Vettori di puntatori

• I vettori possono contenere a loro volta dei puntatori– Ogni elemento/cella del vettore contiene non un dato ma un indirizzo di

memoria di un’altra variabile (punta ad un dato esterno al vettore)

• L’applicazione più comune è creare un vettore di stringhe, finora realizzato esclusivamente come array bidimensionalechar *suit[4] = {“Hearts", “Diamonds", “Clubs", “Spades" };

– char * ogni elemento del vettore suit è un puntatore ad un char– Il vettore non contiene realmente le stringhe ma solo puntatori alle stringhe– Una stringa è un vettore di caratteri salvati in indirizzi di memoria contigui

• Per accedere alla stringa è sufficiente un puntatore al suo primo carattere

– Il vettore ha ovviamente una dimensione prestabilita, ma ora le singole stringhe possono avere dimensioni qualsiasi (ognuna diversa dalle altre)

suit[3]

suit[2]

suit[1]

suit[0] ’H’ ’e’ ’a’ ’r’ ’t’ ’s’ ’\0’

’D’ ’i’ ’a’ ’m’ ’o’ ’n’ ’d’ ’s’ ’\0’

’C’ ’l’ ’u’ ’b’ ’s’ ’\0’

’S’ ’p’ ’a’ ’d’ ’e’ ’s’ ’\0’

Page 20: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.10 - Caso di studio: simulare un mescolatore/distributore di carte

(1/5)• Il programma mescola e distribuisce le carte a 2 giocatori

– Usa due vettori di stringhe correlati per identificare ogni carta da gioco (semi per i semi, figure per la figura), implementati come vettori di puntatori

– Usa un vettore bidimensionale mazzo per rappresentare il mazzo di carte– Gli elementi della matrice contengono numeri in [1,52], che

rappresentano la posizione di ogni singola carta nel mazzo – Questo sarà poi l’ordine con cui le carte verranno distribuite ai giocatori

• Ne viene data una a testa partendo dalla prima (in cima al mazzo)

 

mazzo[2][12] rappresenta il Re di Fiori e indica che questa è la prima carta del mazzo

Cuori

Quadri

Fiori

Picche

0

1

2

3

Asso Due Tre Quattro Cinque Sei Sette Otto Nove Dieci Jack Regina Re0 1 2 3 4 5 6 7 8 9 10 11 12

Fiori Re

1

Page 21: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.10 - Caso di studio: simulare un mescolatore/distributore di carte

(2/5)• Pseudocodice – Livello Top : mescola e distribuisci 52 carte

Per ognuna delle 52 carte Assegna la sua posizione nel mazzo selezionando in modo casuale una carta non ancora inserita nel mazzo, ovvero una posizione casuale di deck tra quelle non ancora occupate

Per ognuna delle 52 carte Trova nella matrice deck la carta avente la posizione specificata e stampane face/suit corrispondenti

Scegli casualmente una posizione di deck Mentre la posizione di deck appena scelta è già occupata

Scegli casualmente un’altra posizione Metti il numero di posizione corrente nel mazzo nella posizione libera scelta di deck

Per ogni posizione del vettore deck Se contiene la posizione specificata stampa i relativi face/suit della carta corrispondente a tale posizione

Secondo rifinimento

Terzo rifinimento

Primo rifinimento

Inizializza il vettore suit

Inizializza il vettore face

Inizializza il vettore deck

Mescola deck

Distribuisci le 52 carte

Page 22: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.10 - Caso di studio: simulare un mescolatore/distributore di carte

(3/5)1 /* Fig. 7.24: fig07_24.c2 Programma per mescolare/distribuire delle carte da gioco */3 #include <stdio.h>4 #include <stdlib.h>5 #include <time.h>67 void mescolaCarte( int [][ 13 ] );8 void daiCarte( const int [][ 13 ], const char *[], const char *[] );910 int main(){11 const char *semi[ 4 ] = 12 { “Cuori", “Quadri", “Fiori", “Picche" };13 const char *figure[ 13 ] = 14 { "Asso", "Due", “Tre", “Quattro",15 “Cinque", “Sei", "Sette", “Otto",16 "Nove", “Dieci", "Jack", “Regina", “Re" };17 int mazzo[ 4 ][ 13 ] = { 0 };18

19 srand( time( 0 ) );

20 merscolaCarte( mazzo );

21 daiCarte( mazzo, figure, semi );22 return 0;

23 }

24

1. Inizializza i vettori suit, face e deck

2. Chiama shuffle per mescolare

3. Chiama deal per distribuire le carte

Page 23: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.10 - Caso di studio: simulare un mescolatore/distributore di carte

(4/5)

29 do {

30 riga = rand() % 4;

31 colonna = rand() % 13;32 } while( wMazzo[ riga ][ colonna ] != 0 );

33 wMazzo[ riga ][ colonna ] = pos_carta;

34 }

35 }36

37 void daiCarte( const int wMazzo[][ 13 ], const char *wFigure[],

38 const char *wSemi[] ){

39 int pos_carta, riga, colonna;40

41 for ( pos_carta = 1; pos_carta <= 52; pos_carta++ )

42 for ( riga = 0; riga <= 3; riga++ )

43 for ( colonna = 0; colonna <= 12; colonna++ )

44 if ( wMazzo[ riga ][ colonna ] == pos_carta )45 printf( "%7s of %-8s%c",

46 wFigure[ colonna ], wSemi[ riga ],

47 pos_carta % 2 == 0 ? '\n' : '\t' );48 }

25 void mescolaCarte( int wMazzo[][ 13 ] ){26 int riga, colonna, pos_carta;2728 for ( pos_carta = 1; pos_carta <= 52; pos_carta++ ){

4. Definisce le funzioni

5. Per ogni posizione nel mazzo, continua a generare carte in modo casuale finchè non ne trova una che non è ancora stata inserita nel mazzo

6. Simulazione della distribuzione di carte a 2 giocatori

6.1. Per ogni posizione nel mazzo, cerca tale posizione dentro la matrice delle carte e ne stampa suit e face

6.3. Usa un formato di stampa particolare per simulare “una carta a me, una a te”

I numeri 1-52 (le posizioni delle carte) sono messi nel vettore mazzo casualmente

Cerca in mazzo la carta che ha la posizione indicata e quindi ne stampa figure e semi.

Page 24: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 7 (Deitel) I puntatori Sommario 7.1 - Introduzione 7.2 - Dichiarare e inizializzare i puntatori

2000 Prentice Hall, Inc. All rights reserved.

7.10 - Caso di studio: simulare un mescolatore/distributore di carte

(5/5) Sei di Fiori Sette di Quadri Asso di Picche Asso di Quadri Asso di Cuori Regina di Quadri Regina di Fiori Sette di Cuori Dieci di Cuori Due di Fiori Dieci di Picche Tre di Picche Dieci di Quadri Quattro di PiccheQuattro di Quadri Dieci di Fiori Sei di Quadri Sei di Picche Otto di Cuori Tre di Quadri Nove di Cuori Tre di Cuori Due di Pichhe Sei di Cuori Cinque di Fiori Otto di Fiori Due di Quadri Otto di Picche Cinque di Picche Re di Fiori Re di Quadri Jack di Picche Due di Cuori Regina di Cuori Asso di Fiori Re di Picche Tre di Fiori Re di Cuori Nove di Fiori Nove di PiccheQuattro di Cuori Regina di Picche Otto di Quadri Nove di Quadri Jack di Quadri Sette di Fiori Cinque di Cuori Cinque di QuadriQuattro di Fiori Jack di Cuori Jack di Fiori Sette di Picche

Visualizzazione del programma