...

Cap. 7 Deitel

by user

on
Category: Documents
12

views

Report

Comments

Transcript

Cap. 7 Deitel
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
 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
count
– Non contengono valori specifici (riferimento diretto)
7
– Contengono indirizzi di memoria di altre variabili, che a loro volta
contengono/immagazzinano dei valori specifici (riferimento indiretto)
countPtr
count
7
– 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)
 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
 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
yPtr
yPtr
500000
y
5
600000
y
600000
5
L’indirizzo di y è
il valore yPtr
– Nota: Il “tipo” pointer non è compatibile con gli altri, quindi assegnamenti
come double x = yptr non si possono fare, così come double x=&y
 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=7
x = *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);
printf(“Valore di yPtr: %p”,yPtr);
 2000 Prentice Hall, Inc. All rights reserved.
//Stampa 001F2BB4
//Stampa 001F2BB4
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]
 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 &
2 #include <stdio.h>
L’indirizzo di a
3
aPtr.
4 int main(){
5
int a;
/* è un intero */
6
int *aPtr;
/* è un puntatore ad un intero
7
8
a = 7;
9
aPtr = &a;
/* Assegna ad aPtr l’indirizzo
10
printf( "L’indirizzo di a è %p"
11
"\nIl valore di aPtr è %p", &a, aPtr
12
13
14
15
16
17 }
e * */
è il valore di
1. Dichiara le variabili
*/
di a
);
L’operatore * restituisce
un alias della variabile
puntata
2. Inizializza
le variabili
->Punta
ad a */ aPtr punta ad
dall’operando.
a, quindi *aPtr3. èStampa
alias di
a.
le varie
casistiche
printf( "\n\nIl valore di a è %d"
Fa notare come *
"\nIl valore di *aPtr è %d", a, *aPtr );
printf( "\n\nDimostrazione che * e & sono operatori inversi.\ne "
& siano inverse
"&*aPtr = %p\n*&aPtr = %p\n", &*aPtr, *&aPtr );
return 0;
L’indirizzo di a è 0012FF88
Il valore di aPtr è 0012FF88
Il valore di a è 7
Il valore di *aPtr è 7
Dimostrazione che * e & sono operatori inversi.
&*aPtr = 0012FF88
*&aPtr = 0012FF88
 2000 Prentice Hall, Inc. All rights reserved.
Visualizzazione
del programma
7.4 - Passare alle funzioni
i 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 funzione
void 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
 2000 Prentice Hall, Inc. All rights reserved.
7.4 - Passare alle funzioni
i parametri per riferimento (2/2)
1
/* Fig. 7.7: fig07_07.c
2
3
Eleva al cubo una variabile usando una chiamata per riferimento
#include <stdio.h>
Si passa l’indirizzo di number
4
5
void cuboPerRiferimento( int * );
/*
6
7
8
int main(){
int numero = 5;
cubeByReference aspetta un
prototipo(indirizzo
*/
puntatore
di variabile).
Così facendo non serve più che la
funzione ritorni qualcosa.
1. Prototipo – prende
un puntatore a int
9
10
printf( “Il valore originale del numero è %d", numero );
11
cuboPerRiferimento( &numero );
12
13
printf( "\nIl nuovo valore del numero è %d\n", numero );
return 0;
14 }
15
16 void cuboPerRiferimento( int *nPtr ){
17
Dentro cubeByReference,
è usato *nPtr come alias di
3. Definisce la funzione
number.
*nPtr = *nPtr * *nPtr * *nPtr;/* eleva al cubo number nel main */
18 }
Il valore originale del numero è 5
Il nuovo valore del numero è 125
 2000 Prentice Hall, Inc. All rights reserved.
2. Chiama la funzione
passando “number”
per riferimento
che ha per parametro
formale un puntatore
Visualizzazione
del programma
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
 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
3
Tentare di modificare un puntatore costante a dati variabili */
#include <stdio.h>
4
5
int main(){
6
int x, y;
7
8
int * const ptr = &x;
9
cambiare *ptr è permesso
perchè x non è una costante
/* ptr è un puntatore costante a int.
Un intero può essere modificato tramite
10
ptr, ma ptr punta sempre alla stessa
11
locazione diCambiare
memoria.ptr
*/
12
*ptr = 7;
13
ptr = &y;
14
return 0;
è e dà un errore
- ptr è un puntatore costante
1. Dichiara le variabili
2. Dichiara il puntatore
const ad int
3. Cambia *ptr (che
è alias di x)
15 }
4. Tenta di cambiare
l’indirizzo in ptr
FIG07_13.c:
Error E2024 FIG07_13.c 16: Cannot modify a const object in
function main
*** 1 errors in Compile ***
Visualizzazione
del programma
 2000 Prentice Hall, Inc. All rights reserved.
7.6 - L’ordinamento Bubble Sort tramite
una chiamata per riferimento (1/3)
• 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
• Pseudocodice
Inizializza il vettore
Stampa i dati nell’ordine originale
Chiama la funzione per l’ordinamento a bolle
Stampa il vettore ordinato
Definisce l’ordinamento a bolle
 2000 Prentice Hall, Inc. All rights reserved.
7.6 - L’ordinamento Bubble Sort tramite
una chiamata per riferimento (2/3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
16
17
18
/* Fig. 7.15: fig07_15.c
Questo programma inserisce dei valori in un vettore, ordina i
valori in modo ascendente, e visualizza il vettore risultante. */
#include <stdio.h>
#define SIZE 10
void bubbleSort( int *, const int );
bubbleSort di fatto si
aspetta di riceve un puntatore.
int main(){
Non89,
a caso,
nome di
int i, a[ SIZE ] = { 2, 6, 4, 8, 10, 12,
68, perchè
45, 37 il};
un vettore è un puntatore che
contiene
printf( “Elementi nell’ordine originale\n"
); l’indirizzo del primo
for ( i = 0; i < SIZE; i++ ) printf( "%4d",
a[ del
i ]vettore
);
elemento
bubbleSort( a, SIZE );
/* ordina il vettore */
printf( "\nElementi in ordine crescente\n" );
for ( i = 0; i < SIZE; i++ ) printf( "%4d", a[ i ] );
printf( "\n" );
return 0;
}
 2000 Prentice Hall, Inc. All rights reserved.
1. Inizializza il vettore
2. Stampa il vettore
originale
3. Invoca bubbleSort
4. Stampa il vettore
ordinato
7.6 - L’ordinamento Bubble Sort tramite
una chiamata per riferimento (3/3)
19 void bubbleSort( int *vettore, const int size
){
I singoli
elementi di un vettore5. Definizioni delle
20
void swap( int *, int * );
sono come variabili comuni e funzioni
21
int pass, j;
22
23
24
25
quindi passarli per riferimento
necessita l’uso di &
for ( pass = 0; pass < size - 1; pass++ )
for ( j = 0; j < size - 1; j++ )
if ( vettore[ j ] > vettore[ j + 1 ] )
swap( &vettore[ j ], &vettore[ jDentro
+ 1 ] la
);swap
26 }
27
28 void swap( int *elemento1Ptr, int
29
int temp = *elemento1Ptr;
30
*elemento1Ptr = *elemento2Ptr;
31
*elemento2Ptr = temp;
uso i puntatori
con deferimento per lavorare
su alias delle variabili originali
perché tali puntatori puntano
*elemento2Ptr ){
proprio alle variabili passate.
32 }
Elementi nell’ordine originale
2
6
4
8 10 12 89 68
Elementi in ordine crescente
2
4
6
8 10 12 37 45
 2000 Prentice Hall, Inc. All rights reserved.
45
37
68
89
Visualizzazione
del programma
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
3000
v[0]
 2000 Prentice Hall, Inc. All rights reserved.
3004
v[1]
Locazione
3008
3012
v[2]
v[3]
3016
v[4]
7.7 - Le espressioni con i puntatori e
l’aritmetica dei puntatori (2/3)
• 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
 2000 Prentice Hall, Inc. All rights reserved.
7.7 - Le espressioni con i puntatori e
l’aritmetica dei puntatori (3/3)
• 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
 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 puntatore
Da 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
 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 bidimensionale
char *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[0]
’H’
’e’
’a’
’r’
’t’
’s’
’\0’
suit[1]
’D’
’i’
’a’
’m’
’o’
’n’
’d’
suit[2]
’C’
’l’
’u’
’b’
’s’
’\0’
suit[3]
’S’
’p’
’a’
’d’
’e’
’s’
 2000 Prentice Hall, Inc. All rights reserved.
’\0’
’s’
’\0’
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)
Asso
0
Cuori
Due
1
Tre Quattro Cinque Sei Sette Otto Nove Dieci Jack Regina
2
3
4
5
6
7
8
9
10
11
Re
12
0
Quadri 1
Fiori
2
1
Picche 3
mazzo[2][12] rappresenta il Re di Fiori e indica che
questa è la prima carta del mazzo
Fiori
 2000 Prentice Hall, Inc. All rights reserved.
Re
7.10 - Caso di studio: simulare un
mescolatore/distributore di carte (2/5)
• Pseudocodice – Livello Top : mescola e distribuisci 52 carte
Primo rifinimento
Inizializza il vettore suit
Inizializza il vettore face
Inizializza il vettore deck
Mescola deck
Distribuisci le 52 carte
 2000 Prentice Hall, Inc. All rights reserved.
Terzo rifinimento
Secondo rifinimento
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
7.10 - Caso di studio: simulare un
mescolatore/distributore di carte (3/5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Fig. 7.24: fig07_24.c
Programma per mescolare/distribuire delle carte da gioco */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void mescolaCarte( int [][ 13 ] );
void daiCarte( const int [][ 13 ], const char *[], const char *[] );
int main(){
const char *semi[ 4 ] =
{ “Cuori", “Quadri", “Fiori", “Picche" };
const char *figure[ 13 ] =
{ "Asso", "Due", “Tre", “Quattro",
“Cinque", “Sei", "Sette", “Otto",
"Nove", “Dieci", "Jack", “Regina", “Re" };
int mazzo[ 4 ][ 13 ] = { 0 };
srand( time( 0 ) );
merscolaCarte( mazzo );
daiCarte( mazzo, figure, semi );
return 0;
}
 2000 Prentice Hall, Inc. All rights reserved.
1. Inizializza i vettori
suit, face e deck
2. Chiama shuffle
per mescolare
3. Chiama deal per
distribuire le carte
7.10 - Caso di studio: simulare un
mescolatore/distributore di carte (4/5)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void mescolaCarte( int wMazzo[][ 13 ] ){
int riga, colonna, pos_carta;
4. Definisce le funzioni
for ( pos_carta = 1; pos_carta <= 52; pos_carta++ ){
do {
riga = rand() % 4;
colonna = rand() % 13;
} while( wMazzo[ riga ][ colonna ] != 0 );
wMazzo[ riga ][ colonna ] = pos_carta;
I numeri 1-52
}
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
(le posizioni
delle carte) sono messi nel
vettore mazzo casualmente
}
void daiCarte( const int wMazzo[][ 13 ], const char *wFigure[],
const char *wSemi[] ){
Cerca in mazzo
int pos_carta, riga, colonna;
6. Simulazione della
distribuzione di
carta
carte a 2 giocatori
la
che ha la posizione
indicata e quindi ne 6.1. Per ogni posizione
= 1; pos_carta <= 52; pos_carta++ )
nel mazzo, cerca tale
stampa figure e semi.
0; riga <= 3; riga++ )
for ( pos_carta
for ( riga =
for ( colonna = 0; colonna <= 12; colonna++ )
if ( wMazzo[ riga ][ colonna ] == pos_carta )
printf( "%7s of %-8s%c",
wFigure[ colonna ], wSemi[ riga ],
pos_carta % 2 == 0 ? '\n' : '\t' );
}
 2000 Prentice Hall, Inc. All rights reserved.
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”
7.10 - Caso di studio: simulare un
mescolatore/distributore di carte (5/5)
Sei
Asso
Asso
Regina
Dieci
Dieci
Dieci
Quattro
Sei
Otto
Nove
Due
Cinque
Due
Cinque
Re
Due
Asso
Tre
Nove
Quattro
Otto
Jack
Cinque
Quattro
Jack
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
Fiori
Picche
Cuori
Fiori
Cuori
Picche
Quadri
Quadri
Quadri
Cuori
Cuori
Pichhe
Fiori
Quadri
Picche
Quadri
Cuori
Fiori
Fiori
Fiori
Cuori
Quadri
Quadri
Cuori
Fiori
Fiori
Sette
Asso
Regina
Sette
Due
Tre
Quattro
Dieci
Sei
Tre
Tre
Sei
Otto
Otto
Re
Jack
Regina
Re
Re
Nove
Regina
Nove
Sette
Cinque
Jack
Sette
 2000 Prentice Hall, Inc. All rights reserved.
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
di
Quadri
Quadri
Quadri
Cuori
Fiori
Picche
Picche
Fiori
Picche
Quadri
Cuori
Cuori
Fiori
Picche
Fiori
Picche
Cuori
Picche
Cuori
Picche
Picche
Quadri
Fiori
Quadri
Cuori
Picche
Visualizzazione
del programma
Fly UP