Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/wikka.php on line 315
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/libs/Wakka.class.php on line 176
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/libs/Wakka.class.php on line 463
Deprecated: Function set_magic_quotes_runtime() is deprecated in /home/demetres/public_html/didattica/ae/wikka.php on line 120
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/safehtml.php on line 308
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 159
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 161
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 162
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 163
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 165
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 166
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 167
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 243
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 250
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 259
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 266
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 273
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 280
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 467
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 469
Deprecated: Assigning the return value of new by reference is deprecated in /home/demetres/public_html/didattica/ae/3rdparty/core/safehtml/classes/HTMLSax.php on line 471
Lezione 5 - Lunedì 10 marzo 2014 (180 min)
[
<< Lezione precedente |
^ Diario delle lezioni |
>> Lezione successiva ]
Argomenti: Tipi struttura, typedef, espressioni che denotano tipi
Descrizione dettagliata:
- Strutture in C:
- costrutto struct: dichiarazione e tag
- accesso ai campi di una struttura:
- assegnazione e passaggio di parametri di oggetti di tipo struct
- esempio: lista collegata
- Dichiarazioni di identificatori di tipo mediante typedef
- Espressioni che denotano tipi
Appunti della lezione
Strutture
Come gli array, anche le strutture sono aggregati di oggetti. Il tipo struttura è un
tipo composto che specifica il numero e tipo dei campi di un aggregato. Diversamente dagli array, che sono aggregati di oggetti di tipo omogeneo, in una struttura i campi possono avere tipo diverso.
Dichiarazione di struttura: una struttura si dichara come nell'esempio seguente.
struct S {
int x, y;
double z;
};
La dichiarazione introduce un tipo struttura
S costituito da due
int e un
double, identificati rispettivamente dai nomi dei campi
x,
y e
z. Il tipo struttura dichiarato è identificato dal
tag struct S.
Spazio dei nomi tag delle strutture: i tag delle strutture formano uno spazio di nomi distinti da quelli degli altri identificatori (es. di variabili, ecc.).
Esempio:
struct x { int a, b; };
int x; // legale, poiché x è diverso da struct x
Dichiarazione di variabili struttura: Il seguente frammento di programma dichiara una variabile
v di tipo
struct S:
struct S v;
La
dimensione di una struttura sarà almeno pari alla somma delle dimensioni dei suoi campi. Nel nostro esempio:
sizeof(struct S) >=
sizeof(int) +
sizeof(int) +
sizeof(double). Vedremo più avanti perché potrebbe non valere l'uguaglianza stretta.
Accesso ai campi di una struttura: per accedere ai campi di una struttura è possibile usare l'operatore . (punto). Se
E è un Lvalue di tipo struttura e
c è un suo campo, allora l'espressione
E.c è un Lvalue che denota il campo
c della struttura
E.
Esempi:
v.
x =
10;
// scrittura campo x
v.
y =
20;
// scrittura campo y
v.
z =
3.14;
// scrittura campo z
printf("x=%d, y=%d, z=%f\n", v.
x, v.
y, v.
z);
// lettura di campi di una struttura
Puntatori a strutture: mostriamo ora come accedere ai campi di una struttura mediante un puntatore.
Esempio:
struct S* p;
p = malloc(sizeof(struct S)); // allocato in heap spazio per contenere un oggetto struct S
(*p).x = 10;
(*p).y = 20;
(*p).z = 3.14;
Si noti che, poiché l'operatore
. (punto) ha priorità più alta dell'operatore
*, è necessario usare le parentesi per specificare che si intende accedere all'oggetto
*p puntato da
p.
Operatore -> per accedere ai campo di una struttura: per rendere più agevole l'accesso ai campi di una struttura, in C è possibile usare l'operatore
-> come forma abbreviata: se
E è un puntatore a una struttura che ha un campo
c, allora
E->c è equivalente a
(*E).c.
Esempio:
struct S* p;
p = malloc(sizeof(struct S)); // alloca in heap spazio per contenere un oggetto struct S
p->x = 10; // equivalente a (*p).x = 10;
p->y = 20; // equivalente a (*p).y = 20;
p->z = 3.14; // equivalente a (*p).z = 3.14;
Strutture sono Lvalue modificabili: le espressioni che denotano oggetti struttura sono
Lvalue modificabili. Pertanto, è possibile assegnare una struttura all'altra:
struct S v;
struct S q;
...
v = q; // ok, copia byte a byte del contenuto di q in v
Allo stesso modo, è possibile
passare una struttura come parametro per copia a una funzione:
void foo
(struct S q
) {
q.
x =
55;
// modifica la copia locale della struttura, non la variabile v del main...
q.
y =
12;
q.
z =
7.9;
}
int main
() {
struct S v;
v.
x =
10;
v.
y =
20;
v.
z =
3.14;
foo
(v
);
// passaggio di parametro struttura per copia: copia byte a byte del contenuto di v nel parametro formale q di foo
printf("x=%d, y=%d, z=%f\n", v.
x, v.
y, v.
z);
// stampa x=10, y=20, x=3.14
return 0;
}
Poiché il passaggio per copia potrebbe essere inefficiente, soprattutto per strutture di grandi dimensioni, è possibile
passare una struttura per indirizzo. Oltre a essere più efficiente, poiché viene passato solo un indirizzo invece dell'intera struttura, questo consente anche di fare side-effect sull'oggetto passato:
void foo
(struct S* q
) {
q->x =
55;
// fa side-effect sulla variabile v del main...
q->y =
12;
q->z =
7.9;
}
int main
() {
struct S v;
v.
x =
10;
v.
y =
20;
v.
z =
3.14;
foo
(&v
);
// passaggio di parametro struttura per indirizzo: copia dell'indirizzo di v nel parametro formale q di foo permette a foo di modificare v
printf("x=%d, y=%d, z=%f\n", v.
x, v.
y, v.
z);
// stampa x=55, y=12, x=7.9
return 0;
}
Esempio delle liste collegate.
Le strutture insieme ai puntatori permettono di realizzare strutture dati collegate. Consideriamo ad esempio una lista collegata semplice di interi. Il tipo nodo della lista può essere dichiarato come segue:
struct node {
int elem;
struct node* next;
};
Dove
elem è il dato contenuto nel nodo e
next il puntatore al prossimo nodo della lista. Un nodo può essere creato e inizializzato come segue:
struct node* p; // dichiara variabile puntatore a nodo
p = malloc(sizeof(struct node)); // alloca spazio in heap per il nodo
p->elem = 10; // inizializza campo dato del nodo a 10
p->next = NULL; // non c'è un successore nella lista
...
free(p); // dealloca il nodo
Dichiarazioni di identificatori di tipo mediante typedef
Usando al parola chiave
typedef, in C è possibile definire degli identificatori di tipo che possono essere usati come
alias di altri tipi, cioè come nomi equivalenti.
Esempio:
typedef int intero; // dichiara l'identificatore intero come alias di tipo per int
intero x[10]; // x è una variabile di 10 int
typedef char* stringa; // dichiara l'identificatore stringa come alias di tipo per char*
stringa s; // s è una variabile di tipo char*
typedef struct S S; // dichiara l'identificatore S come alias di tipo per struct S
S* v; // v è una variabile di tipo puntatore a struct S
Espressioni che denotano tipi
Tutorial∞ (in inglese)
Materiale didattico per la lezione
Esercizi del giorno
Esercizio 1
Si consideri la seguente dichiarazione di un nodo di una lista collegata di interi:
typedef struct node {
int elem;
struct node* next;
} node;
- Scrivere una funzione nodo* add(int elem, node* list) che, dato un puntatore al primo nodo di una lista, o NULL per indicare una lista vuota, inserisce in testa alla lista un nuovo nodo contenente il dato elem, e restituisce il puntatore al nodo creato.
- Scrivere una funzione void print(node* list) che, data una lista, ne stampa il contenuto nel formato: [elem1, elem2, elem3, ...].
- Scrivere una funzione void delete(node* list) che, data una lista, ne dealloca tutti i nodi.
Usare il seguente programma di prova:
#include <stdio.h>
typedef struct node {
int elem;
struct node* next;
} node;
// mettere qui la definizione delle funzioni add, print e delete
int main() {
node* list = add(5, add(3, add(2, add(7, add(4, add(1, add(6, NULL)))))));
print(list); // stampa: [5, 3, 2, 7, 4, 1, 6]
delete(list);
return 0;
}
Verificare con
memcheck (Valgrind) che il programma usi la memoria correttamente.
Esercizio 2 (espressioni di tipo)
Si traduca in C la seguente dichiarazione di variabile usando le regole sulla specifica di espressioni di tipo (si veda [
P2∞]):
"
v è un array di 64 puntatori a puntatori a funzione che prende come parametro un puntatore a funzione senza argomenti che restituisce un puntatore a un array di 16
float, e restituisce un puntatore a funzione con due argomenti
int che restituisce
void."
Esercizio 3 (espressioni di tipo)
Si traduca in italiano la seguente dichiarazione C:
int (*(*p)[7])(int *(*f[20])(float** m, int r), void* q[20]);
Esercizio 4 (espressioni di tipo)
Si traducano in italiano le seguenti dichiarazioni C:
- char ****q[30];
- char **(**q)[30];
- int (x)[];
- long (*a[])( char, char );
- int *(*(*(*b)())[10])();
- char *strprt( char (*)( int ), unsigned char );
- int (*ab[])( unsigned int );