Caricare documenti e articoli online 
INFtub.com è un sito progettato per cercare i documenti in vari tipi di file e il caricamento di articoli online.


 
Non ricordi la password?  ››  Iscriviti gratis
 

LA PROGRAMMAZIONE STRUTTURATA

informatica



LA PROGRAMMAZIONE STRUTTURATA





§1. La programmazione strutturata in Pascal



La stesura di un programma è un'attività difficile ed anche delicata, perché ogni minima imperfezione può bloccare il programma o dare risultati errati. Non esiste una regola semplice valida per tutte le situazioni: nei casi più complessi, la via maestra consiste nel suddividere il problema in sottoproblemi più semplici per ricomporre il tutto alla fine. Nel I° secolo a.C. il generale romano Giulio Cesare riuscì, con un esercito di appena 40.000 uomini, a sottomettere in pochi anni tutta l'antica Francia allora popolata da una decina di milioni di Galli ostili, coraggiosi e di costituzione fisica certamente più robusta dei Romani. Fu merito esclusivo della superiore organizzazione militare romana? Certo, anche questa giovò a Cesare. Ma la sua risorsa principale fu l'applicazione sistematica della strategia dìvide et ìmpera, dividi (i tuoi nemici) e comanda. In Pascal faremo proprio questo: suddivideremo il programma principale da creare in sottoprogrammi più semplici (in Informatica: routine), ciascuno dei quali è rivolto alla soluzione di un sottoproblema: risolveremo così un sottoproblema alla volta e alla fine richiameremo insieme tutte le routine per risolvere il 727e43h problema complessivo.



Quando si procede in questo modo si parla di programmazione strutturata: vedremo che il Pascal è un linguaggio che ben si presta ad essere strutturato.

La strutturazione ha i vantaggi di

rendere più trasparente la lettura del programma, perché ogni routine identifica con il suo blocco d'istruzioni la mansione cui è dedicata;

risparmiare memoria, perché anche se una routine è impiegata più volte nello stesso programma la sua memorizzazione tuttavia avviene una volta sola;

migliorare l'affidabilità dei programmi, perché la eventuale presenza di errori può essere rimossa intervenendo su un solo sottoprogramma, invece di dover rivoluzionare l'intero programma. Il software originale per il jet da combattimento F-16 conteneva un piccolo errore (in Informatica, bug=baco), che provocava una scossa dall'alto verso il basso ogni volta che il top gun attraversava l'equatore: per la correzione dell'errore (debugging) non si dovette sconvolgere l'intero software avionico, ma bastò intervenire su una singola routine;

accrescere la versatilità dei programmi, perché una stessa routine finalizzata ad una determinata azione, può essere impiegata in programmi diversi che richiedono quell'azione;

diminuire i tempi ed i costi di realizzazione dei programmi, perché ogni routine può essere progettata da programmatori diversi specializzati. Di fatto, solo la divisione del lavoro rende possibile la creazione materiale di programmi molto complessi che nessun singolo programmatore, per quanto bravo, riuscirebbe da solo a sviluppare.




§2. Procedure



In Pascal esistono due tipi di routine: le procedure e le funzioni.

Definizione. Una procedura è un sottoprogramma che, come una singola istruzione, svolge il suo ruolo in una successione di azioni concentrate ad uno scopo.

La sua sintassi, molto simile a quella di un programma, è


procedure Nome(parametri opzionali);

Dichiarazione delle variabili locali;

begin

Istruzione1;

Istruzione2;

...........

end;


Notiamo:

la parola riservata "procedure" (anziché "program");

l'eventuale presenza di parametri contenuti tra parentesi dopo il nome della procedura: che cosa siano e a che cosa servano, vedremo meglio più avanti;

come nei programmi, c'è la Dichiarazione delle variabili, che sono dette "locali" perché funzionano solo all'interno della procedura e non nel programma principale;

come nei programmi, il Blocco delle istruzioni è contenuto tra un begin ed un end, quest'ultimo però seguito dal non dal .;

la procedura va inserita nel programma principale, immediatamente prima del begin di esso;

la procedura viene richiamata dal programma principale semplicemente usando il Nome della procedura all'interno del Blocco delle istruzioni del programma principale.


I seguenti es. illustrano quanto spiegato.


program FrasePosizionata;

uses Crt;

var i, j: byte;

S: string;


procedure Parola(Col, Riga: byte; Frase: string);

begin

ClrScr;

GotoXY(Col, Riga);

Write(Frase)

end;


begin

ClrScr;

Write('A quali coordinate vuoi iniziare a scrivere?

ReadLn(i, j);

Write('Che frase vuoi scrivere?

ReadLn(S);

Parola(i, j, S);

ReadLn

end.


Osserviamo innanzitutto la struttura:

program FrasePosizionata; è la solita intestazione del programma principale;

uses Crt; è la solita clausola per l'uso di istruzioni che controllano il display, come ClrScr;

var i,j: byte; S: string; è la Dichiarazione delle variabili del programma principale;

procedure Parola(Col, Riga: byte; Frase: string); è l'intestazione d'una procedura di nome Parola, con i tre parametri Col e Riga di tipo byte e Frase di tipo string. Questa procedura non ha variabili locali;

begin... end; è il Blocco delle istruzioni della procedura. Che azione specifica fa Parola? 1) Cancella lo schermo, 2) posiziona il cursore alla colonna Col e alla riga Riga, 3) scrive la stringa Frase. Col, Riga e Frase sono parametri, cioè variabili (il cui tipo è indicato tra le parentesi tonde del nome della procedura) che acquisiranno specifici valori solo dal programma principale. È questo il significato del termine parametri di una procedura;

begin... end. Questo è il Blocco delle istruzioni del programma principale, cioè quello che in effetti viene eseguito dalla CPU. Vediamo che cosa fa il chip: 1) Cancella lo schermo; 2) fa apparire la scritta "A quali coordinate vuoi iniziare a scrivere? ", 3) attende l'introduzione di due numeri byte che depositerà nelle celle di memoria d'indirizzo rispettivo i e j; 4) fa apparire la scritta "Che frase vuoi scrivere? ", 5) attende la digitazione da parte dell'utente d'una frase, che poi depositerà nella cella d'indirizzo S (la Dichiarazione delle variabili del programma principale aveva riservato 3 celle degli indirizzi e dei tipi appositi); 6) a questo punto, con l'istruzione Parola(i, j, S), viene richiamata la procedura, cioè CPU esegue adesso proprio il sottoprogramma avente quel nome, utilizzando i due numeri e la frase digitati dall'utente al posto dei parametri formali: ossia 1) ri-cancella lo schermo, 2) posiziona il cursore alla colonna i e alla riga j digitate dall'utente e 3) scrive la stringa S digitata dallo stesso.

Altro es.:


program FraseMaiuscola;

var S: string;


procedure ScriviMaiuscolo(S1: string);

var i: integer;

begin

For i:= 1 To Length(S1) Do S1[i]:= UpCase(S1[i]);

WriteLn(S1)

end;


begin

Write('Scrivi una stringa: ');

ReadLn(S);

ScriviMaiuscolo(S);

ReadLn

end.


Notiamo che questa volta la procedura ha una variabile locale (i, di tipo integer) ed un solo parametro (S1, di tipo string). La variabile i funziona soltanto all'interno della procedura e serve a numerare tutti i caratteri della stringa per trasformarli ordinatamente in maiuscolo.

III° es.:


program EstrazioneLotto;

uses Crt;

var Num_Lotto, Mio_Numero, N, V: byte;

Tasto: char;


procedure Inizio;

begin

ClrScr;

N:= 1;

V:= 0;

Randomize

end;


procedure Controllo;

begin

Repeat

Tasto:= Readkey;

If not(Tasto in['0'..'9', #27]) Then begin

N:= N-1;

WriteLn('Tasto errato,

riprova')

end;

Until Tasto in ['0'..'9', #27]

end;


procedure MessaggioFinale;

begin

WriteLn('Numero scelto: ', Mio_Numero);

WriteLn('Numero vincente: ', Num_Lotto);

If Num_Lotto= Mio_Numero Then begin

WriteLn('Hai vinto!', ^G^G);

Inc(V)

end

Else WriteLn('Hai perso...');

WriteLn('Hai vinto ', V, ' volte su ', N);

WriteLn('Premere <ESC> per uscire, altrimenti continuare');

Inc(N);

WriteLn

end;


begin

Inizio;

Repeat

Num_lotto:= Random(10);

WriteLn('Scegli un numero fra 0 e 9');

Controllo;

Mio_Numero:= Ord(Tasto)-Ord('0');

MessaggioFinale;

Until Tasto= #27

end.


In questo programma vengono utilizzate ben tre procedure, Inizio, Controllo e MessaggioFinale, nessuna delle quali è dotata di parametri.

IV° es.:


program Animazione;

uses Crt;

var Colonna, i: byte;


procedure Movimento(var X: byte);

begin

If X= 80 Then X:= 1

Else Inc(X)

end;


procedure Disegno;

begin

GotoXY(Colonna, 10);

TextColor(i);

Write(#219);

Delay(50);

GotoXY(Colonna, 10);

Write(' ');

Movimento(Colonna)

end;


begin

ClrScr;

Colonna:= 1;

For i:= 1 To 160 Do Disegno

end.


Questo è un programma un tantino più complicato degli altri. Innanzitutto notiamo la presenza di due procedure, Disegno e Movimento, la seconda delle quali è annidata nella prima. Questa è una performance caratteristica del Pascal, suscettibile di notevoli prestazioni: una procedura può essere richiamata non solo dal programma principale, ma anche da un'altra procedura. Quando la CPU esegue il Blocco delle istruzioni di Disegno, arrivata all'istruzione Movimento, esegue necessariamente il Blocco delle istruzioni di questa.

Nello stesso programma va notata un'altra circostanza: mentre la procedura Disegno non ha parametri, la procedura Movimento ha un parametro X di tipo byte, che però è preceduto dalla parolina var. Perché? proviamo ad eliminare var e a far girare il programma: stavolta il disegno non si muove. Come mai? Il fatto è che quando un parametro, come in tutti i programmi precedenti, è semplicemente messo tra le parentesi tonde senza la parolina var esso è solo formale ed aspetta, per assumere un valore preciso, il programma principale, senza poter variare all'interno della procedura. Esso si chiama parametro valore e viene momentaneamente depositato in un'area speciale della memoria (stack), nella quale non subisce variazioni fino alla definizione del suo valore per azione del programma principale. Perché il disegnino si muova però, noi abbiamo bisogno che X vari da 1 ad 80 all'interno della procedura Movimento: in questo caso si parla di parametro variabile e deve essere preceduto da var. La parolina ha il compito di collocarlo in RAM, in celle dove può assumere valori variabili.

V° es.:


program EquazioneIIGrado;

uses Crt;

var

a1, b1, c1: real;

Risposta: char;


procedure RadiciReali(a, b, c: real);

var Radice1, Radice2, D: real;

begin

D:= sqr(b)-4*a*c;

If D< 0 Then begin

WriteLn('Equazione impossibile!');

Exit

end

Else

Radice1:= (-b-sqrt(D))/(2*a);

Radice2:= (-b+sqrt(D))/(2*a);

WriteLn('La radice1 è = ', Radice1:0:3);

WriteLn('La radice2 è = ', Radice2:0:3)

end;


begin

ClrScr;

Repeat

Write('I coefficiente? = ');

ReadLn(a1);

Write('II coefficiente? = ');

ReadLn(b1);

Write('III coefficiente? = ');

ReadLn(c1);

RadiciReali(a1, b1, c1);

Write ('Vuoi continuare? [S]ì, [N]o: ');

ReadLn(Risposta)

Until (Risposta= 'N') or (Risposta= 'n')

end.


Questo, ed il seguente, sono es. molto semplici, che non richiedono commenti.

VI° es.:


program AlgoritmoEuclideo;

uses Crt;

var M, N: integer;


procedure Scambio;

var TEMP: integer;

begin

If M< N Then begin

TEMP:= M;

M:= N;

N:= TEMP

end

end;


procedure TrovaMcd;

var RESTO: integer;

begin

RESTO:= M mod N;

While RESTO<> 0 Do begin

M:= N;

N:= RESTO;

RESTO:= M mod N;

end;

Write(N)

end;


begin

ClrScr;

WriteLn('Massimo comun divisore di due numeri');

WriteLn(' = = = = = = = = = = = = ');

WriteLn;

WriteLn('Introdurre due numeri naturali');

Write('separati da uno spazio: ');

ReadLn(M, N);

WriteLn;

Write('MCD(', M, ', ', N, ') = ');

Scambio;

TrovaMcd;

ReadLn

end.




§3. Funzioni



Definizione. Una funzione è una procedura che restituisce un valore, di tipo numerico, o char, o string.

La sua sintassi, molto simile a quella di una procedura, è


function Nome(parametri opzionali): tipo del valore restituito;

Dichiarazione delle variabili locali;

begin

Istruzione1;

Istruzione2;

...........

end;


Notiamo:

la parola riservata "function";

l'eventuale presenza di parametri contenuti tra parentesi dopo il nome della procedura: essi giocano lo stesso ruolo che nelle procedure;

a differenza delle procedure, nelle funzioni subito dopo il nome vanno messi : e specificato il tipo (byte, integer, real, char, o string) del valore restituito falla funzione;

come nelle procedure, c'è la Dichiarazione delle variabili locali;

come nelle procedure, il Blocco delle istruzioni è contenuto tra un begin ed un end;;

la funzione va inserita nel programma principale tra le procedure;

la funzione viene richiamata dal programma principale come le altre procedure, usando il suo Nome.


I seguenti es. illustrano quanto spiegato.


program QuadratoDiUnNumero;

uses Crt;

var y: real;


function Potenza(x: real): real;

begin

Potenza:= x*x

end;


begin

ClrScr;

WriteLn('IL QUADRATO D''UN NUMERO DATO');

WriteLn;

Write('La base = ');

ReadLn(y);

WriteLn(y:0:2,'ý = ', Potenza(y):0:2);

ReadLn

end.


Osserviamo innanzitutto la struttura:

program QuadratoDiUnNumero; L'intestazione del programma principale;

uses Crt; La clausola per l'uso di ClrScr;

var y: real; La Dichiarazione delle variabili del programma principale;

function Potenza(x: real): real; è l'intestazione d'una funzione di nome Potenza, con il parametro x di tipo real. Questa funzione restituisce un valore real;

begin... end; è il Blocco delle istruzioni della funzione. Che azione specifica fa Potenza? Una sola: dato il real x lo moltiplica per se stesso ed assegna il risultato (che è un altro real) a Potenza;

begin... end. Questo è il Blocco delle istruzioni del programma principale, cioè quello che in effetti viene eseguito dalla CPU. Esso: 1) Cancella lo schermo; 2) fa apparire la scritta "IL QUADRATO D'UN NUMERO DATO", 3) una riga vuota; 4) fa apparire la scritta "La base = ", 5) attende la digitazione da parte dell'utente d'un numero reale, che poi depositerà nella cella d'indirizzo y (la Dichiarazione delle variabili del programma principale aveva prenotato lo spazio apposito); 6) ne fa apparire il quadrato poich, Potenza(y) ha proprio per valore y².

Altro es.


program Fib1;

uses Crt;

var i: byte;


function Fibonacci(n: byte): longint;

var indice: byte;

attuale, primo, secondo: longint;

begin

primo:= 1;

secondo:= 1;

attuale:= 1;

If n> 2 Then For indice:= 1 To (n-2) Do

begin

attuale:= primo+secondo;

primo:= secondo;

secondo:= attuale

end;

Fibonacci:= attuale

end;


begin

ClrScr;

WriteLn('I PRIMI 20 NUMERI DI FIBONACCI');

WriteLn;

For i:= 1 To 20 Do WriteLn(i:3, Fibonacci(i):8);

ReadLn

end.


In questo programma, che calcola i primi 20 numeri di Fibonacci, è utilizzata una funzione di nome Fibonacci il cui parametro è un numero di tipo byte e che restituisce un valore di tipo longint.

Altro es.


program Rad_n_ma;

uses Crt;

var Radicando: real;

Indice: byte;

Risposta: char;

B1, B2: boolean;


function Potenza(a: real; m: byte): real;

var j: byte;

q: real;

begin

q:= 1;

j:= 0;

While j< m do begin

q:= q*a;

j:= j+1

end;

Potenza:= q

end;


function Radice(c: real; p: byte): real;

var s: real;

begin

s:= 0;

While Potenza(s, p)< c do s:= s+1;

s:= s-1;

While Potenza(s, p)< c do s:= s+0.001;

Radice:= s

end;


begin

ClrScr;

WriteLn('RADICE NATURALE D''UN NUMERO REALE POSITIVO');

WriteLn('-------- ----- ------ -------- ----- ------ ---------');

WriteLn;

Repeat

Write('Digita Radicando (> 0) e Indice (naturale): ');

ReadLn(Radicando, Indice);

B1:= (Radicando < 0);

B2:= (Indice <= 0);

If (B1 or B2) Then WriteLn('Non calcolo questa radice!')

Else WriteLn(Radice(Radicando, Indice):0:3);

WriteLn;

Write('Un''altra radice? [s]ì, [n]o: ');

ReadLn(Risposta);

Until ((Risposta= 'N') or (Risposta= 'n'))

end.


In questo programma ci sono due funzioni: Potenza e Radice. Potenza ha due parametri, a di tipo real ed m di tipo byte, e restituisce un valore di tipo real. Ha anche due variabili locali, j e q. Radice invece ha due parametri, c di tipo real e p di tipo byte, restituisce un valore di tipo real ed ha una sola variabile locale, s di tipo real. Notiamo anche che la funzione Potenza non è richiamata dal programma principale, ma è annidata dentro la funzione Radice. In questo modo, quando il programma principale richiama Radice, CPU eseguendo Radice esegue anche Potenza.




§4. Ricorsione



Definizione. Si chiama ricorsione una routine (procedura o funzione) che richiama se stessa, ossia che nel suo Blocco di istruzioni usa il proprio nome.

A prima vista tutto questo potrebbe apparire strano, se non addirittura illogico; si tratta invece di una delle più potenti applicazioni del Pascal. Consideriamo il seguente programma per il calcolo dei primi 10 fattoriali:


program Fattoriale;

uses Crt;

var num: byte;


function Fatt(j: byte): longint;

begin

If j= 1 Then Fatt:= 1

Else Fatt:= j*Fatt(j-1)

end;


begin

ClrScr;

WriteLn('I PRIMI 10 FATTORIALI');

WriteLn;

For num:= 1 to 10 Do

WriteLn(num:2, '! = ', Fatt(num));

ReadLn

end.

Il programma fa uso della funzione Fatt nel cui blocco essa richiama se stessa: ...Else Fatt:= j*Fatt(j-1). Questo quindi è un programma ricorsivo. Un altro es. è dato dal programma seguente, che calcola i primi 20 numeri di Fibonacci. Notiamo come l'uso della ricorsione semplifichi sostanzialmente il programma Fib2 rispetto al programma Fib1 del paragrafo precedente, che perseguiva lo stesso scopo senza l'uso della ricorsione. 


program Fib2;

uses Crt;

var i: byte;


function Fibonacci(n: byte): longint;

begin

If n<= 2 Then Fibonacci:= 1

Else Fibonacci:= Fibonacci(n-2) + Fibonacci(n-1)

end;


begin

ClrScr;

WriteLn('I PRIMI 20 NUMERI DI FIBONACCI');

WriteLn;

For i:= 1 To 20 Do WriteLn(i:3, Fibonacci(i):8);

ReadLn

end.




§5. Moduli personalizzati



I moduli Crt, Dos, Graph (quest'ultimo lo studieremo più avanti e serve per la produzione grafica), ed altri ancora, sono biblioteche predefinite di routine, procedure e funzioni non standard, costruite da Borland. È possibile però costruirsi propri moduli, dove raccogliere routine importanti da noi costruite e che possono essere utilizzate nei vari programmi direttamente, cioè evocando la routine (procedura o funzione) nel Blocco delle istruzioni, senza la necessità di trascriverla nel programma. Che cosa facciamo quando abbiamo bisogno in un programma di cancellare lo schermo, o di usare l'ora corrente? Semplicemente evochiamo la routine ClrScr o GetTime, direttamente col loro nome, e senza trascriverne la complessa struttura che non conosciamo. Un'unica avvertenza dobbiamo avere: non essendo ClrScr e GetTime comandi standard, dobbiamo richiamare in testa al programma - subito sotto l'intestazione - la clausola uses con il nome del rispettivo modulo dove queste routine sono raccolte (Crt per ClrScr, Dos per GetTime).

La stessa cosa faremo con le routine A, B, C,... da noi costruite: le raccoglieremo, secondo regole che ora andiamo a studiare, in moduli appositamente creati (e che possiamo differenziare a nostro piacimento, secondo classi di azioni operate dalle routine). Ad ognuno di questi moduli daremo un nome M, N, P,... Quando avremo bisogno di usare in un programma la routine A del modulo M, basterà richiamare sotto l'intestazione del programma la clausola


uses M;


e nel Blocco delle istruzioni del programma chiamare la routine A, direttamente e senza trascriverla. Vediamo direttamente un es.

Il Pascal ha alcune routine sui numeri reali che sono standard; per es., sqr, o sqrt, o *, sono operazioni direttamente eseguibili nei programmi. Non esiste però in Pascal l'operazione di elevamento a potenza (con esponente naturale >2), né l'operazione di fattoriale di un numero naturale; queste operazioni non esistono né come standard, né come appartenenti a moduli predefiniti da Borland. Noi però, a suo tempo, ci siamo costruiti delle routine per queste operazioni:

1) per la POTENZA


function Potenza(b: real; e: shortint): real;

var k: shortint;

p: real;

begin

p:= 1;

For k:= 1 to e do

p:= b*p;

Potenza:= p

end;


2) per il FATTORIALE


function Fattoriale(n: byte): longint;

begin

If n= 1 Then Fattoriale:= 1

Else Fattoriale:= n*Fatt(n-1)

end;


A questo punto potremmo decidere di costruirci un modulo, per es. di nome ALGEBRA, dove raccogliere queste due routine ed altre ancora, cui potremo attingere ogniqualvolta avremo bisogno in un programma di eseguire l'operazione di potenza, di fattoriale, ecc.

La costruzione del modulo avviene in IDE utilizzando

la parola riservata unit seguita dal nome del modulo e dal punto e virgola;

alla riga successiva la parola riservata interface (senza punto e virgola);

l'elenco delle intestazioni delle routine che si vogliono inserire nel modulo, separate dal punto e virgola;

la parola riservata implementation (senza punto e virgola);

i programmi di ogni routine del modulo;

alla fine della unit la parola riservata end col punto.

Nel caso del nostro es., avremmo


unit Algebra;

interface

function Potenza(b: real; e: shortint): real;

function Fattoriale(n: byte): longint;

implementation

function Potenza;

var p: real;

k: shortint;

begin

p:= 1;

For k:= 1 to e do

p:= b*p;

Potenza:= p

end;

function Fattoriale;

begin

If n= 1 Then Fattoriale:= 1

Else Fattoriale:= n*Fattoriale(n-1)

end;

end.


Non basta. Ora dobbiamo ancora

salvare il modulo sul disco, per es. con il nome ALGEBRA.PAS;

compilarlo sul disco (opzione Compile/Destination disk), dove Turbo.exe provvederà automaticamente ad assegnare l'estensione .TPU al file che contiene il modulo compilato.

È tutto. A questo punto, POTENZA(x: real; y: shortint) e FATTORIALE(z: byte) sono per i nostri programmi due routine pronte per l'uso al solo richiamo del loro nome. L'unica avvertenza che dovremo avere, sarà nel programma l'inserzione della clausola


uses Algebra;


ALGEBRA è una nuova biblioteca di routine a nostra disposizione, accanto a CRT, DOS, GRAPH, ecc. Il programma seguente, ad uso di prova, ne mostra l'efficacia.


program ProvaAlgebra;

uses Crt, Algebra;

var x: real;

y, z: shortint;

begin

ClrScr;

WriteLn('CALCOLO DI POTENZA E DI FATTORIALE');

Write('Digita base ed esponente, separati da uno spazio: ');

ReadLn(x, y);

WriteLn(x:0:3, '^', y, '= ', Potenza(x,y):0:3);

Write('Digita un numero naturale (non troppo grande!!): ');

ReadLn(z);

WriteLn(z, '!', '= ', Fattoriale(z));

ReadLn

end.




Privacy




Articolo informazione


Hits: 1415
Apprezzato: scheda appunto

Commentare questo articolo:

Non sei registrato
Devi essere registrato per commentare

ISCRIVITI



Copiare il codice

nella pagina web del tuo sito.


Copyright InfTub.com 2024