• Programmazione Android
  • CORSI ONLINE
  • Web Agency

Logo

Corsi di programmazione web e mobile online
Navigation
  • Home
  • CORSI ONLINE
  • Tutorial Pratici
  • GUIDE COMPLETE
    • Corso completo di C
    • Corso videogame con Cocos2d
    • Programmazione Cocoa Touch
  • Sezioni
    • Libri e manuali
    • Tips & Tricks
    • Risorse utili
    • Strumenti di Sviluppo
    • Materiale OpenSource
    • Framework
    • Guide Teoriche
    • Guide varie
    • Grafica e Design
    • iPad
    • News
    • Video Tutorial
    • Windows Phone
  • Pubblicità
  • About
    • Chi siamo
    • Pubblicazioni
    • Collabora
    • Sostieni devAPP

15. Costrutti enum, union e struct

By IgnazioC | on 1 Giugno 2011 | 9 Comments
Corso completo di C

corso-completo-c-costrutti-enum-union-struct-00 Benvenuti alla quindicesima lezione del nostro corso completo di programmazione in C, se avete avuto l’ardore di seguirci fino a questo punto ormai avrete preso familiarità con il C e la sua sintassi.

In questa lezione vedremo tre costrutti: enum, union e struct che ci permetteranno di scrivere codice più comprensibile e più vicino al modo umano di vedere le cose. Questi costrutti sono forse “gli antenati” della moderna programmazione ad oggetti, vedremo infatti che utilizzandoli ci si può distaccare dal concetto di semplice variabile ed iniziare a ragionare in termini di “entità” più complesse.

enum

Le enum ci vengono incontro quando abbiamo a che fare con una lista di valori.

Facciamo un esempio: supponiamo di aver scritto un programa che, a seconda del giorno della settimana, ci mostri un messaggio personalizzato:

in pseudocodice:

if (oggi = Lunedì)

   messaggio = "Dai, alzati il week end è finito"

else if (oggi = martedì )

  messaggio = "Alzati campione!"

else if (oggi = mercoledì )

   messaggio = "Già mezza settimana! inizia a programmare il prossimo weekend"

…..e così via....

Dovremmo decidere però come memorizzare l’elenco dei giorni della settimana….volendo si potrebbero memorizzare come stringhe di testo ma questo è un grosso problema, primo perché le stringhe di testo in C vanno trattate con cautela (li vedremo la prossima lezione) e poi è sempre possibile digitare male, nell’esempio precedente “martedì” e “mercoledì” li ho scritti con le iniziali minuscole.. scartate le stringhe allora dobbiamo assegnare un codice numerico, decidiamo ad esempio che per noi 0 significa “Lunedì” e modifichiamo il codice scivendo, sempre in pseudocodice:

if ( oggi = 0 )

   messaggio = "Dai, alzati il week end è finito"

… e così via....

Ma quanto è chiaro questo test? Quando ci saremo dimenticati di aver associato mentalmente 0 a “Lunedì” riusciremo a capire il nostro codice? Per un inglese sarebbe più ragionevole supporre che 0 sia associato a “Sunday”?

Ecco quindi che nascono le enum. Utilizzando questo costrutto:

enum _GiorniSettimana{

    Lunedì,

    Martedì,

    Mercoledì,

    Giovedì,

    Venerdì,

    Sabato,

    Domenica

};

abbiamo definito un nuovo tipo di dato, utilizzabile così come utilizziamo int, char e via dicendo, ma che può assumere solo i valori elencati all’interno della enum.

In questo modo il nostro codice sarà sicuramente più chiaro.

Metto qui il codice completo di un piccolo esempio che ho scritto utilizzando la libreria time.h, forse il codice non sarà comprensibile a tutti, soprattutto la funzione today() ma quello che conta è che siamo riusciti ad inserire all’interno del nostro programma, in maniera semplice, il concetto di giorno della settimana.

#include 
#include 
#include 

enum GiornoSettimana{

    Domenica,

Lunedi,

    Martedi,

    Mercoledi,

    Giovedi,

    Venerdi,

    Sabato,

};

enum GiornoSettimana today() {

        time_t timer;

        timer=time(NULL);

        struct tm *currentTime = localtime(&timer);

        return currentTime->tm_wday;

}

int main(void) {

        enum GiornoSettimana giornodioggi = today();

        if (giornodioggi == Domenica) {

                printf("Oggi è Domenica!!");

        }

        else if (giornodioggi == Lunedi) {

                        printf("Dai, alzati il week end è finito");

        }

        else if (giornodioggi == Martedi) {

                        printf("Alzati campione!");

        }

        else if (giornodioggi == Mercoledi) {

                        printf("Già mezza settimana! inizia a programmare il prossimo weekend");

        }

        else if (giornodioggi == Giovedi) {

                        printf("Domani è venerdì :) ");

        }

        else if (giornodioggi == Venerdi) {

                        printf("Venerdì..lo senti il profumo del Sabato??");

        }

        else if (giornodioggi == Sabato) {

                printf("Inizia il fine settimana!!");

        }

        return 0;

}

Come si può notare l’enum ha proprio definito un nuovo tipo di dato, ed è possibile dichiarare una variabile di questo nuovo tipo scrivendo semplicemente:

enum GiornoSettimana nome_variabile

Ma come funziona l’enum? L’idea di base è molto semplice, ad ogni valore della enumerazione viene assegnato un intero a partire da 0, quindi a basso livello il confronto viene sempre fatto con gli interi, ma ad alto livello noi vediamo nomi più significativi come “lunedì, martedì etc”.

UNION

Le union definiscono, così come le enum, un tipo di dato. La particolarità della union è che contiene più variabili, anche di dimensioni diverse ma tutte sono memorizzate alla stessa allocazione di memoria quindi occupa lo spazio occupato dalla più grande di esse. Questo, in pratica, significa che la union è come un “contenitore” che può essere utilizzato per contenere più tipi di variabili, ma ne può essere utilizzato solo uno alla volta.

Riporto, per comodità, un esempio prelevato da wikipedia (link)

#include 
union numero{
  int valX;
  int valY;
};

int main(){
  union numero Punto; // Definisce la variabile Punto di tipo union numero
  Punto.valX=50; // Inizializza il membro valX dell'unione al valore 50
  Punto.valY=100; // Inizializza il membro valY dell'unione al valore 100

  printf("Il valore di X vale %d mentre il valore di Y vale %d\n",Punto.valX,Punto.valY); // Stampa sullo schermo i membri dell'unione''

  return 0;
}

Per accedere alla variabile contenuta all’interno della union si utilizza il “.” e come si può notare eseguendo il programma l’utilizzo della variabile “valY” all’interno della union ha sovrascritto il valore della variabile “valX”.

Ci possono essere però utilizzi più complessi del costrutto union, ad esempio per contenere alternativamente un intero oppure un puntatore a caratteri.

union identificativo{
  int id_int;
  char *id_char;
};

La union la si può pensare come l’antesignana del polimorfismo dei nuovi linguaggi ad oggetti, perché si può utilizzare una variabile in più modi a seconda della necessità. (ok forse è un pò forzato :P).

STRUCT

Lo ammetto, il costrutto struct è il mio preferito. Serve per definire un nuovo tipo di variabile, aggregando altri tipi di variabili ed eventualmente altre strutture.

Questo ci permette di staccarci dalla logica delle singole variabili ed iniziare a pensare in temrmini di “oggetti” (non storcano il naso i puristi della OOP).

Partiamo dall’esempio classico: scrivere una funzione che restituisca la distanza euclidea tra due punti nello spazio r2, in altri termini “date le misure dei cateti di un triangolo rettangolo, restituire la misura dell’ipotenusa”.

Se non usassimo le strutture il programma sarebbe pressapoco così:

#include 
#include 
#include 

float distance(float x1, float y1, float x2, float y2) {

        float d;

        d = sqrt( pow(x1 - x2, 2) + pow(y1 - y2,2));

        return d;

}

int main(void) {

        float punto1x, punto1y, punto2x, punto2y, distanza;

        punto1x = 0;

        punto1y = 0;

        punto2x = 1;

        punto2y = 1;

        distanza = distance(punto1x, punto1y, punto2x, punto2y);

        printf("La distanza è: %2f",distanza);

        return 0;

}

L’esempio sopra funziona, non c’è che dire.. ma come esprimiamo il fatto che “punto1x” e “punto2y” sono in qualche modo correlati, che sono due caratteristiche che nella nostra testa appartengono allo stesso concetto di “punto”? E che dire della funzione che calcola la distanza? Per noi la distanza viene calcolata tra due entità che sono “punti” non tra 4 numeri a virgola mobile…

Risolviamo tutto semplicemente definendo un nuovo tipo di dato con il costrutto struct così definito:

struct Point {
        float x;
        float y;
};

In questo modo il programma può essere riscritto semplicemente in questo modo:

#include 
#include 
#include 

struct Point {
        float x;
        float y;
};

float distance(struct Point p1, struct Point p2) {
        float d;
        d = sqrt( pow(p1.x - p2.x, 2) + pow(p1.y - p2.y,2));
        return d;
}

int main(void) {

        struct Point p1, p2;
        float distanza;
        p1.x = 0;
        p1.y = 0;
        p2.x = 1;
        p2.y = 1;

        distanza = distance(p1, p2);
        printf("La distanza è: %2f",distanza);

        return 0;
}

In questo modo il programma ha assunto maggiore chiarezza e, soprattutto, è più simile al modo di pensare dell’uomo.

Ma supponiamo adesso di calcolare la distanza tra due cerchi, non vogliamo certo ricadere nell’errore precedente, quindi ragioniamo subito in termini di strutture e visto che sappiamo che le strutture possono essere annidate definiamo il nostro cerchio in questo modo:

struct Circle {
    float radius;
    struct Point center;
};

e la funzione per calcolare la distanza può essere tranquillamente definita in questo modo:

float distance(struct Circle c1, struct Circle c2) {
        float d;
        d = distance(c1.center, c2.center);

        return d;
}

Alzi la mano chi voleva inserire nuovamente il calcolo dentro questa funzione!

Meno 10 punti !!

Mai scrivere lo stesso codice due volte!

Aspetti Comuni “.” o “->”

Le union e le struct hanno molto in comune, specie nell’accesso ai loro membri interni. Negli esempi che ho proposto ho sempre utilizzato l’operatore “.” ma esiste anche un secondo metodo che prevede l’utilizzo dell’operatore “->”.

La differnza è che il punto si utilizza quando abbiamo dichiarato una variabile di tipo struct o union, mentre “->” si utilizza quando abbiamo dichiarato un puntatore ad una struttura o union.

Ricordando quanto abbiamo detto per i puntatori e le funzioni, scriviamo una funzione che serva per “spostare” un cerchio.

void moveCircle(struct Circle *c) {
        c->center.x = c->center.x + 10;
}

che possiamo richiamare tramite:

struct Circle c1;

c1.radius = 5;
c1.center.x = 2;
c1.center.y = 5;

printf("Il cerchio è centrato nel punto: %f %f\n",c1.center.x, c1.center.y);

moveCircle(&c1);

printf("Il cerchio è centrato nel punto: %f %f\n",c1.center.x, c1.center.y);

typedef

Un aspetto che riguarda anche le enum è invece la possibilità di evitare di dover ogni volta scrivere enum/union/struct nel dichiarare le nostre variabili.

Ad esempio dichiarando la struttura “Circle”, quando vogliamo un tipo di dato di tipo “Circle” siamo costretti a scrivere:

struct Circle c1;

Questo si può ovviare con il costrutto typedef, che permette di creare un vero e proprio tipo di dato a tutti gli effetti. Scrivendo quindi:

typedef struct Circle {

    float radius;
    struct Point center;
};

possiamo dichiarare le nostre nuove variabili semplicemente scrivendo:

Circle c1;

//così come si fa con

int j;

Dichiarazione automatica

In alcuni casi potremmo incontrare una dichiarazione di struct/enum/union leggemente diversa da quella che ho dato io, ad esempio potremmo trovare:

typedef struct Circle {
    float radius;
    struct Point center;
} circle;

In questo caso quello che avviene è che stiamo dichiarando una variabile di tipo “Circle” direttamente durante la definizione del tipo. Io non amo molto questo modo di fare, soprattutto perché la definizione dei tipi la faccio con scope globale e se dichiarassi una variabile in quel punto questa sarebbe una variabile globale, che cerco di evitare quanto più possibile.

Alla prossima!!

Letture consigliate:

C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP Il linguaggio C. Principi di programmazione e manuale di riferimento (Accademica)
Brian W. Kernighan – Dennis M. Ritchie
Editore: Pearson | Lingua: Italiano | Brossura: 313 pagine
Prezzo Listino: EUR 27,00
Prezzo Promozione: EUR 22,95 con Spedizione gratuita

C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP C. Corso completo di programmazione
Paul J. Deitel – Harvey M. Deitel
Editore: Apogeo | Lingua: Italiano | Brossura: 640 pagine
Prezzo Listino: EUR 39,00
Prezzo Promozione: EUR 33,15 con Spedizione gratuita



Share this story:
  • tweet

Tags: corso completo di Ccorso di Cenum in Cesempi codice programmazione Cesercizi programmazione CIgnazio Calòstruct in Ctypedef in Cunion in C

Recent Posts

  • Parte il percorso programmatori iOS in Swift su devACADEMY.it

    20 Dicembre 2017 - 0 Comment
  • Android, crittografare dati velocemente con Encryption

    24 Settembre 2018 - 0 Comment
  • Sql2o, accesso immediato ai database tramite Java

    3 Settembre 2018 - 0 Comment
  • Okio, libreria per ottimizzare l’input/output in Java

    27 Agosto 2018 - 0 Comment

Related Posts

  • iSketch: la lavagna magica di Ignazio Calò disponibile GRATUITAMENTE in App Store

    29 Agosto 2011 - 2 Comments
  • 17. La gestione dei file in C

    22 Agosto 2011 - 4 Comments
  • Uno sguardo a Unit test: impariamo a prevenire ore e ore di debug durante lo sviluppo di Applicazioni iOS

    8 Agosto 2011 - 2 Comments

Author Description

9 Responses to “15. Costrutti enum, union e struct”

  1. 4 Giugno 2011

    peppe

    sono uno dei tanti supestiti

  2. 4 Giugno 2011

    ignazioc

    dai, non demordete!!

  3. 5 Giugno 2011

    Enrico

    Wow che roba! La difficoltà aumenta esponenzialmente!

    Grazie infinite anche se lo ripeto a tutte le lezioni prof:-)

  4. 17 Giugno 2011

    Massimo

    Complimenti!! Io studio a ingegneria elettronica ma ho fatto molto prima a ripassarmi tutto qua che sulle dispense!! Spiegato tutto davvero in modo ottimo. Devo ammettere che avevo pochi dubbi su queste cose ma quei pochi sono stati risolti splendidamente 😉

  5. 18 Giugno 2011

    Spartan

    Ma è già finito il corso ?

  6. 21 Giugno 2011

    peppe

    quando continui con la prossima lezione???????

  7. 27 Giugno 2011

    Mab

    Si è interrotto il corso?

  8. 27 Giugno 2011

    ignazioc

    no, no ho pubblicato un post a riguardo…

  9. 5 Luglio 2011

    giuseppe

    puoi spiegare qui come mai non continua il corso?????????non ho trovato il post che hai pubblicato.ciao e grazie.

Leave a Reply

Your email address will not be published. Required fields are marked *


*
*

Corso online di programmazione android e java

SEZIONI

  • Android
  • Comunicazioni
  • Contest
  • Corsi ed Eventi
  • Corso completo di C
  • Corso programmazione videogiochi
  • Framework
  • Grafica e Design
  • Guida rapida alla programmazione Cocoa Touch
  • Guide Teoriche
  • Guide varie
  • iPad
  • Le nostre applicazioni
  • Libri e manuali
  • Materiale OpenSource
  • News
  • Pillole di C++
  • Progetti completi
  • Risorse utili
  • Strumenti di Sviluppo
  • Swift
  • Tips & Tricks
  • Tutorial Pratici
  • Video Tutorial
  • Windows Phone

Siti Amici

  • Adrirobot
  • Allmobileworld
  • Apple Notizie
  • Apple Tribù
  • Avvocato360
  • Blog informatico 360°
  • bubi devs
  • fotogriPhone
  • GiovaTech
  • iApp-Mac
  • iOS Developer Program
  • iPodMania
  • MelaRumors
  • Meritocracy
  • SoloTablet
  • TecnoUser
  • Privacy & Cookie Policy
©2009-2018 devAPP - All Rights Reserved | Contattaci
devAPP.it è un progetto di DEVAPP S.R.L. - Web & Mobile Agency di Torino
Str. Volpiano, 54 - 10040 Leini (TO) - C.F. e P.IVA 11263180017 - REA TO1199665 - Cap. Soc. € 10.000,00 i.v.

devACADEMY.it

Vuoi imparare a programmare?

Iscriviti e accedi a TUTTI i corsi con un’unica iscrizione.
Oltre 70 corsi e migliaia di videolezioni online e in italiano a tua disposizione.

ISCRIVITI SUBITO