Programmare in Pascal
Obiettivi operativi
• Realizzare programmi
• Inviare dati al video
• Accettare valori da tastiera
• Usare variabili e costanti di tipo integer
• Invocare funzioni e procedure predefmite
Obiettivi cognitivi
• La struttura dei programmi
• Tipi, variabili e costanti
• Dichiarazioni
• Il tipo integer
• Assegnamenti ed espressioni
2.1 Struttura dei programmi
Iniziamo lo studio del Pascal osservando il listato 2.1, in cui possono già essere evidenziate alcune delle caratteristiche comuni alla struttura di ogni programma.
La parola chiave program, che apre l'intestazione, è seguita dal nome che abbiamo assegnato al programma, nel caso in esame paese. Il punto e virgola chiude l'intestazione.
Il corpo del programma è compreso tra la parola chiave begin e la parola chiave end seguita da un punto ed è composto da una serie di istruzioni write che verranno eseguite sequenzialmente.
program paese ;
begin
write('Tre') ;
write(' casettine')
write(' dai');
write(' tetti');
write(' aguzzi');
end.
NOTA INFORMATIVA
Nei linguaggi di programmazione con parola chiave o riservata si intende una parola a cui il compilatore attribuisce un'interpretazione univoca e determinata riservandola a un uso specifico. Tali parole non devono quindi essere utilizzate dal programmatore in modi e con scopi diversi da quelli previsti. Rimandiamo all'appendice A per un elenco completo delle parole chiave del Turbo Pascal 7.0.
Ogni istruzione write permette la stampa su video di ciò che è racchiuso fra parentesi tonde e apici. Per esempio
Write('Tre’);
Visualizza
Tre
Ogni istruzione deve essere seguita obbligatoriamente dal carattere di punto e virgola; fa eccezione l'ultima istruzione, quella che precede l'end finale, in cui il punto e virgola è opzionale. La struttura di un programma Pascal così come l'abbiamo finora descritta è:
Le istruzioni vengono eseguite una dopo l'altra nella sequenza in cui si presentano. Il programma del listato 2.1 è composto da istruzioni write e la sua esecuzione visualizzerà la frase
Tre casettine dai
tetti aguzzi
Nell'esecuzione delle istruzioni il Pascal non distingue fra lettere maiuscole e minuscole; possiamo dunque scrivere write anche come WRITE, Write o wRiTE.
Le write successive alla prima iniziano a scrivere a partire dalla posizione del video che segue quella occupata dall'ultimo carattere visualizzato dalla write immediatamente precedente. Abbiamo perciò inserito all'interno degli apici uno spazio bianco iniziale; se non lo avessimo fatto avremmo ottenuto:
Trecasettinedaitettìaguzzi
Infatti anche lo spazio è un carattere come gli altri e, se vogliamo visualizzarlo, dobbiamo esplicitamente inserirlo nella giusta posizione. Se desideriamo che ogni parola della frase sia scritta su una riga separata, dobbiamo utilizzare l'istruzione writeln. Sostituendo nel listato 2.1 ogni write con una writeln otteniamo la seguente visualizzazione:
program paese_tranguillo;
begin write('Tre'); write(' cassettine'); write (' dall1 'aria') ; wrìte(' tranquilla'}; end
Un
programma
con
apostrofo
.
Tre
casettine
dai
tetti
aguzzi
Dalla seconda riga in poi il primo carattere visualizzato è uno spazio, se vogliamo toglierlo dobbiamo cancellarlo dalla parte compresa tra apici delle writeln corrispondenti. Se nel testo che desideriamo visualizzare sullo schermo compare un apostrofo, come in:
Tre casettine dall'aria tranquilla
dobbiamo usare un doppio apostrofo come nella terza write del listato 2.2
2.2 Variabili e
assegnamenti
Supponiamo di voler calcolare l'area di un rettangolo di base 3 e altezza 7; com'è noto, l'area cercata è data dal prodotto 3x7. Osserviamo il listato 2.3 il programma che risolve il problema.
{ Calcolo area
rettangolo } program rettangolo; var base : integer; altezza: integer; area : integer; begin base := 3; altezza := 7; area := base*altezza; write(area); end.
Listato 2.3
Calcolo
dell'area di
un rettangolo
Per rendere evidente la funzione espletata dal programma abbiamo inserito un commento:
{ Calcolo
area rettangolo }
I commenti devono essere inseriti tra parentesi graffe e possono estendersi su più righe e apparire in qualsiasi parte del programma. Tutto ciò che è racchiuso fra parentesi graffe non viene preso in considerazione e non ha alcuna influenza sul funzionamento del programma. In alternativa possiamo far precedere i commenti dalla sequenza di caratteri ( * e farli seguire dalla sequenza * ) ; dunque avremmo anche potuto scrivere:
(* Calcolo area
rettangolo *)
Dopo la parola chiave var e prima di begin sono presenti le dichiarazioni delle variabili intere necessarie:
var
base : integer;
altezza: integer;
area: integer;
Ogni singola dichiarazione è costituita da un identificatore di variabile seguito da due punti e dalla parola chiave integer, che specifica che la variabile è di tipo intero, base, altezza e area sono dunque identificatori di variabili di tipo integer.
Anche le dichiarazioni devono terminare con un punto e virgola. Nel nostro esempio alla dichiarazione del tipo della variabile corrisponde inoltre la sua definizione, la quale fa sì che alla variabile venga riservato uno spazio nella memoria centrale dell'elaboratore:
base
altezza area
II nome di una variabile la identifica, il suo tipo ne definisce la dimensione e l'insieme delle operazioni che vi si possono effettuare. Il Turbo Pascal riserva per gli integer uno spazio di due byte, il che consente di poter lavorare su interi che vanno da -32768 a +32767.
NOTA INFORMATIVA
La memoria degli elaboratori elettronici è organizzata in byte. Ogni byte è composto da otto bit. Un bit può avere il valore zero o uno. Nel sistema binario che utilizza solo le cifre O e 1, con 2 byte (16 bit) sono rappresentabili valori compresi tra -215 (-32768) e +215- 1 (432767), quindi in totale 216 valori, considerando lo zero.
Tra le varie operazioni permesse fra integer che danno come risultato un integer vi sono somma, sottrazione e prodotto, che corrispondono rispettivamente agli operatori +, -, *.
L'istruzione
base
:= 3;
assegna alla variabile base il valore 3, cioè inserisce il valore (3) che segue l'operatore : = nello spazio di memoria riservato alla variabile (base). Effetto analogo avrà altezza := 7. L'assegnamento è dunque realizzato mediante l'operatore : =. Nella macchina i valori saranno memorizzati in notazione binaria, ma per comodità li riportiamo in formato decimale:
Base Altezza Area
3 7
L'istruzione:
area := base*altezza;
assegna alla variabile area il prodotto dei valori di base e altezza:
Base Altezza Area
21 7 3
L'ultima istruzione
write(area);
visualizza 21, il valore della variabile area.
La struttura dei programmi Pascal prevede che le variabili siano dichiarate dopo la parola chiave var e prima di begin:
program nome_programma;
var
dichiarazioni_di_variabili;
begin
istruzione1;
istruzione2;
istruzioneS;
istruzioneN
end.
Nelle dichiarazioni gli identificatori delle variabili dello stesso tipo possono essere scritti in sequenza:
base, altezza, area: integer;
Gli identificatori della lista possono essere in numero qualsiasi e devono essere separati da virgola e seguiti da due punti e dalla dichiarazione del tipo. Un punto e virgola chiude come al solito la dichiarazione:
lista_di_identificatori: tipo;
Allo scopo di rendere più chiaro l'effetto ottenuto dal programma dell'esempio precedente, si possono visualizzare anche i valori delle variabili base e altezza.
writeln(base); writeln(altezza); write(area);
In ogni write o writeln, tra parentesi tonde, si è inserito il nome della variabile da visualizzare, così da ottenere:
3
7
21
Se si vuole far precedere la visualizzazione dei valori da una descrizione, è sufficiente inserirla tra apici seguiti da una virgola, prima del nome della variabile.
write
(‘Base: ', base);
write
(' Altezza: ', altezza);
write('
Area: ', area);
Quello che si ottiene in esecuzione è
Base: 3
Altezza: 7 Area:
21
Una seconda versione del programma per il calcolo dell'area del rettangolo è quella del listato 2.4, la cui esecuzione avrà il seguente effetto:
Base: 3
Altezza: 7
Area: 21
Mentre integer è una parola chiave del Pascal e fa parte integrante del linguaggio, rettangolo, base, altezza e area sono identificatori scelti a nostra discrezione.
Esistono comunque alcune regole da rispettare nella costruzione degli identificatori: devono iniziare con una lettera o con un carattere di sottolineatura (_) e possono contenere solo lettere non accentate, cifre e_. Le lettere maiuscole vengono considerate equivalenti alle rispettive minuscole.
{ Calcolo area
rettangolo } program rettangolo2; var base, altezza,
area : integer; begin base := 3; altezza := 7; area := base*altezza; writeln('Base : ' , base); writeln('Altezza:',
altezza); writeln('Area:
', area); end.
Listato 2.4
Calcolo
dell'area di
un rettangolo
(seconda
versione)
Esempi d'identificatori validi sono: nome1, cognome2, cognome_nome, volume, età, a, x; al contrario non sono corretti: 12nome, cognome-nome, vero?, padre&figli, età. Si noti che volume, VOLUME e voLume fanno riferimento allo stesso identificatore. Oltre a rispettare le regole precedentemente enunciate, un identificatore non può essere una parola chiave del linguaggio, né può essere uguale a uno degli identificatori definiti precedentemente. Anche il nome del programma, quello che segue la parola chiaveprogram, è un identificatore e non può quindi essere in conflitto con un nome di variabile.
Nel programma per il calcolo dell'area del rettangolo, si sarebbe ottenuto lo stesso risultato utilizzando nomi generici quali prova, x, y e z. Inoltre la forma grafica data al programma è del tutto opzionale: una volta rispettata la sequenzialità e la sintassi, la scrittura del codice è libera. In particolare più istruzioni possono essere scritte sulla stessa riga:
program prova;
var x, y, z: integer;begin x := 3; y := 7
z:=x*y; writeln('Base:’,x) end.;
writeln ('Altezza
:', y); writeln('Area:)
Indubbiamente questo programma è notevolmente meno leggibile del precedente. Lo stile grafico facilita enormemente il riconoscimento delle varie parti del programma e consente una diminuzione di tempo nelle modifiche, negli ampliamenti e nella correzione degli errori. Non importa quale stile decidiate di utilizzare, l'importante è che lo seguiate con coerenza senza, d'altra parte, incorrere in un'eccessiva rigidità. In generale è bene dare a ogni variabile un nome significativo, in modo che, quando si deve intervenire a distanza di tempo sullo stesso programma, si possa facilmente ricostruire l'uso che se ne è fatto.
2.3 Costanti
Nel programma visto nel paragrafo precedente i valori di base e altezza sono costanti, dato che non variano durante l'esecuzione del programma. Evidentemente, avremmo potuto scrivere direttamente:
area
:= 3*7;
Quando un certo valore non viene
modificato nel corso del programma è opportuno, soprattutto se è utilizzato in
modo ricorrente, rimpiazzarlo con un nome simbolico. Per farlo dobbiamo
definire prima di begin e dopo la parola chiave const un identificatore di costante e fargli corrispondere il valore
desiderato.
const
BASE = 3;
Grazie a questa direttiva potremo utilizzare all'interno del
programma l'identificatore BASE al posto del valore
intero 3.
La stessa definizione di costante implica che il suo valore
non può essere modificato: BASE può essere utilizzata in un'espressione a patto
che su di essa non venga mai effettuato un
assegnamento.
Vediamo nel listato 2.5 come viene
modificato il programma del paragrafo precedente utilizzando alcune costanti.
Il nome di una costante può essere qualsiasi identificatore valido in Pascal.
Per maggiore chiarezza abbiamo scelto di evidenziare visivamente le costanti
scrivendole con caratteri maiuscoli.
Invece dì utilizzare direttamente i valori è auspicabile far uso degli identificatori di costante che, essendo descrittivi, migliorano la leggibilità
{ Calcolo area
rettangolo, utilizzando costanti } program rettangole3; const BASE = 3; ALTEZZA =
7; var area: integer; begin area := BASE*ALTEZZA; writeln('Base
: ', BASE); writeln('Altezza: ',
ALTEZZA); writeln('Area:
', area); end.
dei programmi. Inoltre, dovendo
cambiare un determinato valore se questo è stato definito come
costante è sufficiente modificare il solo valore attribuitogli al momento della
dichiarazione; se, al contrario, il valore non è stato definito come costante
occorrerà cercare e modificare tutte le sue Decorrenze all'interno del testo,
con notevole perdita di tempo in listati di una certa lungezza.
Per esempio, per fare in modo che il programma del listato
2.5 calcoli l'area del rettangolo con base 102 e
altezza 34, è sufficiente modificare gli assegnamenti effettuati in fase di
definizione delle costanti BASE e ALTEZZA:
const
BASE = 102;
ALTEZZA = 34;
In sintesi, l'uso delle costanti migliora due parametri classici di valutazione dei programmi: flessibilità e facilità di manutenzione. Nel Turbo Pascal le dichiarazioni di costanti e variabili possono apparire in un ordine qualsiasi, fermo restando che devono seguire l'intestazione del programma e precedere il begin del corpo del programma. Questa regola rimane valida anche per le dichiarazioni che studieremo in seguito, come le dichiarazione di tipo definito dall'utente, di funzione e di procedura le quali tutte insieme vanno a formare la parte dichiarativa.
program nome_programma;
parte_dichiarativa
begin
istruzionel;
istruzione2;
istruzioneS;
ìstruzioneN;
end.
2.4 Immissione ed emissione di dati
I programmi che abbiamo scritto non calcolano l'area di un
qualsiasi rettangolo ma soltanto di quello che ha per base 3
e per altezza 7, supponiamo centimetri.
Per esempio, per trovare l'area di un
rettangolo di base 57 e altezza 20 si deve intervenire nella parte
dichiarativa del programma riportato nel listato 2.5 scrivendo:
const
BASE = 57;
ALTEZZA =20;
oppure nel corpo del listato 2.4, dove al posto delle costanti si sono utilizzate delle variabili, si deve scrivere:
base := 57;
altezza := 20;
Dopo aver effettuato nuovamente la
compilazione, la successiva esecuzione restituirà 1140, cioè l'area del rettangolo
in centimetri quadri. Come si comprende anche da questo semplice esempio, la
procedura di modifica del programma è estremamente
laboriosa. Per rendere il programma di applicazione
più generale si deve permettere a chi lo sta utilizzando di immettere i valori
della base e dell'altezza: in questo modo l'algoritmo calcolerà l'area di un
qualsiasi rettangolo. L'esecuzione dell'istruzione:
read(base);
fa sì che il sistema attenda l'immissione di un dato da parte dell'utente. Durante l'esecuzione di un programma può essere richiesta all'utente l'immissione di più informazioni. Perciò è opportuno visualizzare frasi esplicative; a tale scopo facciamo precedere le istruzioni read da appropriate istruzioni write:
write('Valore
base: ');
read
(base);
L'argomento di write è semplicemente una frase da visualizzare, quindi deve essere racchiuso tra apici. Non è neppure necessario richiedere un salto a riga nuova mediante una writeln, in quanto l'immissione può avvenire sulla stessa riga. Quello che apparirà all'utente in fase di esecuzione del programma sarà:
Valore base :
In questo istante l'istruzione read attende l'immissione di un valore, se l'utente
digiterà 15 seguito da INVIO:
Valore base:
15<INVIO>
Questo dato verrà assegnato alla
variabile base:
base
15
L'istruzione read può leggere più valori in ingresso. Per esempio
read(base,
altezza);
aspetta due valori in ingresso e li assegna rispettivamente alle variabili base e altezza.
Nel nostro caso dovremmo coerentemente modificare il commento che apparirà sul video:
write('Valori
di base e altezza: ');
read(base,
altezza);
L'utente vedrà apparire sul video il messaggio dell'istruzione write e dovrà inserire i valori separati da almeno uno spazio:
Valori di base e
altezza: 10 13
Nel caso di valori numerici non ha importanza se vengono digitati uno o più spazi prima o dopo i valori in ingresso.
L'istruzione readln agisce in modo simile a read; ma, a differenza di questa, alla fine della lettura delle variabili effettua un salto a riga nuova. Inoltre readln, seguita direttamente dal punto e virgola, può essere utilizzata per provocare un'attesa indefinita durante l'esecuzione del programma:
write('Premere
Invio per continuare...');
readln;
{ Calcolo area
rettangolo } program rettangolo4; var base, altezza,
area: integer; begin writeln; writeln; writeln('AREA
RETTANGOLO'); writeln; write('Valore
base : '); readln(base); write(' Valore altezza: '); readln(altezza); area := base*altezza; writeln; writeln('Base
: ', base); writeln('Altezza:
', altezza); writeln('Area:
', area); readln; end.
Listato 2.6
Calcolo
dell'area di
un rettangolo
(quarta
versione)
Vediamo l'esecuzione del programma nell'ipotesi che l'utente inserisca i valori 10 e 13:
AREA RETTANGOLO
Valore base: 10
Valore altezza: 13
Base: 10
Altezza: 13
Area: 130
Per lasciare una riga vuota si deve utilizzare l'istruzione writeln seguita direttamente dal punto e virgola:
writeln('AREA
RETTANGOLO');
writeln;
La prima istruzione writeln fa andare il cursore a riga nuova dopo la visualizzazione di AREA RETTANGOLO, la seconda, senza argomenti, lo fa scorrere di un'ulteriore riga.
Si possono stampare più variabili con una sola write o writeln, indicando gli identificatori separati da una virgola. L'istruzione
writeln(base,
altezza, area);
inserita alla fine del programma precedente, visualizzerebbe, se i dati immessi dall'utente fossero ancora 10 e 13:
1013130
Per far in modo che i valori vengano separati da spazi dobbiamo esplicitamente inserirli all'interno di apici:
writeln(base,’
‘,altezza,’ ‘,area);
E comunque consigliabile inserire commenti che descrivano ciò che viene visualizzato:
writeln('Base:
', base,' Altezza: ', altezza, ' Area: ', area);
genererà:
Base:
10 Altezza: 13 Area: 130
Si tratta dunque di inserire i vari messaggi che devono apparire sul video tra apici, prima o dopo gli oggetti da visualizzare. È possibile inserire espressioni aritmetiche nella write al posto delle variabili:
writeln('Area: ',
10*13);
L'istruzione stamperà 130, cioè il risultato dell'espressione.
L'operatore div (divisione intera)
x div y
restituisce il risultato della divisione intera tra x e y. Per esempio:
11 div 4
è uguale a 2; viene cioè effettuato il troncamento del risultato alla parte
intera mentre la parte decimale viene perduta. L'operatore mod (modulo)
x
mod y
consente di ottenere il resto della divisione intera x div y. Per esempio:
34 mod 5;
ha valore 4 (resto di 34 diviso 5). Si noti che per ogni x vale la formula:
x =
x div y
* y +
x mod y
All'interno delle espressioni aritmetiche la priorità degli operatori segue le regole dell'algebra. Le operazioni di negazione sono eseguite per prime, poi vengono eseguite le moltiplicazioni e le divisioni, infine le somme e le sottrazioni. Se due operatori sono gerarchicamente allo stesso livello, per esempio * e div, quello più a sinistra sarà considerato per primo (vedi figura 2.1).
Il risultato di un'espressione intera può essere assegnato a una variabile intera, come abbiamo già visto nel programma per il calcolo dell'area di un rettangolo:
area := base*altezza;
In un'istruzione di assegnamento
y :=
z + 3*x
prima viene valutata completamente la parte a destra dell'assegnamento e poi il risultato viene attribuito alla variabile y.
La priorità degli operatori può essere alterata mediante parentesi tonde; in questo caso vengono valutate per prime le operazioni contenute nelle parentesi tonde più interne. Osserviamo per esempio il seguente assegnamento:
x :=
a + b
- 15 +
4 * c;
nell'ipotesi che le variabili intere a, b e e abbiano rispettivamente valore 7, 3 e 5, a x viene assegnato il valore 15. L'inclusione tra parentesi dell'espressione 15 + 4
x :=
a + b
- (15 +
4) * c;
cambia evidentemente il risultato, che diventa -85. ,.
Nell'espressione:
(a + b - (15 + 4) ) * c
viene prima valutata l'espressione presente nella parentesi più interna (15+4) e successivamente quella nella parentesi esterna (a+b-19); il risultato viene infine moltiplicato per il valore di c, che restituisce -45. Il risultato dell'espressione
a + b
+ c mod
2
è 11, in quanto l'operatore mod restituisce il resto della divisione intera tra il valore di e (5) e 2, che è 1. Invece il risultato di
(a + b +
c) mod
2
è 1. Infatti prima viene effettuata la somma dei valori di a, b e e, successivamente viene calcolato il resto della divisione intera del risultato (15) per 2. Il risultato di
(a +
b)*32 + 4
è 340, mentre quello di
((((((c + 6) * 3 + a)
div 2)
+ 10 * 4) div
12) + b)
è 8. Non esiste alcun limite al numero di parentesi tonde aperte. Attenzione: l'assegnamento a un intero di un valore non compreso nell'intervallo previsto, da -32768 a +32767, genera effetti difficilmente prevedibili. Provate, durante l'esecuzione del programma del listato 2.6 che calcola l'area del rettangolo, a inserire i valori 751 e 63. Tali valori verranno immessi nelle variabili base e altezza e l'istruzione
area := base*altezza;
assegnerà ad area il valore -18223, mentre il risultato corretto sarebbe 47313. Si ha quello che si definisce un overflow (traboccamento): l'operazione genera un valore intero che in binario non è rappresentabile con due byte, il bit che costituisce la parte più rappresentativa del numero viene perciò perso e il risultato è completamente errato. Nel capitolo 9 (Tipi di dato) vedremo come il Turbo Pascal metta a disposizione dell'utente altri tipi numerici che permettono di gestire variabili intere che possono assumere valori ben più grandi di quelli consentiti dal tipo integer.
2.6 Funzioni e
procedure predefinite
funzione, analogamente a quanto definito in matematica, è uno strumento che, a partire da uno o più valori presi in input, restituisce un valore associato ai primi in modo univoco.
Più avanti impareremo a creare le nostre funzioni; esistono però delle funzioni predefinite o standard, già pronte all'uso, che il linguaggio mette a disposizione del programmatore. Da questo punto di vista non interessa come il compito affidato alla funzione venga svolto, basta sapere cosa deve esserle passato in entrata e cosa restituisce in uscita. Un esempio di funzione predefinita è abs, che applicata a un numero ne restituisce il valore assoluto.
Se dopo il nome della funzione abs, all'interno di parentesi tonde, viene inserito un numero intero, abs restituisce il suo valore assoluto, valore che è possibile assegnare a una variabile o utilizzare direttamente all'interno di un'espressione. Se w e j sono variabili di tipo intero, l'istruzione
w := abs (j) ;
assegna a w il valore assoluto di j.
All'interno delle parentesi tonde può essere inserito direttamente un valore, come nel caso
w := abs (3) ;
che assegna a w il valore 3; o come nel caso
w := abs(-186);
che assegna a w 186.
Il risultato restituito da una funzione può essere inserito all'interno di
un'espressione:
w := j*abs(k);
dove, se j è uguale a 100 e k a -73, viene assegnato a w il valore 7300, mentre con w : = j * k a w sarebbe stato assegnato -7300. Osserviamo nel listato 2.7 un programma completo che utilizza la funzione abs. Si tratta del calcolo della lunghezza di un segmento i cui estremi vengono immessi dall'utente.
Se consideriamo la successione dei numeri interi, ognuno dei due estremi del segmento può essere sia positivo che negativo: perciò la lunghezza corrisponde al valore assoluto della differenza tra i due valori.
Per esempio, se il primo estremo corrisponde a -5 e il secondo a -1, la lunghezza del segmento sarà 4, cioè il valore assoluto di - 5 - (-1). L'esecuzione del programma del listato 2.7, nel caso l'utente inserisca i valore 7 e -2, produrrà la seguente visualizzazione:
LUNGHEZZA SEGMENTO
Primo estremo: 7
Secondo estremo: -2
Lunghezza segmento:
9
{ Esempio
utilizzo di funzioni } program lunghezza_segmento;
var a, b: integer; segmento, lunghezza: integer; begin writeln; writeln; writeln('LUNGHEZZA SEGMENTO'); writeln; write('Primo estremo: '); readln(a); write('Secondo estremo: '); readln(b); segmento := a - b; lunghezza := abs(segmento); writeln('Lunghezza segmento: 'lunghezza); readln; end.
Listato 2.7
Utilizzo
della funzione
abs
I parametri di wri te e writeln possono essere espressioni al cui interno sono presenti delle funzioni, come nel caso delle istruzioni:
writeln('
valore assoluto: ', abs(j));
writeln('
valore assoluto +1: ', abs(k)+1);
Passiamo adesso a considerare altre funzioni disponibili in Pascal.
Se num è una variabile numerica integer, abbiamo i seguenti esempi
di funzioni standard del Turbo Pascal:
pred
(num) restituisce
il predecessore di num
succ
(num) restituisce
il successore di num
sqr
(num) restituisce
il quadrato di num
Se x è una variabile intera, l'istruzione
x := pred(50);
assegna a x il valore 49, mentre
x := succ(50);
assegna a x il valore 51.
Se y ha valore 7,
x
:= succ(y+3);
assegna a x il valore 11 e
x
:= sqr(y);
assegna a x il valore 49. Infine in
x
:= prec(sqr(y));
prima viene calcolata la funzione più interna sqr ( y ), che restituisce 49, poi quella più esterna, per cui a x viene assegnato il valore 48. Un'altra funzione numerica importante è random (n), che restituisce un numero intero casuale compreso fra O e n - 1. Quindi, se x è una variabile intera, l'istruzione
x
:= random(10);
assegna a x un valore casuale compreso fra O e 9, mentre
x := random(lOO) + 100;
assegna a x un valore casuale compreso fra 100 e 199.
Nel listato 2.8 si ha un esempio di utilizzo della funzione random per simulare al computer il lancio di due dadi.
Osserviamo che iterando più volte l'esecuzione del listato 2.8 otteniamo sempre lo stesso risultato. Questo perché la funzione random genera numeri solo apparentemente casuali, in realtà determinati a partire da un valore iniziale (detto seme) memorizzato nella variabile di sistema RandSeed.
Listalo 2.8
Utilizzo della
{Esempio di utilizzo della funzione random} program lancio_dadi ; var a, b: integer; totale : integer; begin writeln; writeln ('LANCIO DI
DUE DADI'); a := random(6) + 1; b := random(6) +1; totale := a + b; writeln
('Lancio : ',totale); readln; end.
funzione
casuale
random(n)
Per modificare questo valore occorre utilizzare l'istruzione randomize;
che modifica il valore dei seme. Per avere lanci di dadi sempre diversi occorrerà quindi inserire all'inizio del programma:
begin
randomize;
writeln;
Le procedure, come le funzioni, svolgono un compito specifico ma, a differenza di queste, non restituiscono direttamente un valore in uscita e non possono cosi essere utilizzate all'interno di espressioni. Vengono richiamate, come abbiamo fatto con randomize, specificandone il nome seguito da un punto e virgola; per esempio l'istruzione
ClrScr;
invoca la procedura ClrScr (CLeaRSCReen) che pulisce completamente lo schermo e posiziona il cursore nell'angolo in alto a sinistra dello stesso. Un'altra procedura molto utilizzata è
GotoXY{c, r);
che sposta il cursore in una certa posizione dello schermo. Analogamente allo schema di una battaglia navale, il video è infatti costituito da una griglia invisibile formata da linee verticali e orizzontali; in ogni istante il cursore è localizzato all'incrocio tra una colonna e una riga. La procedura GotoXY (c, r) sposta il cursore sulla colonna c, riga r. I valori interi che c e r possono assumere sono normalmente compresi tra 1 e 80 per il primo, tra 1 e .25 per il secondo; c e r possono essere valori costanti o variabili. L'istruzione
GotoXY(25,10);
posiziona il cursore nella decima riga in corrispondenza della venticinquesima colonna.
Infine, se il computer con cui lavoriamo dispone di uno schermo a colori sono interessanti le procedure predefinite
TextColor(n);
che modifica il colore con cui i dati vengono visualizzati sullo schermo; e TextBackground (n);
che modifica il colore dello sfondo (background) su cui viene visualizzato il testo. Per esempio, le istruzioni
textcolor
(14);
textbackground(4);
writeln('Prova
testo a colori');
Tabella 2.1
Codici dei colori
nero 0 grigio scuro 8
blu 1 blu chiaro 9
verde 2 verde chiaro 10
turchese 3 turchese chiaro 11
rosso 4 rosso chiaro 12
magenta 5 magenta chiaro 13
marrone 6 giallo 14
grigio chiaro 7 bianco 15
visualizzano sullo schermo la scritta Prova testo a colori in caratteri gialli su sfondo rosso. I colori disponibili per il testo e lo sfondo dipendono dal computer; nella tabella 2.1 sono riportati i valori corrispondenti ai codici più comuni.
Le procedure ClrScr, TextColor, TextBackground e GotoXY non vengono collegate automaticamente ai nostri programmi come avviene per le funzioni viste in precedenza. Si deve quindi richiedere esplicitamente questa connessione al sistema, inserendo dopo l'intestazione del programma e prima della dichiarazione di costanti e variabili
uses crt;
dove crt (Cathode Ray Tube) è il nome della libreria (o modulo) contenente l'insieme delle funzioni e delle procedure per la gestione del video. In precedenza abbiamo potuto utilizzare direttamente le funzioni esaminate perché queste, come molte altre funzioni e procedure, sono contenute nel modulo system che viene automaticamente collegato al programma dal compilatore.
Nel listato 2.9 è riportato un esempio di uso delle procedure standard comprese nella libreria crt. Il programma visualizza nel mezzo dello schermo, dopo averlo pulito, alcuni semplici testi scritti con colori e su sfondi differenti. Si osservi che abbiamo utilizzato delle write e non delle wr i te In in quanto la posizione della visualizzazione viene comunque determinata dalla GotoXY precedente.
Una dichiarazione uses può riguardare un modulo oppure una lista di moduli: in quest'ultimo caso gli elementi della lista devono essere separati da una virgola.
La possibilità di includere diversi moduli utilizzando le relative funzioni e procedure predefinite ci porta a definire una struttura sintattica del programma più generale:
{ Uso delle
procedure della libreria crt} program provaCRT; uses crt; begin ClrScr; GotoXY(30, 7); write
('BIANCO SU NERO'); TextColor(14);
TextBackground(4) ; GotoXY(30,ll); write('GIALLO SU
ROSSO'); TextColor(lO); TextBackground(7); GotoXY(30,15); write('VERDE SU GRIGIO'); readln; end.
Listato 2.9
Utilizzo delle
procedure
della libreria
standard
crt
program nome_programma;
uses
lista_di_moduli;
parte_dichiarativa
begin
istruzionel;
istruzioneN;
end.
Altri moduli importanti del Turbo Pascal sono printer per l'uso della stampante e Graph per la grafica.
Anche read e write sono in realtà procedure standard. La procedura read accetta in ingresso le variabili in cui immettere i valori letti e write accetta i commenti e le variabili da scrivere.
I valori che le funzioni e le procedure accettano tra parentesi tonde sono detti parametri; si noti che ClrScr non accetta alcun parametro in ingresso, mentre GotoXY ne accetta due.
In seguito utilizzeremo numerose funzioni e procedure predefinite e vedremo in quale modo costruirne di proprie.
2.7 Precedenti
versioni del Turbo Pascal
L'esposizione principale di questo volume si riferisce alla versione 7 del Turbo Pascal, anche se le differenze con le precedenti versioni sono minime.
In particolare, quanto illustrato in questo capitolo è valido per tutte le versioni del Turbo Pascal eccetto che per le seguenti differenze relative alla versione 3.
In quest'ultima non è presente il concetto di inclusione di librerie di funzioni e procedure, per cui non esiste la direttiva uses. Le procedure GotoXY eClrScr sono comunque disponibili direttamente: per quanto riguarda i programmi di questo capitolo è quindi sufficiente togliere uses crt dal listato 2.9.
Viceversa, se avete dei programmi scritti nella versione 3 che usano tali procedure, per renderli compatibili alle versioni successive dovete aggiungere l'inclusione del modulo crt dopo l'intestazione:
uses crt;
Nella sola versione 3 il nome del programma che nell'intestazione segue la parola chiave program è considerato non un identificatore ma un semplice commento. Non deve quindi rispettare le regole per la costruzione degli identificatori e può essere in conflitto con un identificatore, per esempio di variabile o costante.
Se un programma scritto per la versione 3 del Turbo Pascal quando viene eseguito in una versione successiva produce per questa ragione un errore, è sufficiente cambiargli nome seguendo le regole previste per gli identificatori.
Domande di verifica
Qual è la struttura generale di un programma?
Come si dichiarano le variabili di tipo intero?
Qual è l'operatore che permette di assegnare un valore a una variabile?
Quale compito svolgono le istruzioni write e read?
Qual è la differenza fra write e writeln? E fra read e readln?
Quale utilizzo viene fatto delle costanti e come si definiscono?
Quali operatori possono essere utilizzati con le variabili di tipo
integer? Qual è il loro effetto?
Qual è la gerarchla fra gli operatori aritmetici?
Come operano random e randomize?
Quali funzioni e procedure predefinite conosci? Qual è il loro effetto?
Che cosa è una libreria?
In quale libreria si trovano le procedure GotoXY e TextColor? Ache
cosa servono?
Come possono essere utilizzate nei programmi funzioni e procedure
predefinite?
Esercizi
1 Scrivere un programma che visualizzi sullo schermo:
Esercizio n.l, tutto
bene!
2 Scrivere un programma che, utilizzando tre istruzioni write, visualizzi:
Esercizio n. 2,
prove di visualizzazione
3 Scrivere un programma che produca in uscita:
Esercizio n. 3,
prima riga
Esercizio n.3, seconda riga
Esercizio n.3, terza riga
4 Scrivere un programma che calcoli l'espressione^ = ax + b, dove x è uguale a 5, o è uguale a 18 e b è uguale a 7 e dove x,a, b ey devono essere
dichiarate come variabili intere.
Si visualizzi infine il valore finale:
y=97
5 Trasformare il programma dell'esercizio precedente in modo che x sia una variabile il cui valore viene richiesto all'utente in fase di esecuzione.
O Modificare il programma dell'esercizio precedente in modo che a e b non siano variabili ma costanti.
7 Scrivere un programma che calcoli e visualizzi i valori di a, b e e ricavati dalle espressioni indicate:
a := ZERO - abs (x)
b := TOP- abs (y)
c := a * b
dove x e y sono variabili intere immesse dall'utente, ZERO e TOP sono costanti intere di valore zero e mille.
8 Determinare il valore assunto dalle variabili a, b e e al termine di questa sequenza di istruzioni:
a
:= -2;
b
:= a + 1;
b
:= b - abs (a) ;
c
:= a*b
b
:= 3;
9 Scrivere un programma che richieste all'utente lunghezza, larghezza e altezza di un parallelepipedo ne calcoli il volume.
1 0 Scrivere un programma che richieste all'utente lunghezza, larghezza e altezza di un parallelepipedo ne calcoli la superficie totale.
1 1 Scrivere un programma che richieda all'utente un numero di riga r e di colonna e, scriva in quella posizione una O e attorno a questa quattro X nelle posizioni (r,c+2), (r+2,c), O,c-2) e (r-2,c).
12 Se x e y sono variabili intere e x ha valore 25, quali valori vengono assegnati a y da ognuna delle seguenti istruzioni?
a) y= pred(x) ;
b) y= succ (x) ;
e) y= sqr (x) ;
d) y= pred(succ
(x) )
e) y= sqr (pred (x) )
;
f) y= abs(-(x * 2));
g) y= sqr(-x) ;
h) y= sqr (31 div x)
i) y= (31 mod x)*2;
j) y= abs(sqr(31 div
x) - (31 mod x) * 2) ;
1 3 Trascrivere in Pascal le seguenti espressioni matematiche:
a) ab + c-5 c) |x + 3 | (x2 - 3x (x2 - 1))
1 4 Scrivere un programma che, richiesti all'utente i valori dix ey, visualizzi sul video il resto di x diviso y.
1 5 Sapendo che in un parcheggio ogni ora costa 2500 lire, scrivere un programma che richieda il numero complessivo delle ore e visualizzi il totale da pagare.
1 6 Sapendo che una moto percorre n kilometri con* litri di benzina, scrivere un programma che richieda n e x e quindi calcoli quanti kilometri si possono percorrere con un litro.
1 7 Sapendo che in un parcheggio la prima ora costa 2500 lire mentre tutte le successive costano 1500 lire, scrivere un programma che richieda il numero complessivo delle ore e visualizzi il totale da pagare.
1 8 Modificare il programma del precedente esercizio in modo tale che il totale sia visualizzato in rosso su fondo nero.
1 9 Scrivere un programma che richieda all'utente un tempo in secondi e ne visualizzi quindi l'equivalente in ore, minuti e secondi.
program tutto sbagliato; cost base, altezza, area := integer; begin base = 3; altezza := 7 area := base x altezza; writeln('Base: , base); writeln('Altezza:'; altezza); writelm('Area: \ area); end
Listato 2.10
Listato tutto sbagliato
2 O [ Inverso del precedente ] Scrivere un programma che richieda il numero di ore, minuti e secondi che compongono un tempo e visualizzi quindi l'equivalente espresso in secondi.
21 Indicare tutti gli errori commessi nel listato 2.10.
22 Scrivere un programma che simuli al computer tre lanci consecutivi di
palline in una roulette.