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.