Comments
Description
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