Strutture
Transcript
Strutture
Strutture Mentre un array consente di raggruppare, sotto un unico nome, vari elementi tutti dello stesso tipo, una struttura permette di gestire, mediante un unico nome, elementi di QUASI tutti i tipi. struct prova{int a; char b; float c[30];}; in alternativa typedef struct {int a; char b; float c[30];} nuovo; typedef struct prova nuovo; La definizione di un nuovo tipo di dato non comporta allocazione di memoria; la memoria viene allocata solo nel momento in cui avviene una dichiarazione di variabile o un’allocazione dinamica. Quanto spazio occupa in memoria una variabile di tipo struct? dipende .... In generale è >= alla somma delle dimensioni delle variabili di cui la struttura è composta e la scelta tra > o = dipende da come viene gestita la memoria sull’architettura in cui lavoriamo, ovvero da come risulta allineata la memoria. ... 38 39 typedef struct prova nuovo; indirizzi nella memoria struct prova{int a; char b; }; 40 int a (4 byte) 41 42 43 char b (1 byte) 44 45 ... totale : 5 byte ... 39 Tenendo conto di questo, il compilatore potrebbe scegliere di allineare a 4 byte anche variabili adiacenti all’int, semplicemente per rendere più rapido l’accesso alla memoria (o per poter posizionare in memoria un’altra struct adiacente alla prima ed allineata in modo corretto) indirizzi nella memoria In alcune architetture, la memoria non viene sempre allineata byte per byte ma tenendo conto della dimensione delle variabili. Ad esempio, gli int possono essere allineati a 4 byte (allineato a 4 byte significa che l’indirizzo in memoria occupato da un int deve essere un valore multiplo di 4) 40 41 42 int a (4 byte) 43 44 char b (1 byte) 45 46 3 byte per l’allineamento 47 ... totale : 8 byte Per forzare l’allineamento ad un byte si può usare la direttiva del preprocessore #pragma pack(1) In generale, quindi, non sapendo a priori quale sia la posizione delle variabili all’interno dell’area di memoria riservata per la struttura, è preferibile non usare un accesso diretto ma servirsi degli operatori di accesso. In questo modo, l’aggiunta di uno o più campi ulteriori nella struttura non implica una riscrittura delle funzioni d’accesso. typedef struct {char nome[30]; char cognome[30]; char numero[15];} agenda; typedef struct {char nome[30]; char cognome[30];} agenda; ... codice ... agenda var; printf(“Inserisci il nome”) scanf(“%s”,var.nome); ... codice ... se risulta utile aggiungere un nuovo parametro le funzioni d’accesso ai vecchi parametri non necessitano alcuna modifica ... codice ... agenda var; printf(“Inserisci il nome”) scanf(“%s”,var.nome); ... codice ... Alle strutture posso applicare gli operatori & e = struct prova{int a; char b;}; typedef struct prova nuovo; int main() {nuovo var; nuovo *pvar; pvar=&var; var.a=5; a=6; // ERRORE, la variabile non è stata dichiarata var.b=‘y’; printf(“Valore int: %d, valore char: %c\n”,pvar->a,pvar->b); return 0;} Importante: l’operatore di accesso va scelto in base al tipo di variabile con cui gestisco la struttura, non in base al tipo del membro a cui voglio accedere; il tipo dell’etichetta coincide con quello dell’ultimo nome a destra. pvar->a E’ il nome di una variabile di tipo int, così come var.a Esempio di applicazione /1 Data una struttura definita come: typedef struct {int a; int *codice} sequenza; ogni filamento di DNA è una sequenza di 4 basi (A,C,G,T), noi utilizziamo 4 valori di tipo intero (0,1,2,3) Implementare un programma in cui: - si dichiarino tre variabili di tipo sequenza; - si inizializzino due di tali variabili; - si visualizzino i valori assegnati a tali variabili; - si inizializzi la terza variabile mediante l’operatore di assegnazione - si evidenzino gli effetti di tale operatore - si confrontino i valori degli elementi di due strutture Fatto questo, per ciascun punto si implementi una specifica funzione Altre funzioni proposte - creare una funzione che simuli una mutazione Si definisca una funzione che accetta un parametro di tipo sequenza* , seq, ed un parametro di tipo int, perc; il primo parametro fa riferimento ad una variabile di tipo sequenza, mentre perc deve essere un numero intero compreso tra 0 e 100 (e rappresenta la percentuale di mutazione). La funzione non deve restituire alcun valore. Mediante un ciclo compiere le seguenti operazioni su ciascuno degli elementi di tipo int dell’array di nome codice contenuto all’interno della struttura cui seq fa riferimento: generare un numero casuale compreso tra 0 e 100, estremi inclusi; se questo numero è minore o uguale a perc, allora sostituire il valore dell’elemento considerato con un numero casuale compreso tra 0 e 3, estremi inclusi, altrimenti lasciare il valore dell’elemento inalterato - creare una funzione che da due sequenze ne generi una (leggete bene il testo e ragionate al fine di non generare accessi non consentiti alla memoria) Si definisca una funzione che accetta due parametri di tipo sequenza*, seq1 e seq2, e che restituisca un valore di tipo sequenza*. I due parametri fanno riferimento a due variabili di tipo sequenza. La funzione deve allocare dinamicamente una variabile di tipo sequenza, seq3; il numero di elementi dell’array codice contenuto in tale sequenza, num3, deve essere calcolato in questo modo:se num1 è il numero di elementi dell’array codice di seq1 e num2 è il numero di elementi dell’array codice di num2, num3=num1+num2. Dopo aver allocato seq3, ai primi num1 elementi del suo array codice vanno assegnati i valori contenuti nell’array codice della sequenza seq1 mentre ai secondi num2 elementi del suo array codice vanno assegnati i valori contenuti nell’array codice della sequenza seq2. Restituire l’indirizzo di seq3. - creare una funzione che simuli un virus Si definisca una funzione che accetti un parametro di tipo sequenza*, seq, ed un parametro di tipo int, lungh. Il primo parametro fa riferimento ad una variabile di tipo sequenza. Sia num la lunghezza dell’array codice contenuto nella struttura cui fa riferimento seq; generare un numero casuale, caso, compreso tra 2 e num-2. Allocare dinamicamente un’area di memoria di dimensione tale da contenere (num+lungh) variabili di tipo int e verificare se l’allocazione sia avvenuta con successo. Mediante un ciclo, copiare i primi caso elementi dell’array codice della struttura cui fa riferimento seq all’interno dell’array appena creato; mediante un secondo ciclo, iniziare i successivi lungh elementi dell’array appena creato con numeri casuali compresi tra 0 e 3. Mediante un terzo ciclo copiare i restanti elementi dell’array codice della struttura cui fa riferimento seq all’interno dell’array appena creato. Fatto questo, liberare l’area di memoria cui fa riferimento il membro codice della struttura cui fa riferimento seq ed assegnare a tale membro l’indirizzo dell’area di memoria di int creato prima.