Skillbook Logo
foto profilo

Categoria: Tutorials


Introduzione alla logica degli oggetti - Lezione 4

Gino Visciano | Skill Factory - 05/10/2018 22:44:13 | in Tutorials

In questa lezione parliamo di Ereditarietà, che insieme all'incapsulamento ed il polimorfismo, è uno dei più importanti paradigmi dell'Object Oriented.

CHE COS'E' L'EREDITARIETA'
L'ereditarietà è una tecnica di riuso del codice che permette di specializzare una classe già esistente, per crearne una nuova.

La nuova classe si chiama classe derivata, mentre la classe ereditata si chiama classe superiore, come mostra il diagramma UML seguente:

L'ereditarietà si dice singola se la classe derivata può ereditare una sola classe, mentre si dice multipla se la classe derivata può ereditare più classi contemporaneamente. Ad esempio  il linguaggio C++ permette anche l'ereditarietà è multipla, mentre  Java e C# permettono solo l'ereditarietà singola, il diagramma UML seguente mostra un esempio di ereditarietà è multipla:

 

 

Un classe Persona che contiene gli attributi seguenti: id, nome, cognome, dataDiNascita, luogoDiNascita e sesso, può essere specializzata in una classe Dipendente che, oltre agli altributi della classe Persona contiene anche gli attributi seguenti: stipendio e ruolo, come mostra il diagramma UML seguente:

Con la classe Dipendete adesso si possono istanziare oggetti che oltre a contenere il ruolo e lo stipendio, contengono anche id, nome, cognome, dataDiNascita, luogoDiNascita e sesso, come mostra il diagramma UML seguente:

Di seguito implementiamo l'esempio appena visto con il linguaggio c++.

Prima di tutto creiamo una classe Data per gestire oggetti di tipo data, servirà in seguito per assegnare la data di nascita alla persona:

Adesso creiamo la classe Persona, che specializzaremo successivamente in Dipendente:

Infine creaiamo la classe Dipendente, che eredita la classe superiore Persona:

GESTIONE DEI COSTRUTTORI PARAMETRIZZATI
Se la classe superiore ha un costruttore parametrizzato, usato per inizializzare gli attributi, la classe derivata lo deve eseguire altrimenti non può funzionare correttamente.

Il diagramma UML seguente, mostra in che modo il costruttore della classe derivata esegue il costruttore parametrizzato della classe superiore:

Vediamo lo stesso esempio scritto in linguaggio C++:

class Persona {
private:
string sesso;
public:
int id;
string nome;
string cognome;
Data *dataDiNascita;
string luogoDiNascita;
void setMaschio(){
        this->sesso="maschio";
}
void setFemmina(){
         this->sesso="femmina";
}
string getSesso(){
          if(sesso=="") sesso="maschio";
          return this->sesso;
}
Persona(){
     this->dataDiNascita=new Data();
}
Persona(int id,string nome,string cognome, Data *dataDiNascita,string luogoDiNascita, string sesso){
     if(sesso=="maschio")setMaschio();
     else setFemmina();
     this->dataDiNascita=new Data();
     this->id=id;
     this->nome=nome;
     this->cognome=cognome;
     this->dataDiNascita=dataDiNascita;
     this->luogoDiNascita=luogoDiNascita;
}

};

class Dipendente : public Persona {
public:
double stipendio;
string ruolo;
Dipendente(){}
Dipendente(int id, string nome,string cognome, Data *dataDiNascita,string luogoDiNascita, string sesso, double stipendio, string ruolo):Persona(nome, cognome, dataDiNascita, luogoDiNascita, sesso){
    this->stipendio=stipendio;
    this->ruolo=ruolo;}
}
};

OVERRIDE (SOVRASCRITTURA) DI METODI EREDITATI DALLA CLASSE SUPERIORE
L'override è la tecnica che permette di sovrascrivere un metodo ereditato da una classe superiore per modificarne il comportamento all'interno della classe derivata. L'override, insieme all'overload può essere definito plimorfismo dei metodi.

Immaginiate di avere nella classe Persona il metodo getInformazioni() che restituisce i valori di tutti gli attributi della classe separti da una virgola. Se la classe Persona viene ereditata dalla classe Dipendente, questo metodo dovrà essere necessariamete sovrascritto altrimenti nell'elenco di attributi restituito mancherà lo stipendio ed il ruolo del Dipendente.

In C++ un metodo della della classe superiore per essere sovrascritto nella classe derivata, deve essere virtuale, come mostra l'esempio seguente:

class Persona {
private:
string sesso;
public:
int id;
string nome;
string cognome;
Data dataDiNascita;
string luogoDiNascita;
void setMaschio(){
        this->sesso="maschio";
}
void setFemmina(){
        this->sesso="femmina";
}
string getSesso(){
           if(sesso=="") sesso="maschio";
           return this->sesso;
}

// Metodo virtuale che verrà sovrascritto nella classe Dipendente
virtual string getInformazioni(){
             return nome + ", "+cognome+", "+dataDiNascita.getData()+", "+luogoDiNascita+", "+sesso;
}

 

Persona(){
     this->dataDiNascita=new Data();
}
Persona(int id,string nome,string cognome, Data *dataDiNascita,string luogoDiNascita, string sesso){
     if(sesso=="maschio")setMaschio();
     else setFemmina();
     this->dataDiNascita=new Data();
     this->id=id;
     this->nome=nome;
     this->cognome=cognome;
     this->dataDiNascita=dataDiNascita;
     this->luogoDiNascita=luogoDiNascita;
}
};

class Dipendente : public Persona {
public:
double stipendio;
string ruolo;
// Sovrascrittura del Metodo getInformazioni ereditato dalla classe Persona
string getInformazioni(){
           // Conversione double in stringa
           stringstream strStipendio;
           strStipendio << this->stipendio;
           return nome + ", "+cognome+", "+dataDiNascita.getData()+", "+luogoDiNascita+", "+
getSesso()+", "+strStipendio.str()+", "+ruolo;
}

Dipendente(){}
Dipendente(int id,string nome,string cognome, Data *dataDiNascita,string luogoDiNascita, string sesso, double stipendio, string ruolo):
    Persona(id, nome, cognome, dataDiNascita, luogoDiNascita, sesso){
    this->stipendio=stipendio;
    this->ruolo=ruolo;}
};

INCAPSULAMENTO DEGLI ATTRIBUTI E DEI METODI DI UNA CLASSE IN CASO DI EREDITARIETA'
Nell'esempio precedente, quando viene sovrascritto il metodo getInformazioni() della classe Dipendente, l'attributo sesso è stato sostituito dal metodo getSesso().
Questa operazione è necessaria perché l'attributo sesso della classe Persona è privato. Gli elementi privati di una classe sono visibili solo ai metodi della stessa classe, mentre non sono visibili in alcun caso ai metodi di altre classi.
In questo caso, sovrascrivendo il metodo getInformazioni() nella classe Dipendente, diventa un metodo esterno alla classe superiore e non può più vedere l'attributo sesso.
Il metodo getInformazioni() della classe Dipendente, per leggere il valore dell'attributo sesso, lo può fare solo attraverso il metodo getSesso() della classe Persona perchè è pubblico, come mostra l'immagine seguente:

Per poter usare direttamente l'attributo sesso nel metodo getInformazioni() della classe Dipendente, bisogna impostarlo protected, come mostra l'immagine seguente:

Per chiarire meglio il ruolo dei modificatori di accesso approfondiamo insieme il diagramma UML seguente:

Osservando il diagramma si capisce che una classe derivata che eredita una classe superiore, può usare attraverso un metodo, senza istanziare, tutti i suoi elementi pubblici e protetti.
Infatti il metodo metodotSeconda() della classe Seconda vede:
   attributoPublic;
   attributoProtected;
   metodoPrimoA();
   metodoPrimoC()
.

Mentre non vede l'attributoPrivate perché è privato. Se fosse necessario accedere a questo attributo lo potrebbe fare solo attraverso l'uso dei metodi:
    metodoPrimoA();
    metodoPrimoC().

Invece una classe utilizzatrice, per usare attraverso un suo metodo, gli elementi di un'altra classe, le deve prima istanziare e attraverso l'oggetto creato può vedere solo gli elementi pubblici della classe istanziata.
Infatti il metodo metodotTerza() della classe Terza, attraverso l'oggetto s vede:
   s->attributoPublic;
   s->metodoPrimoA();
   s->metodoSeconda().

Mentre non vede:
   attributoPrivate
   attributoProtected;
   metodoPrimoC()
.

Se fosse necessario accedere agli attributi oppure ai metodi non visibili lo potrebbe fare solo attraverso l'uso dei metodi:
   s->metodoPrimoA();
   s->metodoSeconda()
.

Per rendere efficace questo argomento, vi suggerisco di implementare con il linguaggio C++  le classi Prima, Seconda e Terza ed analizzarne attentamente il comportamento.

EREDITARIETA' MULTIPLA
Il linguaggio C++ permette di ereditare più classi contemporaneamente in questo caso si parla di ereditarietà multipla, vediamo un esempio:

Immaginate di avere una classe Persona a cui volete aggiungere le informazioni dell'indirizzo ed i riferimenti principali. In questo caso la classe Persona potrebbe ereditare una classe Indirizzo ed una classe Riferimenti, come mostra il diagramma UML seguente: 

class Indirizzo{
public:
    string via;
    string cap;
    string citta;
    string provincia;
    Indirizzo(){}
};

class Riferimenti{
public:
    string telefonoCasa;
    string telefonoUfficio;
    string cellulare;
    string email;
    string social_1;
    string social_2;
    string social_3;
    Riferimenti(){}
};

class Persona : public Indirizzo, public Riferimenti{
private:
   string sesso;
public:
   int id;
   string nome;
   string cognome;
   Data *dataDiNascita;
   string luogoDiNascita;
   void setMaschio(){
            this->sesso="maschio";
   }
   void setFemmina(){
           this->sesso="femmina";
   }
   string getSesso(){
           if(sesso=="") sesso="maschio";
           return this->sesso;
   }
   Persona(){
           this->dataDiNascita=new Data();
   }
   Persona(int id,string nome,string cognome, Data *dataDiNascita,string luogoDiNascita, string sesso,
                   string via, string cap, string citta, string provincia, string telefonoCasa, string telefonoUfficio,
                   string email,string facebook, string linkedin, string skillbook){
                   if(sesso=="maschio")setMaschio();
                   else setFemmina();
                   this->dataDiNascita=new Data();
                   this->id=id;
                   this->nome=nome;
                   this->cognome=cognome;
                   this->dataDiNascita=dataDiNascita;
                   this->luogoDiNascita=luogoDiNascita;
                   this->via=via;
                   this->cap=cap;
                   this->citta=citta;
                   this->provincia=provincia;
                   this->telefonoCasa=telefonoCasa;
                   this->telefonoUfficio=telefonoUfficio;
                   this->email=email;
                   this->social_1=facebook;
                   this->social_2=linkedin;
                   this->social_3=skillbook;
                   }
};

Nella prossima lezione parleremo di Polimorfismo degli oggetti.


<< Lezione precedente


  Clicca qui per scaricare i laboratori di questa lezione  (Per eseguire i laboratori installate Code Block sul vostro computer)


Laboratori di Logica di Programmazione in C

 

Share Button

Impariamo a programmare con JavaScript - Lezione 16

Gino Visciano | Skill Factory - 01/07/2018 18:11:25 | in Tutorials

Benvenuti alla sedicesima lezione, in questa lezione impareremo a gestire un databese con JavaScript ed useremo per lo scambio dei dati il formato JSON (JavaScript Object Notation).

Che cos'è JSON
La struttura di JSON (JavaScript Object Notation) è semplicissima e permette di rappresentare il contenuto di oggetti da usare per lo scambio di dati, soprattutto all'interno di applicazioni JavaScript/Ajax.
E' simile all' XML (eXtensible Markup Language), anche se questo linguaggio viene maggiormente usato per la descrizione di documenti oppure per fornire informazioni di configurazione.
Attenzione, non ponetivi la domanda meglio XML o JSON, perché il loro utilizzo dipende principalmente dalle esigenze che avete oppure dagli strumenti che state usando.

Nell'esempio seguente vediamo come si può usare JSON in JavaScript per memorizzare i dati di un prodotto:

var prodotto = {
     "id" : '1',
     "nome":"Penna",
     "prezzo":'0.5',
     "descrizione":"Penna colore rosso",
     "id_categoria":'3'
}

Per visualizzare il contenuto dell'oggetto prodotto dovete usare la sintassi seguente:

console.log(prodotto.id);
console.log(prodotto.nome);
console.log(prodotto.prezzo);
console.log(prodotto.descrizione);
console.log(prodotto.id_categoria);

 

Tipi di dati in JSON
JSON supporta i seguenti tipi di dati:

Boolean ( true e false )
    "pagata" : true
Numeri
    "eta"  : '34'
Stringhe
    "nome" :  "Mario"
Array
    "contatti" : ["08112428", "rossi.alba@gmail.com",  "skp.rossi.alba"]

Array di oggetti
var prodotti=[ {
     "id" : '1',
     "nome":"Penna",
     "prezzo":'0.5',
     "descrizione":"Penna colore rosso",
     "id_categoria":'3'
}, {
     "id" : '2',
     "nome":"Matita",
     "prezzo":'0.2',
     "descrizione":"Matita a righe gialle",
     "id_categoria":'3'
}
]

Per visualizzare il contenuto dell'Array di oggetti prodotti dovete usare la sintassi seguente:

for(var x=0;x<2;x++){
   console.log(prodotti[x].id);
   console.log(prodotti[x].nome);
   console.log(prodotti[x].prezzo);
   console.log(prodotti[x].descrizione);
  console.log(prodotti[x].id_categoria);
}

Oggetti nidificati
var dipendente= {
"nome":"Mario",

"cognome":"Rossi",
"dataDiNascita":"20/05/1985",
"luogoDiNascita":"Roma",

"indirizzoResidenza":{"strada":"Piazza Fiume, 30","cap":"00100","provincia":"RM"},
"indirizzoDomicilio":{"strada":"Via Montenapoleone, 20","cap":"20100","provincia":"MI"},

"ruolo":"Programmatore",
"titoloDiStudio":"Laurea Triennale",
"stipendio":1.586}

 

Per visualizzare il contenuto dell'Oggetto nidificato dipendente dovete usare la sintassi seguente:

console.log(dipendente.nome);
console.log(dipendente.cognome);

console.log(dipendente.dataDiNascita);
console.log(dipendente.luogoDiNascita);
console.log(dipendente.
indirizzoResidenza.strada);
console.log(dipendente.
indirizzoResidenza.cap);
console.log(dipendente.indirizzoResidenza.provincia);
console.log(dipendente.
indirizzoDomicilio.strada);
console.log(dipendente.
indirizzoDomicilio.cap);
console.log(dipendente.indirizzoDomicilio.provincia);
console.log(dipendente.ruolo);

console.log(dipendente.titoloDiStudio);
console.log(dipendente.stipendio);

 

Come convertire un oggetto JSON in un oggetto JavaScript
Se i dati organizzati in formato JSON sono in formato testo oppure stringa, per trasformarli in oggetti JavaScript potete usare il metodo JSON.parse(testo) oppure eval("("+testo+")"), come mostrano gli esempi seguenti:

 

Esempio 1
var strProdotto='{"id":1,'+'"nome":"Penna","prezzo":0.5,"descrizione":"Penna colore rosso","id_categoria":3}'
var objProdotto=JSON.parse(strProdotto);
console.log(objProdotto.id);
console.log(objProdotto.nome);
console.log(objProdotto.prezzo);
console.log(objProdotto.descrizione);
console.log(objProdotto.id_categoria);

 

Esempio 2
var strProdotto='{"id":1,'+'"nome":"Penna","prezzo":0.5,"descrizione":"Penna colore rosso","id_categoria":3}'
var objProdotto=eval("("+strProdotto+")");
console.log(objProdotto.id);
console.log(objProdotto.nome);
console.log(objProdotto.prezzo);
console.log(objProdotto.descrizione);
console.log(objProdotto.id_categoria);


Che cos'è il CRUD
Il CRUD è l'insieme delle operazioni che servono per Inserire, Leggere, Modificare e Cancellare i dati di una tabella di un databese.

CRUD è l'acronimo di:

  • Create     [Inserimento]
  • Read       [Lettura]
  • Update   [Modifica]
  • Delete    [Cancellazione]

Per creare un'applicazione che vi permette di gestire il CRUD servono gli strumenti seguenti:

  1. Visual Studio Code
  2. MySQL
  3. Express.js

Visual Studio Code
Visual Studio Code è un IDE (Integrated development environment), un ambiente di sviluppo integrato che serve per scrivere applicazioni.
Per scaricare questo programma clicca qui.

   

Dopo il download del file, dovete lanciarlo per installare il programma.

MySQL
MySQL è il nostro DBMS (Database Management System).
Per installare questo programma dovete scaricare XAMPPcliccate qui per avviare il download.

Per ricevere maggiori informazioni su MySQL cliccate qui.

Express.js
Express è un framework per creare applicazioni web Node.JS.
Per Installare il framework create la cartella app-prodotti, attivatela ed eseguite il comando:

npm install express

Laboratorio
In questo Laboratorio creiamo una semplice applicazione per gestire Prodotti.

Per iniziare create la cartella app-prodotti, spostatevi nella cartella ed installate i moduli seguenti:

npm install mysql

npm install body-parser

Dopo l'installazione dei due moduli, lanciate Visual Studio Code, selezionate  apri cartella, aprite la cartella app-prodotti e successivamente selezionate nuovo file (ctrl n).
 


Prima di tutto, con il comando require caricate tutti i moduli che servono per creare l'applicazione, come mostra l'immagine seguente:

Per salvare il file, premete alt f, cliccate sulla voce salva, inserite il nome AppProdotti.js e cliccate sul pulsante salva.
(La stessa cosa la potete fare premendo ctrl s)

Come creare il Server Web
Con il framework Express la creazione di un Server Web è un'operazione molto semplice, il codice JavaScript seguente vi permette di creare i metodi GET e POST ed avviare il server sulla porta 8090.

app.get('*', function (request, response) {
...
});
app.post('*' , function (request, response, next ) {

...
});
app.listen(8090, function () {
    console.log('listening on port 8090.');
});

I metodi app.get ed app.post si attivano ogni volta che arriva una richiesta di tipo GET oppure POST ed eseguono la funzione function (request , response) {...}.

L'argomento request è la request, l'oggetto che contiene i parametri inviati dal server, l'argomento response è la response l'oggetto usato per inviare le risposte al client.

Con Express per leggere i parametri da una request di tipo GET dovete usare la proprietà query, come mostra l'esempio seguente:

req.query.nomeparametro;

Se la request è di tipo POST dovete usare la proprietà body, come mostra l'esempio seguente:

req.body.nomeparametro;

La funzione app.listen è una funzione di callback, serve ad attivare il server web che restrà in ascolto sull'indirizzo ip di default 127.0.0.1 (localhost), utilizzando la porta 8090.  

I metodi app.get ed app.post verranno implementati dopo.

Come creare il Database dbprodotti
Per utilizzare la nostra applicazione dobbiamo creare il database dbprodotti, per farlo seguite le operazioni seguenti:
 

cliccate sull'icona di XAMPP

Quando appare la maschera seguente, avviate prima Apache e poi MySQL come indicato:

Successivamente per lanciare MySQL, dovete cliccare sul pulsante ADMIN.

La maschera seguente mostra come appare il Pannello di Controllo di MySQL, con a sinistra i Database creati e in alto le schede di gestione. 

A questo punto, selezionando la scheda SQL, potete creare il Database eseguendo uno alla volta i comandi SQL seguenti:

1) create database dbprodotti;

Ognuno dei comandi seguenti devono essere eseguiti insieme al comando:

use dbprodotti;

2) create table prodotti(id int primary key auto_increment, prodotto varchar(50) not null, id_categoria int not null);

3) create table categorie(id int primary key auto_increment, categoria varchar(50) not null);

4) 

INSERT INTO categorie (id, categoria) VALUES
(1, 'Abbigliamento'),
(2, 'Sport'),
(3, 'Arredamento'),
(4, 'Casalinghi'),
(5, 'Alimentari');

 

Come connettersi al Database MySQL
Per connettersi al database dbprodotti dovete creare l'oggetto connection utilizzando la funzione mysql.createConnection({ .. }), come mostra l'esempio seguente:

var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'nomeutente',
  password : 'password',
  database : 'nomedatabase'
});

Nel nostro caso:

var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : ''
  database : 'dbprodotti'
});

La password non è stata indicata perché l'utente root non ha una password.

Successivamente per attivare la connessione usate il comando seguete:

connection.connect(function(err){

if(!err) {
    console.log('Connessione eseguita con successo!!!');    
} else {
    console.log('Errore di connessione!!!');    
}
});

Per chiudere la connessione dovete usare il comando:

connection.end();

Come eseguire le operazioni di CRUD
Per eseguire le operazioni di CRUD dovete conoscere il linguaggio SQL, per chi ne avesse bisogno, può apprendere velocemente l'SQL cliccando sul link seguente:

Ricominciamo .. dal linguaggio SQL

Con JavaScript possiamo eseguire  comandi SQL con la funzione query, dell'oggetto connection.

Vediamo gli esempi principali: 

- Create (Inserimento)
connection.query("INSERT INTO prodotii (prodotto, id_categoria) VALUES (?, ?)"), ['Camicia', 1'], function(err, result) { ... }

  1. connection.query -> funzione JavaScript;
  2. INSERT INTO prodotii (prodotto, id_categoria) VALUES (?, ?) -> comando SQL;
  3. ?, ?  -> parametri ;
  4. ['camicia', 1] -> valori dei parametri;
  5. function(err, result) { ... } -> funzione eseguita dopo l'esecuzione del comando SQL;
  6. err -> si usa nel caso in cui l'esecuzione del comando SQL non va a buon fine;
  7. result -> si usa nel caso in cui l'esecuzione del comando SQL va a buon fine.


- Update (Modifica)
connection.query("UPDATE prodotti set id_categoria=? where id=?"), [2,1], function(err, result) { ... }

- Delete (Cancellazione)
connection.query("DELETE FROM prodotti where id=?"), [1], function(err, result) { ... }

- Read (Lettura e Visualizzazione)
connection.query("SELECT * FROM prodotti", function (err, result, fields) {
 if (err) throw err;
     for (var i in result) {
            console.log(result[i]);
     }
});

 

Share Button

Laboratori di Logica di Programmazione in C- Lezione 5

Gino Visciano | Skill Factory - 26/05/2018 17:17:57 | in Tutorials

Benvenuti, in questa lezione, attraverso i laboratori proposti, vedrete le principali tecniche di programmazione.


S O M M A R I O
LAB01: COME SOSTITUIRE IL COMANDO GOTO
LAB02: COME SI CREA UN MENU DI SCELTA UTILIZZANDO UN FLAG
LAB03: COME SI RIPETE UN PROGRAMMA
LAB04: TECNICHE DI SORT
LAB05: RICERCA SEQUENZIALE O LINEARE

LAB06: RICERCA DICOTOMICA O BINARIA
LAB07: ROTTURA DI CODICE
LAB 8: IMPAGINAZIONE DI UNA SEQUENZA DI DATI

ELENCO DELLE LEZIONI
DOWNLOAD LABORATORI


LAB01: COME SOSTITUIRE IL COMANDO GOTO
L'istruzione GOTO permette di saltare ad una particolare riga di programma oppure in una posizione del programma dove è presente un'etichetta.
L'uso del GOTO non è consigliato perchè rende i programmi poco leggibili, creando il famoso spaghetti huose, ovvero percorsi logici difficili da seguire e spesso incomprensibili.

Per evitare i problemi creati dall'istruzione GOTO la possiamo sostituire con un ciclo do - while. Il do deve essere posizionato nel punto dove saltare, perché sostituisce l'etichetta, mentre il while va messo al posto del GOTO, come mostra l'esempio seguente:

 

LAB02: COME SI CREA UN MENU DI SCELTA UTILIZZANDO UN FLAG
Per creare un menu di scelta vi servono le seguenti strutture di programmazione:
1) Ciclo do - while, per ripetere la visualizzazione del menu;
2) Struttura condizionale switch - case - default, per gestire la scelta fatta.

Un flag è una variabile numerica oppure booleana usata per ripetere un ciclo oppure per attivare o meno una scelta condizionale.

In C un flag corrispnde a vero se contiene un valore diverso da 0, altrimenti è falso.
In questo laboratorio usiamo un flag vero per visualizzare di nuovo il menu di scelta.
Impostando il flag a falso (scelta 5), il programma termina.

 

LAB03: COME SI RIPETE UN PROGRAMMA
Per creare un menu di scelta vi servono le seguenti strutture di programmazione:

1) Ciclo do - while esterno, permette di ripetere il programma;
2) Ciclo do - while interno, permette di inserire di nuovo la risposta se non si risponde con s oppure n;
3) Struttura condizionale if - else, viene usata per conrollare se la risposta fornita è s oppure n. Nel caso che i caratteri sono diversi da s oppure n viene stampato un messaggio d'errore e viene richiesta la risposta, altrimenti viene impostato il flag a false ed il controllo passa al do - while esterno.

La funzione tolower trasforma in minuscolo il valore della risposta.
 

LAB04: TECNICHE DI SORT
Per ordinare una collezione di dati, esistono diverse tecniche di sort, le più usate sono le seguenti:

- Selection Sort
- Bubble Sort
- Insertion Sort
- Merge Sort
- Quick Sort

Per poter eseguire il sort di una collezione di dati è importate confrontare tutti gli elementi da ordinare in modo crescente o decrescente e scambiarli (SWAP) se le loro posizioni non corrisponde al tipo di ordinamento scelto.

Lo SWAP è la tecnica che serve per invertire il contenuto di due variabili, questa tecnica richiede l'uso di una variable temporanea usata per conservare provvisoriamente il valore di un delle due variabili da invertire. L'immagine seguente mostra come si applica lo SWAP:

Negli esempi seguenti vediamo un selection sort ed bubble sort applicati ad array numerici.

SELECTION SORT

BUBBLE SORT

 

LAB05: RICERCA SEQUENZIALE O LINEARE
Per ricercare un valore in una collezione di dati, come ad esempio un vettore d'interi, serve un ciclo for che permette di scorrere tutti i valori della collezione e confrontarli con il valore cercato, come mostra l'esempio seguente:

LAB06: RICERCA DICOTOMICA O BINARIA
Per ricercare un valore in una collezione di dati, come ad esempio un vettore d'interi, oltre alla ricerca sequenziale potete usare anche la ricerca dicotomica molto più performante.
Per esegure questo tipo di ricerca detta anche binaria la collezione di dati deve essere ordinata.
L'esempio seguente mostra come usare questa tecnica per ricercare un valore in un vettore d'interi ordinato in modo crescente:

 

LAB07: ROTTURA DI CODICE
La  rottura di codice è una tecnica applicata per analizzare sequenze di dati organizzate in base ad una chiave comune chiamata codice. Tutte le volte che la chiave scelta cambia, si verifca una rottura di codice.
Ad ogni cambiamento di codice vengono visualizzate le statistiche della chiave corrente (conteggio, somma, media, max e min) e si ricominciano a calcolare quelle della nuova chiave.
L'immagine seguente mostra la tecnica della rottura di codice applicata ad un vettore d'interi, in questo caso alla chiave corrisponde il valore del numero.

L'esempio seguente mostra come calcolare la frequenza e la somma dei numeri interi uguali presenti in un vettore, utilizzando la rottura di codice:

LAB 8: IMPAGINAZIONE DI UNA SEQUENZA DI DATI
L'impaginazione è una tecnica di programmazione fondamentale per visualizzare sequenze di dati memorizzati in array oppure tabelle.
L'impaginazione deve permettere l'organizzazione dei dati da visualizzare in pagine di lunghezza predefinita e consentire la navigazione tra le pagine con la seguente modalità:

- Vai alla prima pagina;
- Vai all'ultima pagina;
- Vai alla pagina precedente;
- Vai alla pagina successiva.

 


Per gestire la navigazione sono importanti le informazioni seguenti:

1) Numero di righe per pagina;
2) Numero totale di pagine;
3) Pagina corrente;
4) Offset, valore che corrisponde alla posizione della prossima riga da leggere.

Per calcolare il numero totale di pagine dobbiamo dividere il numero totale di righe, della serie di dati da visualizzare, per la lunghezza della pagina e arrotondare per eccesso, come mostra la formula seguente:

totalePagine=ceil(totaleRighe/lunghezzaPagina);

L'Offset lo possiamo calcolare con la formula seguente:

offset=(paginaCorrente-1)*lunghezzaPagina;

L'esempio seguente mostra come impaginare un vettore di nomi:

 


LABORATORI DI LOGICA DI PROGRAMMAZIONE IN C
LEZIONE 1
LEZIONE 2
LEZIONE 3
LEZIONE 4
LEZIONE 5


D O W N L O A D   L A B O R A T O R  I
Clicca qui per il download dei laboratori.

 

 

Share Button

Introduzione alla logica degli oggetti - Lezione 3

Gino Visciano | Skill Factory - 06/04/2018 00:17:32 | in Tutorials

In questa lezione iniziamo a descrive in modo più dettagliato l'architettura delle applicazioni software ad oggetti.

Nella lezione precedente abbiamo visto che oggi le applicazioni software sono insiemi di componenti che collaborano tra loro per per soddisfare le specifiche funzionali richieste.

Gli oggetti che compongono le applicazioni sono di tre tipi:

1) MODEL - Contengono dati (sono entità).
2) VIEW - Hanno il compito di permettere la visualizzazione oppure l'inserimento dei dati negli oggetti di tipo MODE, ad esempio in un'applicazione Web corrispondono alle Pagine HTML, mentre in un'applicazione Desktop corrispondono alle interfacce grafiche (GUI).
3) CONTROLLER, che hanno il compito di gestire il flusso logico applicativo. Un controller può svolgere anche il ruolo di servizio, mettendo a disposizione dell'applicazioni in cui è presente, funzionalità oppure azioni specifiche, che si possono richiamare attraverso i metodi dell'interfaccia esposta.

I simboli UML (Unified Modeling Language) che si usano per indicare i tre tipi di oggetti utilizzati per creare le applicazioni software, sono i seguenti:

Il diagramma UML che descrive l'architettura di un'applicazione software si chiama "Diagramma dei Componeti".

Diagramma dei componenti che descrive il processo di login di un'applicazione.

 

COME SI CREANO I COMPONENTI DELLE APPLICAZIONI
I componenti delle applicazione software si creano con i linguaggi di programmazione ad oggetti, questi linguaggi si differenziano da quelli procedurali o funzionali perché si basano prevalentemente sull'uso di classi ed oggetti e permettono d'implemetare i seguenti paradigmi di programmazione:

1) Incapsulamento;

2) Polimorfismo di metodi ed oggetti;

3) Ereditarietà.

I principali linguaggi di programmazione ad oggetti sono:

1) C++ (pronuncia: c plus plus);

2) Java (pronuncia: giava);

3) C# (pronuncia: c sharp);

4) Python (pronuncia: paiton).

Per i nostri esempi useremo il C++ il linguaggio di programmazione ad oggetti più insegnato nelle scuole superiori.


CLASSI ED OGGETTI
Le Classi  sono template creati dai programmatori, con i linguaggi di programmazione ad oggetti, servono per creare gli oggetti.
L'esempio seguente mostra una classe scritta in C++, che definisce il template di un oggetto di tipo Persona:

class Persona {
    private:
    string nome;
    string cognome;
    int eta;
    public:
    void setNome(string nome){
            this->nome=nome;
        };
    void setCognome(string cognome){
            this->cognome=cognome;
        };
    void setEta(int eta){
            this->eta=eta;
        };
     string getNome(){
            return this->nome;
        }
     string getCognome(){
            return this->cognome;
        }
    int getEta(){
            return this->eta;
        }
    Persona(){};
    Persona(string nome, string cognome, int eta){
            this->nome=nome;
            this->cognome=cognome;
            this->eta=eta;
        }
};

<Per approfondire la conoscenza del linguaggio C clicca qui.>

 

Gli Oggeti sono istanze delle Classi, istanziare significa creare un oggetto in memoria utlizzando la classe corrispondente.
Con la stessa classe si possono creare tanti oggetti dello stesso tipo.

L'esempio seguente mostra come s'istanzia l'oggetto persona di tipo Persona:

Attenzione *persona diventerà il puntatore che conterrà l'indirizzo dove è stato allocato l'oggetto costruito con il comando new.

I metodi e gli attributi degli oggetti istanziati possono essere usati associando il nome dell'oggetto all'elemento che si vuole usare con il simbolo ->, come mostra l'esempio seguente:

persona->setNome("Mario");
persona->setCognome("Rossi");
persona->setEta(35);

Le Classi definiscono il tipo di oggetto che state usando nell'applicazione, in fase di progettazione per disegnare una classe con il linguaggio UML (Unified Modeling Language) dovete usare un "Diagramma di Classe".

L'esempio seguente mostra il diagramma di classe dell'oggetto persona:


Per convenzione i nomi delle Classi iniziano sempre con la lettera maiuscola, se sono composti da più parole, devono iniziare tutte con la lettera maiuscola.
I nomi degli Oggetti  sono sempre scritti in minuscolo, se sono composti da più parole, le altre parole devono iniziare con la lettera maiuscola.

Gli Oggetti sono  Componenti  che contengono i seguenti elementi:

- attributi
- metodi
- costruttori

I programmatori per capire come sono fatti i componenti di un'applicazione e qual è il loro stato, devono leggere rispettivamente il  "Diagrammi di Classe" e il "Diagrammi degli Oggetti".

Nell'esempio seguente, il "Diagramma di componete" a sinistra, indica che il componete applicativo persona è un MODEL.
Il "Diagramma di Classe" al centro ne descrive la struttura  ed il tipo, infatti corrisponde alla classe Persona.
Il "Diagramma di Oggetto" a destra ne descrive lo stato in memoria dopo che è stato istanziato (creato), il Titolo del diagramma: persona:Persona indica rispettivamente il nome dell'oggetto e la classe corrispondente, cioè il tipo.

 

 

INCAPSULAMENTO
L'Incapsulamento è una proprietà dei linguaggi di programmazione ad oggetti, permette di utilizzare dei modificatori di accesso per regolare la visibilità degli elementi di una classe (attributi, metodi e costruttori), verso i metodi di altre classi che vogliono usarli.

I modificatori di accesso più usati sono:

1) public (in un diagramma UML corrisponde al segno +);

2) private (in un diagramma UML corrisponde al segno -);

3) prrotected (in un diagramma UML corrisponde al segno #), si comporta come private in caso d'istanza, come public in caso di ereditarietà, come vedremo nelle prossime lezioni;


ATTRIBUTI
Gli Attributi sono variabili che contengono informazioni, si possono definire le proprietà dell'oggetto. Ad esempio nei MODEL, gli attributi si usano per memorizzare i dati delle entità corrispondenti, come mostra l'esempio seguente:


persona->nome="Mario";
persona->cognome="Rossi";
persona->eta=30;

persona contiene l'indirizzo dell'oggetto a cui facciamo riferimento;
nome è un attributo dell'oggetto.

Gli Attributi  possono essere usati direttamente, come nell'esempio, da metodi di altre classi, solo se sono pubblici (+), se gli Attributi in una classe sono privati (-)  sono visibili solo ai metodi della stessa classe.

Quindi l'unico modo per gestire gli  Attributi privati di una classe è quello di usare i Metodi ed i Costruttori pubblici presenti nella stessa classe.

 

METODI
I Metodi sono funzioni che eseguono operazioni, le azioni dei Metodi determinano il comportamento ed il ruolo dell'oggetto.
I linguaggi di programmazione ad oggetti, permettono di scrivere le istruzioni necessarie per implementare la logica delle applicazioni, unicamente all'interno dei Metodi.

I  Metodi che hanno il nome che inizia con i prefissi get e set si usano per assegnare o leggere i valori degli Attributi privati dell'oggetto a cui appartengono. 
Ad esempio,  dato che gli  Attributi della clappe  Persona sono privati, per gestirli sono stati creati i seguenti Metodi pubblici:

- setNome
- getNome
- setCognome
- getCognome
- setEta
- getEta 

Nell'esempio seguente vediamo come si possono assegnare i valori agli  Attributi privati dell'oggetto  persona usando i  Metodi  set corrispondenti:

persona->setNome("Mario");
persona->setCognome("Rossi");
persona->setEta(30);

Mentre nel prossimo esempio vediamo come si possono leggere i valori degli  Attributi privati dell'oggetto  persona usando i  Metodi  get corrispondenti:

String nome = persona->getNome();
String cognome = persona->getCognome();
int eta = persona->getEta();

I Metodi se sono pubblici possono essere eseguiti anche dai Metodi di altri oggetti, se sono privati possono essere eseguiti solo dai Metodi dello stesso oggetto, perché non sono visibili a metodi di altre classi.
 

POLIMORFISMO DEI METODI
Il polimorfismo dei metodi detto anche Overload è una prorpietà dei linguaggi di programmazione ad oggetti, permette di usare metodi con lo stesso nome, ma firma diversa.
La firma di un metodo è composta dal nome del metodo più i tipi degli argomenti passati al metodo, come mostra l'immagine seguente:

Vediamo un esempio di Overload in C++:

Immaginate di voler colorare una figura geometrica, dando la possibilità al programmatore di usare le seguenti modalità d'impostazione del colore:

1) fornire direttamente il nome del colore da assegnare alla figura geometrica sotto forma di stringa;

2) indicare il colore da assegnare alla figura geometrica con un numero intero;

3) fornire i codici RGB del colore da assegnare alla figura geometrica.

Per evitare di assegnare nomi diversi ai metodi per colorare la figura geometrica,  dato che per ogni modalità d'impostazione del colore si usano tipi sono diversi, possiamo usare l'Overload.

class ColoraFiguraGeometrica{
// Attributi privati non visibli a metodi di altre classi classi
private:
string tipoFigura;
string coloreFigura;
// Metodi pubblici visibli a metodi di altre classi classi
public:
// Restituisce il tipo di figura geometrica
string getTipoFigura(){
return this->tipoFigura;
}
// Restituisce il colore della figura geometrica
string getColoreFigura(){
return this->coloreFigura;
}
// 1-Overload Firma = setColore string
void setColore(string colore){
    this->coloreFigura=colore;
}
// 2-Overload Firma = setColore int
void setColore(int colore){
    switch(colore){
    case 1:
         this->coloreFigura="Rosso";
         break;
    case 2:
         this->coloreFigura="Verde";
         break;
    case 3:
         this->coloreFigura="Giallo";
         break;
    default:
         this->coloreFigura="Nero";
         break;
    }
}
// 3-Overload Firma = setColore int int int
void setColore(int r,int g, int b){
        stringstream sr;
        stringstream sg;
        stringstream sb;
        sr << r;
        sg << g;
        sb << b;
        this->coloreFigura="R="+sr.str()+", G="+sg.str()+"B="+sb.str();
}
// Costruttore parametrizzato usato per indicare il tipo di figura geometrica
ColoraFiguraGeometrica(string tipoFigura){
      this->tipoFigura=tipoFigura;
}
};

<Per approfondire la conoscenza del linguaggio C clicca qui.>


COSTRUTTORI
I Costruttori sono Metodi che si usano per istanziare gli oggetti, vanno sempre indicati dopo il comando new usato per creare un oggetto, come mostra l'esempio seguente:

 

 

I Costruttori servono per inizializzare gli Attributi degli oggetti istanziati.

Ci sono due tipi costruttori, quello di base, senza parametri e quello parametrizzato, usato per inizializzare gli Attributi dell'oggetto con valori esterni, si riconoscono perché hanno lo stesso nome della Calsse e nella loro dichiarazione non è indicato il tipo restituito,

I Costruttori sono sempre pubblici, solo gli oggetti di tipo Singletone, particolari oggetti che possono essere istanziati una sola volta, hanno il costruttore privato.
 

COMUNICAZIONE E COLLABORAZIONE TRA COMPONENTI
Gli elementi pubblici di un oggetto rappresentano la sua Interfaccia. Come avviene anche per i componenti elettronici, l'Interfaccia viene usata per permettere la comunicazione con gli altri componenti.

 

 

Ad esempio l'Interfaccia dell'oggetto persona è la seguente:

- setNome
- getNome
- setCognome
- getCognome
- setEta
- getEta 

Gli attributi dell'oggetto persona non sono visibili, perche sono privati, quindi non appartengono all'interfaccia.

I Metodi degli oggetti che devono gestire l'oggetto persona lo fanno attraverso la sua interfaccia, come mostra Il "Diagramma dei Componeti" seguente:

Il simbolo usato in UML per rappresentare un'interfaccia è il lecca lecca (lollipop).

Quindi il metodo  di un componente applicativo (oggetto), per comunicare e  collaborare con un altro componente, usando i metodi e gli attributi pubblici della sua interfaccia, lo deve prima istanziare con il comando new, successivamente usando il riferimento del componente creato, può usare tutti gli elementi della  sua interfaccia.

In pratica il riferimento contiene l'indirizzo dell'oggetto che espone l'interfaccia, come mostra l'immagine seguente:

L'APPLICAZIONE GESTIONE PERSONE
Adesso vediamo quali sono i passaggi fondamentali per creare un'applicazione che permette di gestire persone.

Prima di tutto disegniamo il diagramma UML che mostra i principali  componenti applicativi e in che modo collaborano tra loro:

                                                            Figura 1

Analizzado i componenti del diagramma in Figura 1, vediamo che il componente gestionePersone, ha il ruolo di controller. Questo oggetto attraverso l'uso di due viewinserimeto_persona e visualizza_persona, permette di gestire i componenti persona,  che hanno  il ruolo di model.

Il Diagramma di Classi seguente, mostra la struttura degli oggetti che compongono l'applicazione Gestione Persone.

COME SI GESTISCE IL FLISSO LOGICO (PROCESSO) DELL'APPLICAZIONE GESTIONE PERSONE
Il metodo main() della classe GestionePersone , il controller, permette d'implementare il flusso logico dell'applicazione per gestire le persone.

Per fare questo lavoro, il metodo main()  esegue le seguenti operazioni:

1) usa il metodo inserimentoPersona() per  permette l'inserimento dei dati attraverso la maschera "Inserimento Persona" (Figura 2);


                                              Figura 2

2) usa i metodi set dell'intercaccia dell'oggetto persona:

persona->setNome(nome);
persona>setCognome(cognome);
persona->setEta(eta);

per memorizza i dati inseriti della maschera all'interno dell'oggetto persona;

3) usa Il metdo visualizzaPersona(persona:Persona) per visualizzare attraverso la maschera "Visualizza Persona" (Figura 3) il contenuto dell'oggeto persona.
Questo metodo usa i metodi get dell'intercaccia dell'oggetto persona:

persona->getNome();
persona>getCognome();
persona->getEta();

per leggere i dati memorizzati negli attributi dell'oggetto persona e visualizzarli nella maschera.


                                              Figura 3


Il Diagramme delle Attività in Figura 4, mostra il flusso delle attività svolte dal metodo  inserimentoPersona() per gestire l'inserimento dei dati nell'oggetto persona:

                                      Figura 4

Nella prossima lezione parleremo di Ereditarietà, per riusare e specializzare classi già esistenti.


<< Lezione precedente           Lezione successiva >>


Laboratori di Logica di Programmazione in C

Share Button

Laboratori di Logica di Programmazione in C- Lezione 4

Gino Visciano | Skill Factory - 25/03/2018 19:49:40 | in Tutorials

Benvenuti, nelle lezioni precedenti, per svolgere i nostri laboratori, abbiamo usato diverse funzioni, includendole  nei programmi attraverso librerie predefinite. in questa lezione introduciamo il concetto di funzioni definite dall'utente, con l'obiettivo di creare librerie di funzioni personalizzate.

Una funzione è un task di programmazione che qundo viene eseguito, può avere da 0 ad n dati in ingresso detti argomenti oppure parametri e restituire da 0 ad 1 risultato.
Le funzioni sono BLACK - BOX che restituiscono sempre lo stesso risultato se vengono passati gli stessi argomenti. 

Una funzione che non restiruisce  un risultato viene chiamata procedura.

L'uso delle funzioni e delle procedure rende i programmi più compatti ed affidabili, riduce i tempi di sviluppo e diventa più semplice testarli.

Il linguaggio C oltre ad essere Imperativo (composto da istruzioni e strutture logiche di programmazione), è anche Funzionale, perché permette sia di creare funzioni personalizzate, sia di usare funzioni di libreria che arricchiscono le potenzialità del linguaggio.

STRUTTURA DI UNA FUNZIONE

Se un funzione non restituisce un risultato, ovvero è una procedura, come tipo restituito dovete indicare void.

Gli argomenti di una funzione sono variabili locali, cioè sono visibili solo all'inteno della funzione,  quando la funzione termina non esistono più.
Nel corpo della funzione divisione gli argomenti dividendo e divisore vengono utilizzati per eseguire il calcolo richiesto.
Il risultato del calcolo viene assegnato alla variabile locale risultato che è anche il valore restituito con il comando return.

L'esempio seguente mostra come utilizzare la funzione divisione:

Esempio 1

#include <stdio.h>

/* Dichiarazione della funzione divisione */
double divisione(double dividendo, double divisore);
int main(){
/* %lf visualizza dove viene inserito il contenuto della variabile double corrispondente */
printf("Risultato %.2lf/%.2lf=%.2lf",15.0,3.0,divisione(15.0,3.0));
return(0);
}

/* Implementazione della funzione divisione */
double divisione(double dividendo, double divisore){
double risultato;
if (divisore>0){
    risultato=dividendo/divisore;
     } else {
    risultato=-1;
   }
return risultato;
}

PASSAGGIO DI ARGOMENTI ALLE FUNZIONI PER VALORE

Di default quando si passano gli argomenti ad un funzione, vengono passati per valore. Questo significa che vengono create nuove variabili locali all'interno dell'area di memoria che appartiene alla funzione e quando la funzione termina non esistono più, come mostra lo schema seguente:

1) In main è presente la variabile risultato=0.0;
2) Quando si esegue la funzione divisione, in main risultato=0.0, mentre in divisione vengono create tre variabili:
     risultato=0.0;
     dividendo=15.0;
     divisore=3.0;
3) Quando si esegue il calcolo in divisione risultato diventa 5.0;
4) Quando termina la funzione divisione, tutte le variabili locali di divisione vengono cancellate e per effetto del return risultato di main diventa uguale a 5.0.

PASSAGGIO DI ARGOMENTI ALLE FUNZIONI PER RIFERIMENTO

In C un riferimento è un indirizzo di memoria dov'è memorizzato un valore, come  mostra l'immagine seguente:

In realtà tutte le variabili, per gestire i contenuti corrispondenti, usano riferimenti (posizioni/indirizzi di memoria), in C per ottenere il riferimento associato ad una variabile basta far precedere il nome da una &, come mostra l'esempio seguente:

&a => A00FF011 => 10 (valore corrispondente in memoria).

Le variabili che contengono un riferimento si chiamano puntatori, si distinguono dalle variabili classiche perchè i nomi sono preceduti da un *, come mostra l'esempio seguente:

Esempio 2

int main(){
    int a=10;
    int *p=&a;
    printf("a=%d, *p=%d, p=%p", a, *p, p);
}

a=>nome varibile intera che contiene il valore 10;
*p=nome puntatore, attraverso il riferimento (indirizzo) assegnato permette di gestire il valore 10, ha lo stesso compostamento della variabile a;
p= nome varibile che contiene il riferimento (indirizzo) del valore 10;

quindi se *p=&a, allora:

a => 10:
*p => 10;
p => A00FF011.

Infatti, eseguendo l'esempio 2, si ottiene l'outpit seguente:

Per capire a cosa servono i puntatori ed i riferimenti facciamo due esemp:i

Immaginate di voler creare una funzione che inverte i valori contenuti in due variabili a e b.

Nel primo caso creiamo la funzione inverti e passiamo a e b  per valore, come nell'esempio seguente:

Esempio 3

void inverti(int a, int b);
int main(){
    int a=10;
    int b=20;
    printf("1) Main[a=%d - b=%d]\n",a,b);
    inverti(a,b);
    printf("3) Main[a=%d - b=%d]\n",a,b);
   return(0);
}

void inverti(int a,int b){
    int temp;
    temp=a;
    a=b;
    b=temp;
    printf("2) Inverti[a=%d - b=%d]\n",a,b);
}

Osservando i risultati potete capire che la funzione inverti ,con il passaggio degli argomenti per valore, ha invertito a e b locali, mentre a e b di main sono rimasti gli stessi.
Questo significa che quando eseguiamo una funzione e passiamo gli argomenti attesi per valore, viene creata una copia di quelli originali, come mostra lo schema seguente:

Nel secondo caso creiamo la funzione inverti, ma questa volta non passiamo i valori di a e b, ma i loro  riferimenti.

Passando alla funzione inverti i riferimenti di a e b, diventa posibile modificare direttamente i loro valori, naturalemente gli argomenti della funzione inverti non sono variabili ma puntatori, come mostra l'esempio seguente:

Esempio 4

void inverti(int *a,int *b);
int main(){
    int a=10;
    int b=20;
    printf("1) Main[a=%d - b=%d]\n",a,b);
    inverti(&a,&b);
    printf("3) Main[a=%d - b=%d]\n",a,b);
   return(0);
}

void inverti(int *a,int *b){
    int temp;
    temp=*a;
    *a=*b;
    *b=temp;
    printf("2) Inverti[a=%d - b=%d]\n",*a,*b);
}

Osservando i risultati, adesso vediamo che passando alla funzione inverti i riferimenti di a e b, cioè &a ed &b,  i valori di a e b di main sono stati invertiti.

Lo schema seguente descrive cosa accade in memoria durante l'esecuzione del programma:

 

FUNZIONI RICORSIVE

In C le funzioni sono ricorsive, questa proprietà è molto importante perché, grazie alla ricorsività, una funzione può richiamare se stessa.
Per capire praticamente la ricorsione vediamo un esempio.

Calcoliamo il fattoriale di un numero n, valore che si indica con il simbolo:

n!

Per cacloare Il fattoriale di un numero n dovete moltiplicare tra loro tutti i numeri compresi tra 1 ed n, come mostra la formula seguente:

1 * 2 * ... * n-1 * n

Ad esempio:

0! = 1 per convenzione;
1! = 1 * 1 = 1;
2! = 1 * 2 = 2;
3! = 1 * 2 * 3 = 6.

L'esempio seguente mostra come calcolare il fattoriale di n utilizzando una funzione ricorsiva in C.

Esempio 5

int fattoriale(int numero);
int main(){
   int numero;
   printf("Calcolo del Fattoriale\n");
   printf("\nNumero:");
   /* %d = input numerico,
   &numero passiamo alla funzione scanf il riferimento della variabile numero */

   scanf("%d",&numero);
   printf("Fattoriale di %d = %d\n", numero, fattoriale(numero));
   return(0);
}
int fattoriale(numero){
    if (numero==0)
        return 1;
    else
        return numero * fattoriale(numero-1);
}

La funzione fattoriale richiama in modo ricorsivo se stessa, passando ogni volta come argomento il valore numero-1.
Quando numero diventa uguale a zero la ricorsione s'interrompe ed i return di tutte le funzioni chiamate vengono eseguiti calcolando il risultato della formula numero * fattoriale (numero - 1), come mostra lo schema seguente:

Osservando il comportamento della funzione fattoriale si capisce che la ricorsione è una tecnica che permette di ripetre più volte le stesse operazioni, come accade per i cicli, infatti il fattoriale può essere calcolato anche nel modo seguente:

Esempio 6

int main(){
   int numero,x;
   int fattoriale=1;
   printf("Calcolo del Fattoriale\n");
   printf("\nNumero:");
   /* %d = input numerico,
   &numero passiamo alla funzione scanf il riferimento della variabile numero */

   scanf("%d",&numero);
   for(x=1;x<=numero;x++){
  /* fattoriale = fattoriale * x => fattoriale*=x */
      fattoriale*=x;
   }
   printf("Fattoriale di %d = %d\n", numero, fattoriale);
   return(0);
}


L A B O R A T O R I   D I   L O G I C A   D I   P R O G R A M M A Z I O N E   I N   C
L E Z I O N E  1
L E Z I O N E  2
L E Z I O N E  3
L E Z I O N E  4
L E Z I O N E  5
 


Share Button
TOP