Puntatori a struttura
Riprendiamo l'esercizio della scorsa settimana. #include <stdio.h> // per printf() #include <string.h> // per le funzioni di gestione delle stringhe #include <stdlib.h> // per malloc() struct temp{char titolo[100]; char *autore; int collocazione;}; typedef struct temp libro; int main() {int i=0; char temp[4]; libro elenco[30]; // ciclo di inizializzazione for(i = 0;i < 30 ; i++) { elenco[i].collocazione = 0 ; elenco[i].titolo[0] = '\0' ; // o, in modo analogo * ( elenco[i].titolo ) = '\0' ; // allocazione di memoria elenco[i].autore = (char *) malloc ( sizeof(char) * (50 + 1) ); } // fine ciclo di inizializzazione // ciclo di assegnazione for( i = 0 ; i < 30 ; i ++ ) { printf(" Vuoi inserire autore e titolo di un libro ? (s/n)"); scanf("%s",temp); if( strncmp(temp,"s",1) == 0 ) break; // in questo modo anche sì viene accettato printf("\n Inserisci il titolo del libro (max 99 car.)"); gets( elenco[i].titolo ) ; printf("\n Inserisci nome e cognome dell'autore del libro (max 50 car.)"); gets( elenco[i].autore ) ; printf("\n Inserisci la collocazione del libro"); scanf("%d", & ( elenco[i].collocazione ) ); // uso & perché il parametro è un int } return 0;} La scorsa settimana avevamo visto che:
Da questo segue che: come succedeva per le variabili appartenenti ai 4 tipi fondamentali, tutti gli elementi di un vettore di strutture possono essere inizializzati / letti utilizzando una funzione Cerchiamo di svolgere le operazioni viste prima (inizializzazione ed inserimento dei valori) utilizzando delle funzioni. ... // istruzioni libro elenco[30]; // ciclo di inizializzazione for(i = 0;i < 30 ; i++) { elenco[i].collocazione = 0 ; elenco[i].titolo[0] = '\0' ; // o, in modo analogo * ( elenco[i].titolo ) = '\0' ; // allocazione di memoria elenco[i].autore = (char *) malloc ( sizeof(char) * (50 + 1) ); } // fine ciclo di inizializzazione ... // istruzioni Una funzione adatta a svolgere lo stesso compito è: /* non prevedo la restituzione di alcun valore in quanto la funzione deve modificare gli elementi di un'area di memoria (l'array) già allocata */ void inizializza(libro*,int); void inizializza(libro* vettore,int dimensione) {int i=0; for(i=0; i < dimensione ; i++) { vettore[i].collocazione = 0; vettore[i].titolo[0] = '\0'; vettore[i].autore = (char *) malloc ( sizeof(char) * (50 + 1) ); } } La versione equivalente a questa, che fa uso dell'aritmetica dei puntatori, è: void inizializza(libro*,int); void inizializza(libro* vettore,int dimensione) {int i=0; for(i=0; i < dimensione ; i++) { ( vettore + i ) -> collocazione = 0; * (( vettore + i ) -> titolo )= '\0'; ( vettore + i ) -> autore = (char *) malloc ( sizeof(char) * (50 + 1) ); } } Allo stesso modo, ci possiamo servire di una funzione per svolgere le istruzioni relative alla parte del codice in cui l'utente doveva inserire i parametri. ... // istruzioni for( i = 0 ; i < 30 ; i ++ ) { printf(" Vuoi inserire autore e titolo di un libro ? (s/n)"); scanf("%s",temp); if( strncmp(temp,"s",1) == 0 ) break; // in questo modo anche sì viene accettato printf("\n Inserisci il titolo del libro (max 99 car.)"); gets( elenco[i].titolo ) ; printf("\n Inserisci nome e cognome dell'autore del libro (max 50 car.)"); gets( elenco[i].autore ) ; printf("\n Inserisci la collocazione del libro"); scanf("%d", & ( elenco[i].collocazione ) ); // uso & perché il parametro è un int } ... // istruzioni Una funzione che ci permette di svolgere il medesimo compito è: void assegna(libro*,int); void assegna(libro* vettore, int dimensione) {int i=0; char temp[4]; for(i = 0 ; i < dimensione ; i++) { printf(" Vuoi inserire autore e titolo di un libro ? (s/n)"); scanf("%s",temp); if( strncmp(temp,"s",1) == 0 ) break; // in questo modo anche sì viene accettato printf("\n Inserisci il titolo del libro (max 99 car.)"); gets( vettore[i].titolo ) ; printf("\n Inserisci nome e cognome dell'autore del libro (max 50 car.)"); gets( vettore [i].autore ) ; printf("\n Inserisci la collocazione del libro"); scanf("%d", & ( vettore[i].collocazione ) ); // uso & perché il parametro è un int } } La versione che fa uso dell'aritmentica dei puntatori è: void assegna(libro*,int); void assegna(libro* vettore, int dimensione) {int i=0; char temp[4]; for(i = 0 ; i < dimensione ; i++) { printf(" Vuoi inserire autore e titolo di un libro ? (s/n)"); scanf("%s",temp); if( strncmp(temp,"s",1) == 0 ) break; // in questo modo anche sì viene accettato printf("\n Inserisci il titolo del libro (max 99 car.)"); gets( ( vettore + i ) -> titolo ) ; printf("\n Inserisci nome e cognome dell'autore del libro (max 50 car.)"); gets( ( vettore + i ) -> autore ) ; printf("\n Inserisci la collocazione del libro"); scanf("%d", & ( ( vettore + i ) -> collocazione ) ); // uso & perché il parametro è un int } } Un'ultima nota sul passaggio delle strutture alle funzioni. Fino ad ora il passaggio di strutture alle funzioni è sempre stato effettuato mediante puntatore. Facendo questo è palese il fatto che, ricevendo l'indirizzo della locazione di memoria in cui risiede una data struttura, la funzione è in grado di modificare il valore di tutti gli elementi della struttura stessa. Nel caso in cui il passaggio venga effettuato per valore, ci aspettiamo che questo non accada, ovvero che la funzione non sia in grado di alterare i valori contenuti nella struttura che passiamo alla funzione, in quanto quest'ultima può alterare solo la copia locale della struttura di cui passiamo il valore. Ma questo non sempre è vero. struct temp{char titolo[100]; char *autore; int collocazione;}; typedef struct temp libro; void modifica(libro); int main() {libro volume; strcpy(volume.titolo,"Manuale di C"); volume.autore= (char*) malloc ( 100 * sizeof(char)); strcpy(volume.autore,"Pinco Pallino"); volume.collocazione = 1234; modifica(volume); return 0;} void modifica(libro copia) { strcpy(copia.titolo,"Manuale di C, seconda edizione"); strcpy(copia.autore,"Mario Rossi"); } All'atto del passaggio della struttura alla funzione, alla variabile locale copia viene assegnato il valore della struttura volume; l'operazione viene effettuata membro a membro. Quindi, la variabile locale copia.autore possiede lo stesso valore della variabile volume.autore, ovvero entrambe possiedono l'indirizzo della locazione di memoria in cui si trova la stringa contenente il nome dell'autore del libro. Perciò la funzione è in grado di alterare la variabile volume. Il passaggio per valore della struttura ha "mascherato" il passaggio per riferimento dell'array in essa contenuto. |