Strutture: Le strutture (talvolta chiamate aggregati), così come gli array, sono tipi di dati derivati. Indicano collezioni di variabili collegate sotto un unico nome. Le strutture possono contenere variabili di vari tipi differenti di dati, a differenza degli array che contengono solo elementi dello stesso tipo di dati. A volte per risolvere dei problemi è necessario "aggregare" elementi di tipo diverso per formare una struttura; ad esempio per modellare il concetto di data: struct data { int giorno; char *mese; int anno; ; Per effetto di questa dichiarazione abbiamo definito un nuovo tipo di dato, il tipo: "data". Cosicchè possiamo definire variabili di questo tipo: es.: struct data oggi; Sintassi per la definizione di una struttura: struct nomestruttura { tipo1 nomemembro1; tipo2 nomemembro2; tipon nomemembron; ;
Gli elementi della struttura sono detti membri, sono identificati da un nome e da un tipo, che può essere sia fondamentale ( int, float, ecc. ) sia derivato. Definita una struttura, di fatto abbiamo un nuovo tipo e possiamo definire delle variabili: struct nomestruttura nomevariabile; Nel caso precedente: struct data oggi, anniversario; Altra sintassi per definire le variabili: struct data { int giorno; char *mese; int anno; oggi, anniversario; Esempi di strutture: struct persona { char nome[30]; char cognome[30]; char codice_fiscale[17]; int eta; ; struct punto { int coordinata_x; int coordinata_y; ;
Nota: per semplificare la "notazione" nella definizione delle strutture possiamo usare la parola chiave typedef, la quale permette di creare dei sinonimi o alias per i tipi di dati definiti. Sintassi: typedef nome_tipo nuovo_nome; Nel caso della struttura "data" : struct data { int giorno; char *mese; int anno; ; struct data oggi, anniversario; typedef struct { int giorno; char *mese; int anno; data; data oggi, anniversario; Data una variabile di tipo struttura, per accedere ai membri usiamo l operatore:. nomevariabile.nomemembro Es.: struct data oggi; oggi.giorno = 25; oggi.mese = "Novembre"; oggi.anno = 2014; Generalmente, ci si riferisce alle variabili di tipo struttura attraverso i membri.
Il linguaggio C permette assegnazioni tra variabili struttura (nel loro insieme) dello stesso tipo: es.: struct data compleanno ; // assumendo la variabile oggi come sopra definita. compleanno = oggi; // è corretto. struct data domani; domani=oggi; domani.giorno++; Mentre due strutture sono differenti anche se hanno gli stessi membri: es.: struct s1 { int x; a; struct s2 { int x; b;.. a = b; // errore! a = x; // errore! Tipi dati discordi. A differenza dell assegnazione, per relazionare due variabili di tipo struttura, dobbiamo necessariamente confrontare i membri.
es.: typedef struct{ float x; float y; punto; punto a; a.x = 10.5; a.y = 20.3; punto b; b.x = 13; b.y = 27.4; if(a < b) { // errore! if(a.x < b.x && a.y < b.y) { // corretto! Come per gli array, l inizializzazione di una variabile struttura può avvenire nella dichiarazione; es.: typedef struct { char marca[30]; char modello[30]; int cilindrata; automobile; automobile utilitaria = {"fiat", "panda", 1200; automobile corsa = {"ferrari", "F40", 3000;
#include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct { float x; float y; punto; float dst(punto a, punto b); int main() { punto a, b; printf("coordinate Punto A: "); scanf("%f%f", &a.x, &a.y); printf("coordinate Punto B: "); scanf("%f%f", &b.x, &b.y); printf("distanza: %f\n", dst(a, b)); return 0; float dst(punto a, punto b) { float distanza, dx, dy; dx = (a.x - b.x)*(a.x - b.x); dy = (a.y - b.y)*(a.y - b.y); distanza = sqrt(dx + dy); return distanza;
Esercizio: dato l esempio precedente, implementare una funzione che ritorni il punto medio: prototipo: punto pt_medio(punto a, punto b); Nota: nelle funzioni il passaggio di strutture avviene sempre per valore. Possiamo definire array di strutture; ad esempio: typedef struct { char marca[30]; char modello[30]; int cilindrata; automobile; automobile vetture[10]; int i; for(i = 0; i < 10; i++) { printf("inserire marca, modello e cilindrata della vettura: "); scanf("%s %s %d", vetture[i].marca, vetture[i].modello, &vetture[i].cilindrata); // per la stampa: for(i = 0; i < 10; i++) printf("%s %s %d\n", vetture[i].marca, vetture[i].modello, vetture[i].cilindrata); Di seguito, un esempio di funzione che riceve come parametro un array di strutture:
#include <stdio.h> #define N 10 typedef struct { float x; float y; punto; void stampa_pt(punto *); punto add_pt(void); int main() { punto vertici[n]; int i; for(i = 0; i < N; i++) vertici[i] = add_pt(); stampa_pt(vertici); return 0; punto add_pt(void) { punto tmp; printf("coordinate punto: "); scanf("%f%f", &tmp.x, &tmp.y); return tmp; void stampa_pt (punto *lista) { int i; for(i = 0; i < N; i++) printf("%f, %f\n", lista[i].x, lista[i].y);
Strutture e Puntatori: E possibile far riferimento ad una struttura attraverso un puntatore, ovvero tramite una variabile che contiene l indirizzo di una variabile di tipo struttura. struct data oggi, *pd; pd = &oggi; (*pd).giorno = 10; (*pd).mese = Novembre ; (*pd).anno = 2014; Nota: le parentesi tonde che circoscrivono *pd sono necessarie poiché l operatore. ha priorità maggiore dell operatore *. Siccome in C si accede spesso a strutture tramite puntatore, per semplificare la sintassi è stato introdotto l operatore freccia ->. Possiamo scrivere: struct data oggi, *pd; pd = &oggi; pd->giorno = 28; pd->mese = "Novembre"; pd->anno = 2014; Nota: i puntatori a struttura sono molto usati, specialmente per passare strutture a funzioni. Alla luce dei nuovi operatori, si veda la tabella riepilogativa: Priorità degli operatori: () [] ->.! ~ -(unario) ++ -- & * (tipo) sizeof * / % + - << >> > < >= <= ==!= & ^ &&?: = += -= *= /= %= &= ^= = <<= >>=
Una struttura aggrega un insieme di elementi che possono essere di qualsiasi tipo; addirittura come membri possiamo avere altre strutture. Ad esempio per rappresentare il concetto di anagrafe potremmo definire le seguenti strutture: typedef struct { int giorno; char mese[10]; int anno; data; typedef struct { char via[35]; int numero; char citta[30]; char provincia[2]; indirizzo; typedef struct { char nome[30]; char cognome[30]; data nascita; char comunenascita[30] indirizzo ind; char telefono[10] persona; Esercizio: Implementare un programma che faccia la gestione anagrafica; (MAX_ELE = 100; visualizzare un menù; funzioni per inserimento, cancellazione e visualizzazione nominativi).
Allocazione dinamica di strutture: Per allocare dinamicamente una struttura, dobbiamo conoscere la dimensione ovvero quanta memoria occupa; a tal fine utilizziamo l operatore sizeof. typedef struct{ int giorno; char* mese; int anno; data; data *pt_day; pt_day = (data *) malloc(sizeof(data)); if(pt_day == NULL) { /* error - out of memory */ // altrimenti: pt_day->giorno = 20; pt_day->mese = "Gennaio"; pt_day->anno = 2012;. Strutture e liste: Le strutture rivestono un ruolo molto importante nell implementazione delle liste. Molto spesso si ha a che fare con strutture ricorsive, ovvero strutture che tra i membri presentano un puntatore alla struttura stessa.
Una lista è una successione di elementi omogenei che (a differenza degli array) occupano in memoria una posizione qualsiasi. La lunghezza di una lista non è fissa (contrariamente agli array) ma può cambiare dinamicamente. L accesso alla lista avviene attraverso il puntatore al primo elemento; ogni elemento contiene un informazione e un puntatore che punta all elemento successivo: Elemento = Informazione + Puntatore inf pt Es. implementiamo la struttura: struct elemento { int inf; struct elemento *pt; Per dichiarare una lista, basta scrivere: struct elemento *ptr_lista; // inizialmente la lista è vuota; dopo vari inserimenti avremo ad esempio: ptr_lista.. NULL Nota: in questo modo abbiamo definito una lista lineare; questa viene visitata (scandita) in ordine, cioè dal primo elemento fino all ultimo che punta a NULL.
Gestione lista: Vediamo ora la gestione di una lista, considerando il problema di memorizzare e visualizzare una sequenza di n numeri interi; dove il valore di n è noto solo in fase di esecuzione (input utente). Nota: risolvere il problema con array è complicato! (n noto solo a run-time) Come struttura possiamo assumere quella riportata in precedenza (elemento). Decomponiamo il problema in due parti (funzioni): struct elemento *crealista(void) : restituisce il puntatore alla lista creata. void visualizzalista( struct elemento * ) : stampa la lista ricevuta in input. Descrizione dell algoritmo della funzione crealista(): struct elemento *start, *paus; int i,n; Acquisizione (input) di n: se n = 0 lista vuota ---> start = NULL; Mentre con n>0: start = (struct elemento *) malloc(sizeof(struct elemento)); // testa della lista. printf ("Inserire numero intero : "); scanf ("%d",&start->inf); // caricamento informazione paus = start; // paus è un puntatore ausiliario. start paus
for (i =2; i<=n; i++) { // creare nuovo elemento: paus->pt = (struct elemento *) malloc(sizeof(struct elemento)); // far puntare paus all elemento successivo: paus = paus->pt; start 12 7 // richiedere informazioni per nuovo elemento: printf ("Inserire numero intero : "); scanf ("%d",&paus->inf); paus infine: paus->pt = NULL; return(start); Per la visualizzazione: start 12 7. 23 NULL void visualizzalista( struc elemento *ptr ) { while( ptr!= NULL ) { printf("%d\t", ptr->inf); ptr= ptr->pt;
// Creazione lista di interi #include <stdio.h> #include <stdlib.h> struct elemento { int inf; struct elemento *pt; ; struct elemento *crealista(void); void visualizzalista(struct elemento *); int main (void) { struct elemento *ptr_lista; ptr_lista=crealista(); visualizzalista(ptr_lista); return 0; void visualizzalista(struct elemento* ptr) { if (!ptr) printf("lista vuota!"); else printf("lista: "); while( ptr!= NULL ) { printf("%d ", ptr->inf); ptr= ptr->pt; if (ptr) printf("--> "); struct elemento* crealista(){ struct elemento *start, *paus; int n=0, i; printf("inserire numero elementi della lista: "); scanf("%d",&n); if (n <= 0) {start = NULL; // fine else{ start = (struct elemento *) malloc(sizeof(struct elemento)); if (start == NULL) {/* error! out of memory */ return start; ; printf("inserire numero intero: "); scanf("%d",&start->inf); paus = start; for (i =2; i<=n; i++) { paus->pt = (struct elemento *) malloc(sizeof(struct elemento)); if (paus->pt == NULL) {/* error! out of memory */ break;; paus = paus->pt ; printf("inserire numero intero: "); scanf("%d",&paus->inf); paus->pt = NULL; return start;
Esercizi: - Data una lista di interi, implementare una funzione che restituisca il valore max/min. - Data una lista ordinata di interi, implementare una funzione che inserisca (rispettando l ordine) un nuovo valore acquisito in input. - Data una lista di interi, implementare una funzione che ordini gli elementi.