0% au considerat acest document util (0 voturi)
731 vizualizări

Tutorial Pascal

Încărcat de

Romeo Borcaias
Drepturi de autor
© Attribution Non-Commercial (BY-NC)
Formate disponibile
Descărcați ca DOCX, PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
731 vizualizări

Tutorial Pascal

Încărcat de

Romeo Borcaias
Drepturi de autor
© Attribution Non-Commercial (BY-NC)
Formate disponibile
Descărcați ca DOCX, PDF, TXT sau citiți online pe Scribd
Sunteți pe pagina 1/ 66

Tutorial Pascal

Pascal, de la inceputuri pana acum


Pascalul original Limbajul Pascal a fost scris in 1971 de Niklaus Wirth, profesor la Politehnica din Zurich, Elvetia. Pascalul a fost intentionat ca o versiune simplificata, in scopuri educationale, a limbajului Algol, care aparuse in 1960. Cand a aparut Pascalul, existau deja multe limbaje, dar numai putine erau folosite pe scara larga, ca Fortranul, C, Assembler, etc. Ideea de baza a noului limbaj de programare a fost ordinea, controlata printr-un concept puternic de tip de data, necesitand declaratii si programare structurata. A fost imaginat ca o unealta de predare pentru studentii la programare. Turbo Pascal... a fost odata... Faimos in lumea intreaga, compilatorul de Pascal de la Borland, denumit Turbo Pascal, a aparut in 1983, fiind bazat pe "Pascal - manualul utilizatorului", de Jensen si Wirth. Acest compilator de Pascal a fost unul din cele mai bine vandute compilatoare din toate timpurile, si a facut popular acest limbaj de programare pe platformele PC, multumita simplitatii si puterii lui. Turbo Pascal a introdus un mediu de dezvoltare integrat (IDE = integrated development environment) unde puteai edita programul (intr-un editor compatibil cu WordStar, un editor de texte), puteai rula programul, verifica si corecta erorile. Suna ca si ceva obisnuit acum, dar atunci trebuia sa iesi din editor inapoi in DOS, sa folositi compilatorul de la linia de comanda, sa scrii undeva numerele liniilor unde ai avut erori, sa redeschizi editorul sa corectezi si tot asa. Mai mult, firma Borland a vandut Turbo Pascal cu 49 de dolari, in timp ce compilatorul de Pascal de la Microsoft costa cateva sute de dolari. Acei multi ani de succes ai Turbo Pascal au contribuit la faptul ca Microsoft, in cele din urma, n-a mai lucrat la compilatorul lor de Pascal. Pentru ca sa vedeti de unde a inceput totul, puteti da jos de pe net prima versiune de Turbo Pascal. Nu va speriati, totusi, a fost doar prima Turbo Pascal... acum... In zilele noastre, Turbo / Borland Pascal nu prea mai e folosit, decat in scoli, dar a avut era lui de glorie. Motivul pentru care nu mai e folosit e destul de simplu: crearea unui program pentru Windows sau Linux (cu GUI = graphical user interface), chiar si in Borland Pascal 7.0 for Windows, dureaza foarte mult si cam doare. Nerecomandat incepatorilor ! Cu toate acestea, Pascal a fost si va ramane un limbaj accesibil celor care nu stiu programare. Odata stapanit bine, poate fi o rampa de lansare catre majoritatea celorlalte limbaje de programare.

Interfata Turbo Pascal 7.0 Mediul integrat (IDE) Turbo Pascal prezinta o bara de meniu orizontala, in partea de sus (meniul principal). Are 10 optiuni:

File Face cam ce face orice meniu File din zilele noastre. Deschide fisier nou, salveaza, etc. Edit Ce credeti ? idem Search Meniul de cautare al aproape oricarui editor de text. Run Ofera modalitati de rulare a programului (normal, pas cu pas), oprirea lui pentru modificari si posibilitatea de a porni programul cu anumiti parametri. Compile Compileaza programul (transforma codul sursa in cod masina, pentru a putea fi inteles si rulat de procesor) si faciliteaza crearea unui proiect, prin setarea unui "primary file" (programul care e rulat cand utilizatorul da aceasta comanda este cel setat prin primary file, asa ca nu mai aveti probleme cand dati Ctrl+F9, daca sunteti intr-un unit. Debug Vizualizarea valorilor variabilelor unui program, in timpul rularii acestuia, afisarea ultimului ecran al programului, puncte de intrerupere (breakpoint-uri), etc Tools Cateva programe care pot ajusta crearea programului, prin modificarea parametrilor pentru crearea lui, verificarea programului pentru a vedea unde "papa" mult timp, etc. Options Puteti seta directoarele implicite pentru unituri, culorile folosite de editor, salvarea preferintelor si (foarte) multe altele. Window Posibilitati de aranjare a ferestrelor Help Destul de usor de inteles ce face asta... doar ca Helpul e in engleza (sper ca nu se astepta cineva sa fie in romana )

E clar ca, in majoritatea timpului, nu veti avea nevoie de cele mai multe din optiunile oferite de meniu, asa ca am sa dau mai jos o lista de scurtaturi de la tastatura pentru cele mai uzuale functii:

COMBINATII UZUALE DE TASTE IN BORLAND PASCAL 7.0

ALT + X F2 F3

inchide Borland Pascalul (l-am pus primul pentru a putea iesi repede din el, daca aveti probleme salveaza fisierul curent deschide un fisier (unul nou sau unul salvat) )

COMBINATII UZUALE DE TASTE IN BORLAND PASCAL 7.0

SHIFT + DEL CTRL + INS SHIFT + INS ALT + F5 ALT + F9

comanda CUT comanda COPY comanda PASTE arata ultimul ecran al programului (ultimele afisari) verifica erorile de sintaxa si compileaza programul reseteaza programul (in caz ca il aveti pornit in modul pas cu pas) pentru alte modificari adauga o variabila a carei valoare va fi afisata pe parcursul executarii programului cu cursorul pus pe un anumit cuvant, va deschide Help-ul la sectiunea respectiva cu cursorul pus pe un cuvant care e numele unui fisier cu extensia .PAS din directorul curent, deschide si acel fisier (de ex. un unit)

CTRL + F9 verifica erorile de sintaxa, compileaza si ruleaza programul CTRL + F2 CTRL + F7 CTRL + F1 CTRL + ENTER

La lucru in Turbo Pascal 7.0 Pentru a incepe un program nou, in primul rand trebuie sa aveti Pascalul pornit. Selectati File / New si veti avea un nou fisier, denumit NONAMEXX.PAS (XX simbolizand al catelea fisier nou deschis este acesta). Alta solutie este sa alegeti File / Open, introduceti un nume, iar fisierul va fi automat salvat (bineinteles, gol).

Acum ca aveti in fata tot ce va trebuie, nu aveti DECAT sa scrieti programul, sa-l verificati de erori (poate fi verificat de erori compilandu-l, dar si rulandu-l direct, fiindca inainte de a-l rula il si verifica... ce descoperire )

Foarte "originalul" program care afiseaza Hello World este mai jos. Spor la joaca
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Begin 2. Write('Hello World'); 3. ReadLn;

4. End.
Veti invata in urmatoarele tutoriale ce inseamna si ce fac aceste 4 linii de mai sus, momentan e de ajuns sa stiti ca puteti modifica Hello World de mai sus cu orice text vreti voi si ca va trebui sa apasati tasta Enter pentru a iesi din program.

Partile unui program Pascal

Cele trei parti principale ale unui program Pascal sunt: antetul (header-ul) programului, declaratiile in care se descriu obiectele asupra carora vor avea loc prelucrarile (in cadrul programului pe care il analizam, vom considera numai declararea variabilelor) si partea principala a programului in care se scriu instructiunile (ansamblul operatiilor ce urmeaza a fi executate). O structura vizuala a unui program Pascal ar arata in felul urmator:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. PROGRAM Nume_Program;
2. 3. CONST 4. (* declaratii de constante *) 5. 6. TYPE 7. (* declaratii de tipuri *) 8. 9. VAR 10. (* declaratii de variabile *) 11. 12. (* declaratii de subprograme (functii si proceduri) *) 13. 14.BEGIN 15. (* instructiuni *) 16. END. De remarcat ca un program functional necesita doar ultimele 3 linii din schita de mai sus, iar compilatorul nu va avea nimic impotriva. Bineinteles, nu veti putea folosi variabile, constante, tipuri sau subprograme. Pentru a intelege aceasta structura, deloc complicata, sa analizam fara graba un program Pascal care calculeaza si afiseaza volumul unui paralelipiped. Este vorba de un program care declara variabile, citeste valorile acestora, efectueaza un calcul simplu si afiseaza rezultatul.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. PROGRAM volumul;
2. {calculeaza si afiseaza volumul unui paralelipiped} 3. VAR lungime, latime, inaltime, volum: real; 4. BEGIN 5. writeln('Introduceti valori: lungime, latime, inaltime'); 6. readln(lungime, latime, inaltime); 7. volum := lungime * latime * inaltime; 8. writeln('Volumul paralelipipedului= ', volum:9:5,' metri cubi')

9. END. {volumul}
Cand programul este rulat, pe ecran se va afisa:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Introduceti valori: lungime, latime inaltime 2. 8.3 7.25 6.29 3. Volumul paralelipipedului= 378.50075 metri cubi De remarcat ca sirul "8.3 7.25 6.29" a fost introdus de la tastatura, fiind valorile pentru lungime, latime, respectiv inaltime. Examinand acest program, vom putea vedea urmatoarele elemente: Antetul (header-ul) programului Prima linie contine antetul programului. Program este un cuvant rezervat cu care incepe (optional) un program (Borland) Pascal. El este urmat de numele programului: volumul si de simbolul punct si virgula. Simbolul punct si virgula (" ; ") este un separator de instructiuni. Este strict necesar, bineinteles, cu unele mici exceptii, care le voi semnala la momentul potrivit. O restrictie importanta a identificatorilor este aceea ca nu pot contine in interiorul lor blancuri (spatii). Comentariile A doua linie a programului "volumul" este numita un comentariu. Orice sir de caractere delimitat de seturile { si } sau (* si *) reprezinta un comentariu. Comentariile sunt folosite pentru a mari inteligibilitatea programelor (ele fiind ignorate de compilatorul Pascal), usurand astfel munca de intelegere si corectare a acestora. Daca se doreste imbricarea comentariilor, acest lucru se face alternand acoladele cu (*. Ex. modul corect:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. (* comentariu1 {comentariu imbricat} comentariu2 *) 2. { comentariu1 (*comentariu imbricat*) comentariu2 } modul incorect
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. (* comentariu1 (*comentariu imbricat*) comentariu2 *)


Setul de acolade { si } mai este folosit si pentru directivele de compilare. Comentariile fac programul mai usor de inteles. Daca va scrieti programele fara comentarii veti putea avea nevoie de o perioada de reacomodare cu codul cand veti reveni pentru a-l modifica. In general, in partile de cod mai serioase sau mai complicate, se obisnuieste sa se foloseasca cateva comentarii. In plus, daca aveti de gand sa modificati codul pentru un alt scop decat cel initial, este bine sa faceti un comentariu in care sa explicati ce doriti sa faceti.

Remarcati in ultima linie a programului prezenta comentariului {volumul}, tocmai pentru a reaminti cititorului numele programului care s-a incheiat. Comentariile pot fi plasate oriunde in cadrul programului, dar nu in interiorul identificatorilor. Declararea variabilelor Cuvantul cheie var (prescurtare de la variables) incepe actiunea de declarare a variabilelor. Fiecare variabila trebuie sa poarte un nume. Programul volumul foloseste patru variabile (lungime, latime, inaltime, volum) identificate in faza de analiza structurata a programului. Acestea sunt grupate astfel: Variabile de intrare: lungime: lungimea paralelipipedului latime: latimea paralelipipedului inaltime: inaltimea paralelipipedului Variabile de iesire: volum: volumul paralelipipedului Nu trebuie sa va speriati de denumirea pompoasa (de intrare, de iesire). Variabilele se declara la fel, indiferent de rolul lor. Denumirile sunt folosite doar pentru a usura intelegerea rolului acestor variabile in program. Tipuri de date In Pascal exista doua tipuri (simple) de date pentru variabile numerice: intregi si reale. Variabilele intregi pot lua valori numai numere intregi, cum ar fi: 6, -19, 0 sau 73700. Un calculator poate reprezenta numai o submultime finita de intregi. O valoare intreaga poate fi salvata in memoria unui calculator doar daca respectiva valoare apartine intervalului (-maxint1, maxint), undemaxint este o constanta predefinita. In majoritatea implementarilor limbajului Pascal constanta maxinteste egala cu 32767. Daca o variabila Pascal va avea o valoare fractionara, variabila trebuie sa fie de tip real. Intr-un program (Borland) Pascal tipul fiecarei variabile utilizate trebuie sa fie declarat. Omiterea declararii unei variabile folosite in partea principala a programului va genera o eroare. In programul pe care-l analizam (volumul), declararea variabilelor s-a facut utilizand enuntul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. VAR lungime, latime, inaltime, volum: real;


Odata intalnit acest enunt, compilatorul afla ca toate cele patru variabile sunt de tip real. Zona de memorie alocata variabilelor Fiecarei variabile din program i se asociaza o locatie de memorie pe care v-o puteti imagina ca pe o cutie avand inscriptionate: nume si tip. Continutul cutiei este dat de valoarea curenta a variabilei. Tipul defineste categoria valorii din cutie. Programul refera variabila prin nume. Partea principala a programului reprezinta zona activa, executabila a programului. Cuvintele rezervate BEGIN si END delimiteaza instructiunile care descriu algoritmul principal al problemei de rezolvat.

Enunturile (instructiunile) write / writeln Enunturile write / writeln sunt utilizate pentru afisarea pe un suport de informatie (de regula monitorul) a rezultatelor obtinute in urma prelucrarilor, a mesajelor catre utilizator etc. Write si WriteLn reprezinta in Pascal doi identificatori (de procedura) predefiniti (standard). De remarcat ca daca dati unui program numele "write" (sau "writeln"), nu mai aveti voie sa folositi in program nici un enunt write (sau writeln) cu sensul predefinit (adica sa afiseze un text, variabila, etc). Ori de cate ori se va executa un enunt write / writeln, calculatorul va afisa ad-litteram tot ceea ce este inclus intre apostrofuri, precum si valorile oricarei variabile sau expresii aflate intre paranteze. In plus fata de write, Writeln va trece la linie noua dupa afisarea propriu-zisa. Pentru separarea elementelor din corpul instructiunii se folosesc virgulele. Primul enunt din programul analizat (volumul) determina calculatorul sa scrie pe ecran mesajul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Introduceti valori: lungime, latime inaltime dupa care va muta cursorul la inceputul liniei urmatoare. Fara un astfel de mesaj este greu sa ne dam seama ca este timpul sa se tasteze ceva. Writeln forteaza calculatorul sa afiseze tot ceea ce s-a specificat in interiorul parantezelor si sa treaca la linie noua. La un enunt write, cursorul va ramane pe pozitia imediat urmatoare ultimul caracter scris cu acest enunt. Writeln poate fi folosit si fara parametri pentru a muta cursorul cu o linie mai jos. Enuntul readln In momentul in care s-a executat instructiunea
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. readln(lungime, latime, inaltime);


calculatorul asteapta de la utilizator sa introduca trei numere. Primul va fi atribuit variabilei lungime, cel de-al doilea variabilei latime si in sfarsit cel de-al treilea variabilei inaltime. Nu uitati ca toate cele trei variabile sunt de tip real! Aceste valori pot fi tastate pe o singura linie, cu spatii intre ele, sau cate una pe linie. De remarcat ca valorile (folosind instructiunile Read / ReadLn) nu sunt citite pana la apasarea tastei Enter. Utilizarea combinatiei write-readln in locul combinatiei writeln-readln De foarte multe ori, in programarea calculatoarelor se foloseste combinatia write-readln in locul combinatiei writeln-readln. Avantajul combinatiei write-readln este acela ca valoarea care se introduce va aparea pe aceeasi linie a ecranului cu cererea, in loc sa apara pe o linie proprie, cum s-ar fi intamplat in cazul folosirii combinatiei writeln-readln.

Enuntul de atribuire (asignare) Enuntul ce urmeaza dupa enuntul readln


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. volum :=lungime*latime*inaltime; se numeste enunt de atribuire intrucat el calculeaza ceva (produsul dintre lungime, latime si inaltime) si atribuie (asigneaza, afecteaza) rezultatul variabilei din stanga simbolului ":=". Partea dreapta a acestui enunt este un exemplu de expresie aritmetica. Formatarea afisarii Ultimul enunt din programul volumul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. writeln('Volumul paralelipipedului= ',volum:9:5,' metri cubi');


afiseaza intr-o forma explicita rezultatul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Volumul paralelipipedului= 378.50075 metri cubi


Remarcati forma de prezentare a rezultatului. Pentru inceput, sirul de caractere "Volumul paralelipipedului", urmat de rezultatul propriu-zis, afisat insa intr-un sablon de 9 caractere, dintre care cinci reprezinta cifre zecimale. Acest mod de afisare a fost stabilit de specificatorul de format ":9:5" (9 caractere, din care 5 cifre zecimale). In cazul in care rezultatul ar fi avut 10 caractere (4 cifre inaintea virgulei, 5 cifre zecimale), specificatia ":9" nu era luata in seama. In cazul in care ar fi fost mai putine caractere (8 sau 7), atunci primul / primele caractere erau completate cu spatii. Specificatia de format " : x : y " este facultativa, dar fara acest specificator de format, volumul calculat ar fi fost afisat in notatie exponentiala (stiintifica), care este mai greu de citit. In sfarsit, sirul de caractere "metri cubi" completeaza imaginea rezultatului. Spatii albe (whitespace) Spatiile albe (spatiile, tab-urile, sfarsiturile de linie) sunt ignorate de Pascal, cu exceptia (evidenta) a sirurilor de text (stringuri) care sunt intre apostroafe. Totusi, pentru a usura munca oamenilor (a programatorului si a celor care mai vad codul) se recomanda spatierea cat mai ordonata a codului si, foarte important, indentarea codului. Folosirea TAB-ului pentru a indenta codul este nerecomandata, luandu-se in considerare diferentele posibile la intelegerea acestui caracter (2, 4, 8 spatii + posibilitati de a-l redefini in compilatorul dvs.). Identificatori Asa cum am aratat mai sus, identificatorii sunt definiti cu numele dorite. Totusi, exista cateva reguli de baza, de la care nu va puteti abate: Trebuie sa inceapa cu o litera din alfabet englezesc sau cu caracterul "_" (underline, underscore). Poate continua cu orice litera, cifra sau underline

Nu poate contine anumite caractere speciale (~ ! @ # $ % ^ & * ( ) + ` - = { } [ ] : " ; ' < > ? , . / |), multe avand intelesul lor in Pascal. Unele compilatoare de Pascal nu pun nicio restrictie asupra lungimii identificatorilor, dar altele folosesc doar primele cateva caractere (Borland Pascal foloseste primele 63 de caractere - n-am testat niciodata ). Problema des intalnita la identificatorii lungi este faptul ca incetinesc scrierea programului de catre programator. Lungimea identificatorilor este bine sa fie limitata la 10, maxim 15, caractere, in majoritatea cazurilor. Constante Constantele sunt identificatori ai unor valori ce sunt definite la inceputul programului. Valorile asignate constantelor nu pot fi schimbate in decursul rularii programului. Mai jos aveti o lista de constante declarate ca: Integer, Real, Caracter, String, Boolean (in aceasta ordine). Aceste tipuri de date vor fi explicate in tutorialul urmator.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. const numar = 2; 2. alt_numar = 3.14; 3. litera = 'G'; 4. nume = 'Ionut'; 5. DoWait = False;

{numar intreg} {numar real} {caracter} {sir de caractere (string)} {valoare logica (boolean)}

Constantele sunt, de obicei, folosite pentru a tine o valoare des utilizata in program, care s-ar putea sa fie nevoie sa fie schimbata. Ganditi-va ca vreti sa faceti un program care deseneaza un dreptunghi in relief (3D). Pentru aceasta va trebui sa desenati dreptunghiul de mai multe ori, cu diferite culori, pentru a realiza efectul 3D. Daca la primul dreptunghi veti pune marimea laturii 50, la al doilea 49 si tot asa, veti vedea ca atunci cand vreti sa modificati programul, va trebui sa modificati fiecare numar. Alternativ, cu constante, in secventa de cod de mai jos:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. { ... } 2. const latura_mare = 50; 3. latura_mica = 20; 4. { ... } 5. begin 6. { ... } 7. Deseneaza Dreptunghi (latura_mare, 8. Deseneaza Dreptunghi (latura_mare 9. Deseneaza Dreptunghi (latura_mare 10. Deseneaza Dreptunghi (latura_mare 11. Deseneaza Dreptunghi (latura_mare 12.{ ... } 13. end.

2, 4, 6, 8,

latura_mica) latura_mica latura_mica latura_mica latura_mica -

2) 4) 6) 8)

Atentie: acest program nu va rula in Pascal. Este dat doar pentru exemplificare. Secventele { ... } desemneaza cod care e posibil sa existe.

Variabile Variabilele sunt identificatori ai unor valori de anumite tipuri, specificate in declaratie. Spre deosebire de constante, pot fi declarate mai multe variabile de acelasi tip pe o singura linie. Mai jos aveti o lista de declarare de variabile. Aceste tipuri de date vor fi explicate in tutorialul urmator.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var index, numar, suma, produs: Integer; 2. valoare_pi, valoare_e: Real; 3. litera: Char; 4. nume, prenume: String; 5. AmTerminat: Boolean;
Variabilele sunt folosite pentru valori care se pot schimba in decursul programului. Variabilele pot fi folosite si in loc de constante, declarandu-le valoarea in program. Asignare Operatia de asignare este operatia prin care variabilele primesc valori. Pentru a asigna o variabila se foloseste urmatoarea sintaxa:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. variabila := valoare; Secventa := se numeste operatorul de asignare. valoare trebuie sa fie de acelasi tip cu tipul declarat al variabilei. Exemple (folosind declararea de variabile de mai sus):
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. index := 1; 2. numar := 15;


3.

4. 5. 6. 7. 8.

litera := 'k'; litera := #65; {caracterul A majuscula} nume := 'Bitcell'; prenume := '.info'; nume := nume + prenume; {da, sirurilor de caractere li se poate aplica operatorul de adunare, caz in care sirurile vor fi concatenate} 9. {in acest exemplu, variabila "nume" va primi valoarea "Bitcell.info"} 10. 11. AmTerminat := (litera = 'X') and (litera = 'x'); {comparatii care returneaza un rezultat boolean, True sau False} 12. 13. valoare_pi := 22 / 7; {nu este chiar valoarea lui pi, dar pentru un exemplu merge} 14. 15. valoare_e := (numar / index) + suma; 16.

In Pascal, operatorii aritmetici sunt:

OPERATORI ARITMETICI IN PASCAL

Operator + * / div mod

Operatie adunare sau semn pozitiv scadere sau semn negativ inmultire impartire catul impartirii intregi restul impartirii intregi

Operanzi reali sau intregi reali sau intregi reali sau intregi reali sau intregi intregi intregi

Rezultat real sau intreg real sau intreg real sau intreg real intreg intreg

Dupa cum se vede in tabelul de mai sus, div si mod pot fi folosite doar cu numere intregi. Operatorul de impartire / poate fi folosit si cu numere intregi, si cu numere reale, dar va returna intotdeauna un numar real. Celelalte operatii functioneaza pe si numere intregi, si pe numere reale. De tinut minte e faptul ca atunci cand intr-o operatie folosim si numere intregi, si numere reale, rezultatul va fi intotdeauna un numar real. Fiecarei variabile ii poate fi asignat o valoare de acelasi tip cu ea. Acesta este motivul pentru care nu se poate asigna o valoare reala unui intreg. Totusi, anumite tipuri de date vor converti valoarea catre un tip mai mare de date. Asta se intampla, de exemplu, cand se asigneaza o valoare intreaga unei variabile reale.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. numar_intreg := 170;
2. numar_real := numar_intreg; In acest caz numarul intreg 170 va fi convertit in numar intreg, iar variabila numar_real va avea valoarea170.0. Schimbarea unui tip de data in alt tip se numeste typecasting (selectare de tip). Typecasting-ul din exemplul de mai sus este un exemplu de typecasting implicit (se intampla fara a se specifica aceasta intentie de catre programator). Majoritatea compilatoarelor moderne de Pascal suporta si typecasting-ul explicit, cu o sintaxa doar putin diferita de cea a limbajului C. Codul de mai jos da un exemplu al typecasting-ului explicit.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var numar8biti: byte; 2. numar16biti: integer;


3. begin 4. numar16biti := 1000; 5. numar8biti := byte(numar16biti);

6. write(numar8biti); 7. end.
In acest exemplu asignam o valoare intreaga, reprezentata intern pe 16 biti, unei variabile intregi reprezentata pe doar 8 biti, specificand ca vrem sa schimbam tipul variabilei in byte (reprezentare interna de 8 biti). Acesta este typecasting-ul explicit si, in Pascal, se face prin a pune paranteze in jurul valorii careia ii vrem schimbate reprezentarea si punand tipul dorit in fata parantezei. In exemplul de mai sus, variabila pe 8 biti va primi valoarea de 232 (byte-ul cel mai putin semnificativ din valoarea pe 2 bytes initiala). Punctuatie si indentare Avand in vedere ca Pascal ignora spatiile albe (vezi mai sus), punctuatia este necesara pentru a spune compilatorului unde se termina o instructiune. Caracterul care indica terminarea unei instructiuni este, in general, punct si virgula ;. Caracterul care indica terminarea programului este punctul .. Trebuie sa aveti un caracter ; dupa: numele programului fiecare definitie de constanta fiecare definitie de variabila fiecare definitie de tip aproape toate instructiunile Ultima instructiune inainte de o instructiune end nu necesita sa aiba ; la sfarsit. Totusi, nu se intampla nimic sa puneti si in acest caz. De fapt, e chiar recomandat sa puneti in acest caz, datorita faptului ca e posibil sa adaugati o alta instructiune dupa instructiunea care nu are terminator ( ; ) si va veti trezi cu erori de compilare. Indentarea NU este necesara, din punctul de vedere al compilatorului. Cu toate acestea, indentarea este una dintre cele mai importante lucruri in programare, oferind claritate codului. Alta problema cu indentarea este indentarea facuta folosind tasta TAB. Caracterul TAB, fiind afisat in diferite feluri in diferite editoare, duce la neclaritati si/sau imprastierea codului pe latime. (Eu, ca programator, refuz sa lucrez pe o bucata de cod care nu e scrisa cat mai clar posibil. Daca e strict necesar sa lucrez pe ea, primul lucru de care ma ocup este indentarea codului.) Alt lucru important (si care ajuta la claritate) e punerea fiecarei instructiuni pe linie separata. Sa luam o bucata de program si sa vedem ce si cum. Aceasta este bucata de cod, indentata si clara.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. const spaced = ' '; 3. select = ' * '; 4. var c: char; 5. sel: integer;

6. begin 7. clrscr; 8. c := #0; 9. sel := 1; 10. {afisam meniul initial} 11. TextColor(Yellow); 12. TextBackground(Blue); {galben pe albastru pentru optiunea selectata} 13. WriteLn(select, '1. BitCell.info'); (luat dintr-un exemplu)

Aceeasi bucata de cod, scrisa cu picioarele (figura de stil

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. 2. 3. 4.

uses crt; const spaced = ' '; select = ' * '; var c: char; sel: integer; begin clrscr; c := #0; sel := 1; {afisam meniul initial} TextColor(Yellow); TextBackground(Blue); {galben pe albastru pentru optiunea selectata} WriteLn(select, '1. BitCell.info');

Instructiuni conditionale si bucle


La inceputurile informaticii, programarea se facea mai mult dupa ureche, programatorul fiind liber sa foloseasca orice structuri oferite de limbajul de programare in care lucra, fara sa tina cont de posibilitatea ca un alt programator ar avea mari dificultati daca ar incerca sa corecteze / dezvolte programul facut de el. Salturile neconditionate (GOTO) si structurile cu mai multe puncte de intrare sau iesire erau un lucru foarte obisnuit. In mai 1966, Bohm si Jacopini au demonstrat ca orice algoritm poate fi compus din numai trei structuri de calcul: structura secventiala structura alternativa structura repetitiva In 1968, Dijkstra a publicat un articol denumit "Un caz impotriva structurii GOTO" (A Case against the GO TO Statement), care de fapt este metodologia a ceea ce astazi numim programare structurata. Programarea structurata este, in conceptia celor mentionati mai sus, cel mai simplu mod de a crea un program care este usor de inteles si usor de corectat / dezvoltat. Sa luam cele trei structuri de mai sus in ordine. Structura secventiala Este cea mai usoara structura intalnita intr-un program. In programul de mai jos (care face suma a doua numere citite de la tastatura) :

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var a, b: integer;
2. begin 3. write('Dati a: '); readln(a); 4. write('Dati b: '); readln(b); 5. write('Suma celor doua numere este ', a + b); 6. readln; 7. end. , nu intalnim alta structura de calcul decat cea secventiala. Cu asta vreau sa spun ca toate instructiunile vor fi folosite, pe rand, in ordine, fara ca vreuna din instructiuni sa se repete. Suna ca o reteta usoara de mancare, nu ? Exact asa si este. Structura alternativa Este o structura de calcul care permite, in functie de anumite conditii, executarea (sau neexecutarea) unei anumite instructiuni sau secventa de instructiuni. Programul de mai jos vrea sa faca suma a doua numere, in afara de cazul in care primul numar este 0 (zero), caz in care aduna al doilea numar cu el insusi :
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var a, b: integer;
2. begin 3. write('Dati a: 4. write('Dati b: 5. If a <> 0 Then 6. Else 7. readln; 8. end. '); readln(a); '); readln(b); write('Suma celor doua numere este ', a+b) write('Suma celor doua numere este ', b+b);

Deci, am pus o conditie si in functie de ea executam o parte sau alta a codului. Parca suntem in viata. Ne ofera cineva ceva, dar noi nu acceptam decat daca pretul e mai mic sau egal cu o anumita suma, pentru ca altfel ni se pare prea mare pretul. Structura repetitiva Este o structura de calcul care permite, in functie de anumite conditii, executarea unei anumite instructiuni sau secventa de instructiuni de N ori (unde N poate fi 0, 1 sau mai mult). Programul de mai jos citeste doua numere de la tastatura si va aduna primul numar cu el insusi de atatea ori cat e valoarea celui de-al doilea :
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var a, b, suma: integer;


2. begin 3. write('Dati a: '); readln(a); 4. write('Dati b: '); readln(b); 5. suma := 0; 6. For b := 1 To b Do 7. suma := suma + a; 8. write('Suma este ', suma);

9.

10. end.

readln;

Este simplu, doar adunam valoarea din A de B ori, altfel spus inmultim A cu B. Totusi, scopul acestui program nu e de a face inmultirea, ci de a explica structura repetitiva Aceste trei structuri de calcul s-au dovedit de-a lungul timpul a fi, intr-adevar, singurele strict necesare crearii unui program, motiv pentru care nici nu o sa explic in aceste tutoriale cum se folosesc, in Pascal, salturile neconditionate (desi exista aceasta posibilitate). Instructiuni conditionale Avem la dispozitie doua tipuri de instructiuni conditionale in Pascal: If ... Then ... [Else ... ] si Case. Sa incepem cu inceputul. Structura If ... Then ... [Else ... ] Are doua sintaxe, putin diferite. Cea mai obisnuita este mai jos:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. If conditie 2. Then instructiune1 3. Else instructiune2;


conditie este o comparatie sau orice altceva care returneaza o valoarea logica (True sau False), cum ar fisuma = 5 ("=" semnifica egalitate, nu atribuire !) instructiune1 si instructiune2 pot fi orice fel de instructiuni, inclusiv instructiunea compusa. Atentie:In cazul folosirii acestei sintaxe, semnul " ; " (punct si virgula) nu numai ca nu este necesar dupa instructiune1, ci este interzis sa fie pus acolo. A doua varianta a acestei structuri conditionale este cea in care nu avem ramura de else :
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. If conditie 2. Then instructiune1;

Atentie:In cazul folosirii acestei sintaxe, semnul " ; " (punct si virgula) este strict necesar dupainstructiune1. Sa exemplificam aceste structuri prin programul de mai jos:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var varsta: integer; 2. sex: char;


3. begin

4. 5.
6.

write('Ce varsta aveti ? '); ReadLn(varsta); write('Sunteti baiat sau fata ? (M / F) : '); ReadLn(sex); If (sex = 'f') or (sex = 'F') Then WriteLn('Sex feminin') Else WriteLn('Sex masculin'); If varsta > 17 Then WriteLn('Persoana majora'); ReadLn;

7. 8. 9.

10.

11. 12.

13. 14.

15. End.

Pentru a intelege programul, sa-l luam pas cu pas. Am definit doua variabile, una de tip integer (valoare numerica) denumita varsta si una de tip Char (un singur caracter) denumita sex. Dupa citirea de la tastatura a valorilor pentru aceste doua variabile, verificam daca variabila sex e cumva litera F. De remarcat ca am folosit operatorul logic OR pentru a verifica daca variabila are valoarea f sauF, ambele insemnand faptul ca sexul este feminin, caz in care afisam acest lucru. Pe ramura de Else, stiind ca sexul nu este feminin, am pus direct afisare ca sexul este masculin, ceea ce nu este tocmai corect. Trebuia facuta o verificare si daca valoarea variabilei sex este m sau M, pentru a asigura acuratetea programului. In programul de mai sus, daca pentru variabila sex introducem litera c, progamul va afisa tot "Sex masculin", dar momentan scopul meu nu e de a crea programe fara bug-uri, ci doar de a va explica modul de functionare a structurilor conditionale. Pentru varsta facem o singura verificare, anume daca varsta este strict mai mare decat 17 (adica minim 18), caz in care afisam "Persoana majora". Sa refacem programul pentru a lua in calcul si alte cazuri (cum ar fi verificarea pentru sexul masculin, varste negative sau peste 150 de ani )
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var varsta: integer; 2. sex: char;


3. begin 4. write('Ce varsta aveti ? '); ReadLn(varsta); 5. write('Sunteti baiat sau fata ? (M / F) : '); ReadLn(sex); 6. 7. If (sex = 'f') or (sex = 'F') 8. Then WriteLn ('Sex feminin') 9. Else 10. If (sex = 'm') or (sex = 'M') 11. Then WriteLn ('Sex masculin') 12. Else WriteLn ('Sex necunoscut, probabil neutru'); 13. 14. If (varsta < 0) 15. Then WriteLn ('Persoana care este inca in planuri de viitor') 16. Else 17. If (varsta < 18)

18. 19. 20. 21. 22. 23. 24. 25.


26. 27.

Then WriteLn ('Persoana minora') Else If (varsta < 60) Then WriteLn ('Persoana majora') Else If (varsta < 150) Then WriteLn ('Persoana in varsta') Else WriteLn ('Personaj biblic'); ReadLn;

28. End.

Dupa cum vedeti, in noul program am luat in calcul ca variabila sex poate reprezenta sex feminin, sex masculin sau un caracter care nu reprezinta nici unul din acestea doua cazuri. Pentru aceasta, am folosit instructiuni conditionale imbricate (adica una in interiorul alteia). Arata urat, nu ? In plus, e si destul de greu de inteles. Cu toate acestea, pentru variabila varsta am facut chiar si mai multe verificari, folosind multiple instructiuni conditionale imbricate. E deja mai urat si chiar si mai greu de inteles. Nu am de facut decat sa va recomand multa atentie cand creati sau recititi programul ... si sa va prezint instructiunea conditionala multipla, ca o alternativa la instructiunea If ... Then ... [Else ... ] Structura Case Instructiunea Case, denumita si instructiune alternativa multipla, ofera posibilitatea verificarii unei variabile pe un set mai intins de valori, fara a da dureri de cap la crearea sau recitirea programului. Sintaxa generala:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Case variabila_simpla Of
2. 3. 4. 5. val_posibile1 : instructiune1; val_posibile2 : instructiune2; ... val_posibileX : instructiuneX; 6. Else instructiuneY; 7. End; Sa incercam sa intelegem aceasta sintaxa, care pare a fi ceva mai complicata decat sintaxa instructiunii dinainte. Variabila_simpla desemneaza orice variabila de un tip simplu de date (vedeti tutorialul anterior). Nu poate fi folosit aici, de exemplu, tipul String, el nefiind un tip simplu de date. Val_posibile1, Val_posibile2 si Val_posibileX tin locul unei (sau a mai multor) valori posibile pentruvariabila_simpla. Daca valoarea variabilei variabila_simpla e egala (sau inclusa) cu vreuna din valorile posibile, atunci va fi executat setul corespunzator de instructiuni. Instructiune1, instructiune2 si instructiuneX pot fi orice fel de instructiuni, inclusiv cele compuse. Pe ramura de Else avem acelasi lucru ca si la instructiunea If ... Then ... [Else ... ], adica o anumita instructiune care se executa in cazul in care valoarea variabilei variabila_simpla nu se regaseste in optiunile de mai sus (Val_posibile1, Val_posibile2, Val_posibileX). Aceasta ramura, ca si la If ... Then ... [Else ... ], poate ramane nefolosita.

Sa refacem programul de mai sus, folosind aceasta noua instructiune.


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var varsta: integer; 2. sex: char;


3. begin 4. write('Ce varsta aveti ? '); ReadLn(varsta); 5. write('Sunteti baiat sau fata ? (M / F) : '); ReadLn(sex); 6. 7. Case sex Of 8. 'f','F' : WriteLn('Sex feminin'); 9. 'm','M' : WriteLn('Sex masculin'); 10. Else Writeln('Sex necunoscut, probabil neutru'); 11. End; 12. 13. Case varsta Of 14. 0 .. 17 : WriteLn('Persoana minora'); 15. 18 .. 60 : WriteLn('Persoana majora'); 16. 61 .. 150 : WriteLn('Persoana in varsta'); 17. 151 .. maxint : WriteLn('Personaj biblic'); 18. -maxint .. -1 : WriteLn('Persoana care este inca in planuri de viitor'); 19. End; 20. 21. ReadLn; 22. End. Dupa cum vedeti, e mult mai usor de folosit si este mult mai clara. Singurul lucru care cred ca mai e necesar sa vi-l explic este ce inseamna, 'f','F' si 18 .. 60. Structura Case, dupa cum am explicat anterior, permite ca, pentru o anumita instructiune, sa verificam mai multe valori posibile. Aceste valori pot fi scrise una cate una si despartite prin virgula (cum a fost in cazul variabilei sex) sau pot fi scrise ca un sir de valori, in care se ofera valoarea minima si apoi valoarea maxima, aceste doua valori fiind despartite prin " .. " (doua puncte unul dupa celalalt). Cam asta ar fi toata partea de instructiuni conditionale in Pascal. Sa trecem la ... Bucle (instructiuni repetitive) Buclele (instructiuni de ciclare) sunt niste instructiuni care asigura repetarea pe un anumit numar de pasi a unor anumite instructiuni. Sa ne imaginam ca vrem sa facem un program care sa afiseze crescator, de la 1 la 20, toate numerele. E destul de simplu sa le afisam cu o instructiune Write (sau mai multe). Dar sa presupunem ca vrem sa facem acelasi lucru pana la 1.000 ... sau pana la 1.000.000 ... cred ca sunteti de acord ca ar fi "cam" mult de lucru. Aici apare nevoia de bucla, pentru a repeta un set de instructiuni de un numar dat de ori.

In Pascal, sunt trei tipuri de instructiuni de ciclare: While Repeat For Bucla While Sintaxa generala a acestei instructiuni este:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. While conditie Do instructiune;


Conditie poate fi orice comparatie sau orice altceva ce are ca rezultat True sau False. Se poate apela si
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. While True Do instructiune; , caz in care nu se poate iesi din bucla din cauza conditiei. Daca nu exista in interiorul acestei bucle o instructiune de iesire (Break), atunci bucla va fi infinita (nu va mai iesi din ea, programul se va bloca si va trebui terminat cu Ctrl + Break, sau si mai rau, din Task Manager sau reboot). In general, conditia va face referire la o conditie care va deveni adevarata, pe masura bucla lucreaza sau este o simpla verificare a unui contor, caz in care putem calcula dinainte exact cate ciclari va face bucla (de cate ori va repeta instructiunile aflate in interior).
De remarcat ca iesirea din bucla se va face doar cand conditia va returna valoarea False. E si destul de usor de inteles asta : While conditie Do instructiune care in limbaj natural ar suna Cat timp conditia_mea_e_adevarata Fa ceva. Aceasta instructiune mai este denumita si "instructiune repetitiva cu test initial" (testul de iesire din bucla se face la inceput). Instructiunile din aceasta bucla nu se vor executa nici macar o data, daca testul de iesire returneaza valoarea False de la inceput. Instructiune poate fi orice fel de instructiune, inclusiv instructiunea compusa. Sa vedem cum am putea face in Pascal, folosind bucla While, programul de mai sus care afiseaza pana la 20.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. cnt := 1; 4. While cnt <= 20 Do 5. Begin 6. WriteLn(cnt); 7. cnt := cnt + 1; 8. End; 9. ReadLn; 10. end. Sa analizam programul. Prima oara am declarat o variabila de tip integer (care poate lua valori intre

-32768 si 32767), care va fi ceea ce denumim contorul buclei. Initializam contorul cu 1, aceasta fiind prima valoare ce va trebui afisata, apoi afisam contorul, care apoi va fi marit cu o unitate. Pe masura ce avansam, ajungem cu Cnt = 20. Ce se va intampla atunci : va fi afisat (20), contorul va fi crescut la 21 si programul va reveni la conditia de la inceputul buclei : este Cnt mai mic sau egal cu 20 ? Evident, nu mai este cazul, motiv pentru care se trece la executarea urmatoarei instructiuni din program, anume ReadLn. Sa vedem cum am putea face programul daca am initializa Cnt cu valoarea 0.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. cnt := 0; 4. While cnt < 20 Do 5. Begin 6. cnt := cnt + 1; 7. WriteLn(cnt); 8. End; 9. ReadLn; 10. end. Ok, ar trebui sa fie evident. Tot ce am facut a fost sa: schimb conditia de iesire din bucla, din <= in simplul < inversez instructiunea de crestere a contorului cu cea de afisare De ce am facut asta ? In primul rand, trebuia sa inversam instructiunile, fiindca altfel ar fi inceput afisarea cu 0, nu cu 1, cum se cerea. Cealalta modificare se refera la faptul ca in momentul care am afisat 20, trebuie iesit din bucla. Inca un ciclu (determinat de o conditie cnt <= 20 ar rezulta in afisarea lui 21, lucru pe care iar nu-l vrem.

Cred ca acum ati inteles cum sta treaba cu While, so ... next one Bucla Repeat Sintaxa general a instructiunii Repeat este:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Repeat 2. instructiune; 3. until conditie; Spre deosebire de While, iesirea din aceasta bucla se face atunci cand valoarea conditiei este True. Pentru o bucla infinita se va folosi:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Repeat 2. instructiune; 3. until False; De remarcat ca instructiune nu e necesar sa fie instructiune compusa. Cu alte cuvinte, nu este necesar

sa puneti Begin ... End pentru a delimita bucla, acest lucru fiind facut de Repeat ... Until. Aceasta instructiune mai este denumita si "instructiune repetitiva cu test final" (testul de iesire din bucla se face la sfarsit). Instructiunile din aceasta bucla se vor executa macar o data, daca testul de iesire returneaza valoarea True la prima testare. Sa rescriem programul initial folosind aceasta instructiune.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. cnt := 1; 4. Repeat 5. WriteLn(cnt); 6. cnt := cnt + 1; 7. Until cnt > 20; 8. ReadLn; 9. end. De remarcat conditia de iesire din bucla, care este exact opusul celei folosite in cazul buclei While (desi e destul de simplu de inteles, avand in vedere motivele terminarii fiecarei bucle). Singurul lucru care il am de adaugat (fiindca e destul de usor de inteles, avand in vedere explicatiile anterioare) e faptul ca dupa ce cnt are valoarea 20 si este afisat, va fi crescut cu 1 (devenind 21), caz in care conditia devine adevarata (cnt > 20), motiv pentru care se iese din bucla. Daca am initializa contorul cu 0, programul ar fi asa:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. cnt := 0; 4. Repeat 5. cnt := cnt + 1; 6. WriteLn(cnt); 7. Until cnt >= 20; 8. ReadLn; 9. End. Din nou, avem conditia de la While, dar inversata. Cam asta ar fi si Repeat-ul ... easy, nu ? Atentie:Inversa conditiei > este <=, iar a conditiei < este >=. Bucla For Sintaxa generala la For cunoaste 2 cazuri: crescator sau descrescator. Cazul crescator:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. For contor = val_initiala To val_finala Do instructiune;


Cazul descrescator:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. For contor = val_initiala DownTo val_finala Do instructiune;


Motivul pentru care avem aceasta distinctie e faptul ca nu mai avem direct controlul asupra contorului buclei, acesta fiind crescut / scazut de bucla, scapandu-ne astfel de o grija. Din pacate, in felul acesta nu putem decat sa mergem cu pasi de cate o unitate (crescator sau descrescator). In cazurile While sau Repeat, puteam creste contorul cu cat vroiam noi (am ales sa-l cresc cu 1 doar pentru exemplificare). Dupa cum ati observat, aici nu mai avem nici o conditie de iesire din bucla. Iesirea din aceasta bucla se face in momentul in care val_initiala devine mai mare / mai mica cu o unitate decat val_finala. De asemenea, daca se foloseste sintaxa cu To se sare peste bucla in cazul in care val_initiala este mai mare decat val_finala si invers. De remarcat e faptul ca nu mai trebuie sa initializam contorul inaintea buclei (il initializam, de fapt, direct in bucla). Programul de mai sus, scris cu o bucla For ar arata in felul urmator:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. For cnt := 1 To 20 Do 4. WriteLn(cnt); 5. ReadLn; 6. End. Dupa cum vedeti, contorul nu prea mai e in grija noastra (iar unele compilatoare chiar dau eroare daca veti incerca sa-i modificati valoarea in interiorul buclei).

Sa incercam acum sa lucram cu varianta descrescatoare pentru a face acelasi program


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. For cnt := 20 DownTo 1 Do 4. WriteLn(20 - cnt + 1); 5. ReadLn; 6. End. Ok, programul merge ... dar de ce am pus formula aceea ciudata acolo ? Trebuie sa tineti cont de faptul ca acum contorul merge de la 20, descrescator, spre 1, exact invers de cum ne-am obisnuit, asa ca prima valoare a lui cnt este 20. Pentru prima afisare, daca scadem 20 din 20 si adaugam 1 (ca in formula), ne da 1, exact ce trebuie afisat. Sa incercam pentru cazul in care cnt este 2 ... 20 - 2 + 1 = 19, deci asta e penultimul numar care va fi afisat, ultimul fiind, evident, 20.

Instructiuni de control pentru bucle Instructiunea Continue Sa presupunem ca avem o bucla care afiseaza numerele de la 1 la 20, ca si in exemplele de mai sus, dar nu vrem sa afisam numarul 9. Cum putem face acest lucru ? Foarte simplu. Trebuie sa "sarim" peste o executie a buclei, cea in care indexul are valoarea 9, inainte de a afisa numarul. Pentru acest lucru folosim instructiunea Continue. Sa vedem un exemplu, folosind bucla FOR:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt : integer;


2. begin 3. For cnt := 1 To 20 Do 4. begin 5. if cnt = 9 then 6. Continue; {daca instructiunea de afisare} 7. WriteLn(cnt); 8. end; 9. ReadLn; 10. End.

indexul

este

egal

cu

9,

nu

executam

Instructiunea Continue sare la urmatorul ciclu al buclei, indiferent ca e vorba de bucla While, Repeat sau For. Instructiunea Break Ce facem daca avem nevoie sa scriem un program care afiseaza numerele de la 1 la 20, dar numai atat timp cat suma numerelor afisate este mai mica decat 35 ? Pentru acest lucru trebuie sa facem o suma, pe care o crestem cu valoarea indexului la fiecare afisare. Aceasta suma o vom verifica inainte de urmatoarea afisare si, daca este mai mai mare sau egala cu 35, folosim instructiunea Break. Sa modificam programul de mai sus pentru un mic exemplu:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var cnt, suma : integer;


2. begin 3. suma := 0; 4. For cnt := 1 To 20 Do 5. begin 6. suma := suma + cnt; 7. if suma >= 35 then 8. Break; {iesim din bucla} 9. WriteLn(cnt); 10. end;

11.

12. End.

ReadLn;

Acest program va afisa numerele de la 1 la 7, inclusiv, fiindca 1 + 2 + ... + 8 = 36. Instructiunea Break opreste bucla din care este apelata. dar nu poate opri decat o singura bucla. Daca aceasta instructiune este folosita in interiorul unei bucle care este imbricata in alta bucla, doar bucla interioara va fi oprita.

Vectori (tablouri, matrici)


Probabil ca acum, dupa ce ati parcurs primele 3 tutoriale de Pascal de pe aici, stiti sa faceti suma a doua numere, citite de la tastatura. Probabil ca vi se pare chiar usor. Sa zicem ca vreau sa-mi si afisati cele doua numere dupa ce-ati afisat suma. Nimic iesit din comun. Ce-ati zice daca v-as cere un program care sa faca suma a trei numere ? E posibil sa nu va deranjeze prea tare ... nu e mare lucru sa adaugi o variabila, sa-i citesti valoarea de la tastatura si sa o aduni la suma. Chiar si afisarea celor trei numere nu ar trebui sa dea batai de cap nimanui. Ce-ati zice daca v-as cere un program care face suma a 1000 de numere, afisand apoi fiecare numar introdus de la tastatura ? E clar, e momentul pentru un alt tip de date, unul structurat, capabil sa tina in memorie siruri de date. Primul tip de date structurat care l-am prezentat in Tipuri de date in Pascal este tipul tablou. Pentru acest tip de date se folosesc mai multe sinonime, cum ar fi vector, matrice sau englezismul array. Toate se refera la acelasi lucru. Sa incepem cu inceputul. Vectori unidimensionali Ca sa putem folosi acest nou tip de date, trebuie sa-l declaram. Modalitatea de declarare a unui vectorunidimensional cu capacitatea de 1000 de numere intregi (pe 2 bytes, in acest caz) este urmatoarea:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. sir : array [1 .. 1000] of Integer;

So, punem cuvantul cheie "array", punem indexul de inceput al sirului (poate fi si -17 ), punem ".." pentru a specifica faptul ca e vorba de un interval, punem indexul de sfarsit (1000 in exemplul de mai sus), adaugam cuvantul cheie "of" (asa-i romanul, plin de ofuri face parte din vector ... si nimic mai mai mult. Exemple
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

), specificam tipul datelor care vor

1. var test: array [65 .. 122] of char; 2. test2: array ['H' .. 'a'] of boolean;

Nu va speriati, si varianta in care am pus litere pe post de indecsi e functionala. Rar folosita, dar posibila. Deci ... un vector de caractere (cu indecsi intre 65 si 122 ... si un vector de valori logice, intre 'H' si 'a' ... adica un vector cu 25 de pozitii). Cum se spune, nimic mai simplu. Avem variabila sir care are 1000 de pozitii si imi permite sa salvez cate un numar pe fiecare dintre aceste pozitii. Singura (posibila) problema este faptul ca nu putem salva decatnumere intregi in acest sir. Elementele unui vector trebuie sa aiba acelasi tip. Nu se pot defini vectori ale caror elemente sa fie fisiere. Modalitatea de accesare a unei anumite pozitii din sir se face scriind numele sirului (sir in cazul acesta) si, intre paranteze drepte, [ si ], indicele (pozitia) din sir care o dorim.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. sir[17] := 2342;
In acest fel, fiecare pozitie a vectorului poate fi privita ca o variabila de sine statatoare, scrisa putin mai ciudat. Atentie: Nu confundati pozitia unui element din vector cu valoarea lui. Daca am valorile urmatoare in vector (in ordine): 159, 65, 78, 23, 72, 34 ... atunci elementul de pe pozitia3 are valoarea 78. Atentie maxima, am vazut multe aiureli cauzate de confuzii de acest gen. Alta problema destul de comuna este incercarea de a folosi vectori care ocupa mai mult decat capacitatea de memorie alocata de catre Pascal. Aceste incercari vor determina compilatorul de Borland Pascal 7.0 sa genereze o eroare de compilare cu mesajul "Structure too large". Compilatorul de Borland Pascal 7.0 ofera un spatiu de memorie de maxim 64KB per fisier al programului (momentan, un singur fisier). Exista alte compilatoare care ofera mult mai mult si care, evident, nu dau asemenea erori. Stiind ca un element al unui vector este apelat folosind indexul lui, devine deja clar ca putem folosi bucle pentru lucrul cu vectori. Hai sa vedem cum citim 1000 de numere, folosind vectori si o bucla For (daca nu mai stiti ce e o bucla For, Instructiuni repetitive va mananca ).
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var sir : array [1 .. 1000] of Integer; 3. i, n: Integer;


4. begin 5. Write('Dati numarul de valori care doriti sa le introduceti: '); 6. ReadLn(n); 7. 8. For i := 1 To n Do {citim toate elementele de la tastatura ...} 9. begin

10. 11. 12.


13. 14.

Write('Dati elementul ', i : 4, ' : '); ReadLn(sir[i]); {... si le salvam in vector} end; ClrScr; {afisam elementele citite de la tastatura}

15. 16.

For i := 1 To n Do Write(sir[i]:8); 17. ReadLn; 18. end.

Pentru amuzament, hai sa dam valorile elementelor din vector in felul urmator: pe o pozitie sa fie valoarea 1, pe urmatoarea sa fie valoarea 0, pe urmatoarea pozitie iar 1, and so on.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var sir : array [1 .. 1000] of Integer; 3. i, n: Integer;


4. begin 5. Write('Dati numarul de valori care doriti sa le introduceti: '); 6. ReadLn(n); 7. 8. For i := 1 to n Do {aici se pune 1, 0, 1, 0, 1 ...} 9. sir[i] := i mod 2; {simplu, nu ?} 10. 11. For i := 1 To n Do {afisam elementele} 12. Write(sir[i]:8); 13. ReadLn; 14. end. Cam asta ar fi ce este de explicat la vectorii unidimensionali, acum puneti-va centura de siguranta pentru ... Vectori multidimensionali Care-i problema cu vectorii astia ? De ce nu pot fi toti la fel ? De ce ne trebuie vectori unidimensionali, si bidimensionali, si tridimensionali, si dimensionali intr-o dimensiune pe care nu o pot vizualiza ... ?

Raspunsul e simplu: nu stiu Vectorii unidimensionali, intr-un mod cat se poate de evident, aveau o singura dimensiune, lungime, care era definita de numarul de elemente din ei. Hai sa ne imaginam vectorul unidimensional ca pe o linie din foaia de matematica: un sir de casute, nu ? Fiecare casuta accepta o cifra (sau, daca scrii ca mine, trei ), deci fiecare element e de acelasi tip.

Totusi, foaia de matematica are doua dimensiuni, lungime si latime. E un tabel. Cum definesti un vector unidimensional in asa fel incat sa-l poti folosi ca pe un tabel ? Nu o faci. Folosesti un vector bidimensional, care este chiar un tabel, nu ?

P.S. ca informatie relativ utila, vectorii unidimensionali pot fi folositi ca vectori multidimensionali. Memoria video este vazuta, practic, ca un vector unidimensional, dar noi o vedem bidimensional. Asta va spune ceva ?

Hai sa vedem cum definim un vector bidimensional, fiindca sunt sigur ca nici nu va trece prin cap
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. tabel = array [1.. 10, 1 .. 20] of integer; Asemanator cu vectorii unidimensionali, nu ? Primul set (1 .. 10) determina numarul de linii, iar al doilea numarul de (20 de) coloane. Accesul la elementul de pe o anumita pozitie necesita acum doi indecsi, ceea ce e normal:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. tabel[2, 5] := 124; Codul acesta poate fi citit in felul urmator: elementul de pe linia 2, coloana 5 din matricea denumita "tabel" va lua valoarea 124. Hai sa facem o tabla de sah (de 8x8) si sa o umplem, ca si in exemplul de mai sus, cu 1 si 0.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var sir : array [1 .. 1000] of Integer; 3. tabla: array [1 .. 8, 1 .. 8] of byte; 4. i,j, n: Integer;
5. begin 6. for i := 1 to 8 do 7. for j := 1 to 8 do 8. tabla[i, j] := (i + j) mod 2; 9. 10. for i := 1 to 8 do 11. begin 12. for j := 1 to 8 do 13. write(tabla[i,j]:2); 14. writeln; 15. end; 16. end. Rezultatul acestei bucati de cod poate fi admirat in imaginea urmatoare:

So, cam asta ar fi si cu vectorii bidimensionali (matrice) ... cred ca v-am speriat degeaba sa va dati jos centura de siguranta.

... puteti

Vectorii cu mai mult de 2 dimensiuni se declara la fel (cu modificarile de rigoare), iar elementele din asemenea vectori sunt folositi la fel (din nou, cu modificarile de rigoare). Atentie: Indiferent de numarul de dimensiuni al vectorului, indiferent de numarul de elemente pe care le contine, aveti grija sa nu incercati sa accesati pozitii care nu exista (cum ar fi pozitia 1001 sau 2000 in vectorul cu 1000 de elemente). In cel mai bun caz, valoarea citita de acolo va fi aleatoare. In cel mai rau caz veti primi un AV (access violation pentru necunoscatori) sau vreo eroare de rulare (runtime error). Matrici patratice Matricile patratice sunt acei vectori bidimensionali a caror numar de linii este egal cu numarul de coloane. La acest tip de matrice putem vedea niste lucruri interesante, cum ar fi faptul ca numarul de elemente este egal cu latura2 (clar, nu?) ... sau ca are diagonale. Prin faptul ca are diagonale ma refer ca exista o serie de elemente ale matricii care determina respectivele diagonale. Diagonalele unei matrici patratice sunt denumite: diagonala principala si diagonala secundara. Diagonala principala porneste din coltul din stanga sus si se termina in coltul din dreapta jos. Diagonala secundara incepe in coltul din dreapta sus si se termina in coltul din stanga jos. In urmatoarea imagine puteti vedea rezultatul unui program care identifica elementele celor doua diagonale ale unei matrici patratice de 8x8. Diagonala principala este afisata cu rosu, iar cea secundara cu galben.

Codul programului care a scos acest rezultat este:


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var tabla: array [1 .. 8, 1 .. 8] of byte; 3. i, j: Integer;


4. begin 5. clrscr; 6. for i := 1 to 8 do 7. for j := 1 to 8 do 8. tabla[i, j] := (i + j + 1) mod 2; 9. 10. for i := 1 to 8 do begin 11. for j := 1 to 8 do 12. begin 13. textcolor(LightGray); 14. 15. if (i = j) then 16. TextColor(LightRed); {diagonala principala} 17. if (i = 8 - j + 1) then 18. TextColor(Yellow); {diagonala secundara} 19. 20. write(tabla[i,j]:2); 21. end; 22. writeln; 23. end; 24. 25. ReadLn; 26. end. Daca ati analizat putin codul, ar trebui sa va fie clar ca un element din matrice face parte din diagonala: principala, daca indecsii au aceeasi valoare (i = j) secundara, daca indecsii se supun formulei urmatoare: i = n - j + 1, unde i, j sunt indecsii de linie, respectiv coloana, iar n este latura matricii patratice. Daca nu ati inteles de ce, luati o foaie si un pix (sau creion sau orice care lasa semne pe hartie) si

verificati formulele Hai sa vedem cum aflam elementele din sectiuni demarcate de diagonale. Aici, cu albastru, elementele de deasupra diagonalei principale.

Codul necesar:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var tabla: array [1 .. 8, 1 .. 8] of byte; 3. i, j: Integer;


4. begin 5. clrscr; 6. for i := 1 to 8 do 7. for j := 1 to 8 do 8. tabla[i, j] := (i + j + 1) mod 2; 9. 10. for i := 1 to 8 do begin 11. for j := 1 to 8 do 12. begin 13. textcolor(LightGray); 14. 15. if (i = j) then {diagonala principala} 16. TextColor(LightRed); 17. 18. if (i = 8 - j + 1) then {diagonala secundara} 19. TextColor(Yellow); 20. 21. if (j > i) then {deasupra diagonalei principale} 22. TextColor(LightBlue); 23. 24. write(tabla[i,j]:2); 25. end; 26. writeln; 27. end; 28. 29. ReadLn;

30. end.
Dupa cum se vede, elementele de deasupra diagonalei principale au proprietatea ca indexul coloanei (j) este mai mare decat indexul liniei (i). Simplu. Tot cu albastru, elementele de sub cele doua diagonale:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var tabla: array [1 .. 8, 1 .. 8] of byte; 3. i, j: Integer;


4. begin 5. clrscr; 6. for i := 1 to 8 do 7. for j := 1 to 8 do 8. tabla[i, j] := (i + j + 1) mod 2; 9. 10. for i := 1 to 8 do begin 11. for j := 1 to 8 do 12. begin 13. textcolor(LightGray); 14. 15. if (i = j) then {diagonala principala} 16. TextColor(LightRed); 17. 18. if (i = 8 - j + 1) then {diagonala secundara} 19. TextColor(Yellow); 20. 21. if (i > j) and (i > 8 - j + 1) then {sub cele doua diagonale} 22. TextColor(LightBlue); 23. 24. write(tabla[i,j]:2); 25. end; 26. writeln; 27. end; 28. 29. ReadLn; 30. end.

Proprietatea elementelor cu albastru este ca indicele liniei este mai mare decat indicele liniei SI este sub diagonala secundara (adica indexul de linie este mai mare decat numarul de linii, din care scadem indexul coloanei si adunam 1). Restul sectiunilor si subsectiunilor determinate de diagonale le puteti afla si singuri, modificand programele de mai sus.

Subprograme (proceduri si functii)


Vi s-a intamplat sa aveti nevoie sa faceti un program si sa fie nevoie sa repetati o secventa de cod in mai multe locuri din program ? Probabil ca da, posibil ca nu. Vi s-a intamplat sa aveti nevoie sa va ordonati codul in alt fel decat insiruirea liniilor una dupa alta, sa zicem ... dupa functionalitate ? Pentru a usura aceste lucruri, Pascal ofera subprogramele: proceduri si functii. Pe scurt, acestea sunt parti de program care pot fi folosite apeland numele lor.

Proceduri
Sa vedem cum arata o structura generala a unei proceduri:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. procedure nume_procedura [(lista_parametri)];


2. 3. CONST 4. (* declaratii de constante *) 5. 6. VAR 7. (* declaratii de variabile *) 8. 9. BEGIN 10. (* instructiuni *) 11. END;

De remarcat ca, spre deosebire de structura unui program, end-ul de la sfarsit este finalizat cu ; (punct si virgula), nu cu . (punct). Lista de parametri este optionala, motiv pentru care este incadrata intre paranteze drepte. Ce inseamna parametri va fi explicat putin mai tarziu. Sa vedem un program obisnuit folosind proceduri. Programul original (fara proceduri) ar fi urmatorul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var vector : array[1..200] of integer; 2. i, n: integer;


3. begin 4. Write('Dati N: '); ReadLn(n); {N = numarul de elemente} 5.

6. 7. 8. 9. 10. 11. 12.


13.

i := 1; {*} while (i <= N) do {citim elementele} begin Write('Dati elementul ', i, ': '); ReadLn(vector[i]); i := i + 1; end; i := 1; {*} while (i <= N) do {impartim fiecare element la 2 si salvam catul} begin vector[i] := vector[i] div 2; i := i + 1; end; Write('Vectorul modificat este : '); i := 1; {*} while (i <= N) do {afisam noile valori din vector} begin Write(vector[i] : 5); i := i + 1; end;

14. 15. 16. 17. 18. 19. 21. 23. 24. 25. 26. 27. 28.

20. 22.

29.

30. ReadLn; {asteptam sa fie apasat Enter} 31. end.

Vedeti secventele marcate cu {*} ? Aceeasi instructiune, repetata de 3 ori... Bineinteles, intr-un program mai mare si mai stufos, secventele care se repeta contin mai multe instructiuni ... si probabil se repeta de mai multe ori. Sa vedem cum rescriem programul folosind o procedura care sa faca acelasi lucru (sa initializeze variabila icu 1).
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var vector : array[1..200] of integer; 2. i, n: integer;


3.

4. 5. 6. 7.

procedure Init; begin i := 1; end;

8. 9. begin 10. Write('Dati N: '); ReadLn(n); {N = numarul de elemente} 11. 12. Init; {*} 13. while (i <= N) do {citim elementele} 14. begin

15. 16. 17. 18.


19.

Write('Dati elementul ', i, ': '); ReadLn(vector[i]); i := i + 1; end; Init; {*} while (i <= N) do {impartim fiecare element la 2 si salvam catul} begin vector[i] := vector[i] div 2; i := i + 1; end; Write('Vectorul modificat este : '); Init; {*} while (i <= N) do {afisam noile valori din vector} begin Write(vector[i] : 5); i := i + 1; end;

20. 21. 22. 23. 24. 25. 27. 29. 30. 31. 32. 33. 34.

26. 28.

35.

36. ReadLn; {asteptam sa fie apasat Enter} 37. end.

Probabil ca acum va ganditi "Ce mare branza a rezolvat ? Numarul de linii este acum mai mare !". Da, asa e, dar asa cum am mentionat, acest program este doar un exemplu simplist. In acest caz, variabila i este o variabila globala. Nu e declarata in niciun subprogram, ci direct in programul principal. Procedura Init o poate folosi fiindca variabila a fost declarata inaintea procedurii (daca erau declarate invers, compilatorul ar fi dat eroare spunand ca variabila folosita in procedura nu poate fi gasita). Variabilele declarate in interiorul unui subprogram se numesc variabile locale. Atentie: Variabilele globale si locale pot avea acelasi nume, lucru care poate duce la probleme in program. Sa vedem un alt program care foloseste o procedura pentru a calcula factorialul unui numar (pentru cei care nu stiu, factorialul unui numar N este produsul lui 1 x 2 x ... x N).
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var i, n, f: integer;
2.

3. 4. 5. 7.

procedure Fact; begin f := 1; for i := 1 to n do

6.

8.

9.

f := f * i; end;

10. 11.begin 12. Write('Dati N: '); ReadLn(n); 13. 14. Fact; 15. Write('Factorial de N este egal cu : ', f); 16. 17. ReadLn; {asteptam sa fie apasat Enter} 18. end.

Destul de clar, cred. Sa trecem la ...

Functii
Functiile sunt foarte asemanatoare procedurilor, singura diferenta fiind faptul ca functiile pot intoarce un rezultat. Sa vedem cum arata o structura generala a unei functii:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. function nume_functie [(lista_parametri)] : tip_rezultat;


2. 3. CONST 4. (* declaratii de constante *) 5. 6. VAR 7. (* declaratii de variabile *) 8. 9. BEGIN 10. (* instructiuni *) 11. END;

Haideti sa vedem cum ar putea arata un program care calculeaza factorialul unui numar, folosind o functie de data asta:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var i, n, f: integer;
2.

3. 4. 5. 6. 8.

function Fact: Longint; var lFact: Longint; {variabila locala} begin lFact := 1; for i := 1 to n do lFact := lFact * i;

7. 9. 10.

11. 12.

Fact := lFact; {am asignat rezultatul in numele functiei !} end;

13. 14.begin 15. Write('Dati N: '); ReadLn(n); 16. 17. F := Fact; 18. Write('Factorial de N este egal cu : ', f); 19. 20. ReadLn; {asteptam sa fie apasat Enter} 21. end.

De data asta am asignat variabila F din afara subprogramului, si i-am dat valoarea rezultata din functie. Rezultatul functiei a fost setat asignand valoarea respectiva numelui functiei, in interiorul functiei. Alta modificare este faptul ca folosim o variabila locala pentru a calcula factorialul. Acest lucru nu este strict necesar, l-am facut doar pentru a exemplifica rolul variabilelor locale.

Parametri
Sa vedem ce sunt parametrii si cum ii folosim in subprograme. Lista de parametri este scrisa, practic, ca o lista de variabile. Parametrii pot fi scrisi in orice ordine sau pot fi grupati dupa tipul variabilelor. Parametrii pot fi de doua tipuri, prin modul in care sunt folositi: parametri prin valoare - acesti parametri pot fi modificati in interiorul subprogramului, dar modificarile nu sunt vizibile in exteriorul subprogramului. parametri prin adresa - acesti parametri sunt, de fapt, adresele de memorie ale unor variabile deja declarate. Modificarile aduse unor astfel de parametri in interiorul unui subprogram vor fi vizibile in exterior.

Teoria ca teoria, dar hai sa vedem niste exemple


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var i, n, f: integer;
2.

3.

function Fact(X: Integer): Longint; {X prin valoare} 4. var lFact: Longint; {variabila locala} 5. begin 6. lFact := 1; 7. 8. for i := 1 to X do 9. lFact := lFact * i;

este

un

parametru

transmis

10.

11. 12. 13.

X := -1; Fact := lFact; {am asignat rezultatul in numele functiei !} end;

14. 15.begin 16. Write('Dati N: '); ReadLn(n); 17. 18. F := Fact(N); 19. WriteLn('Factorial de N este egal cu : ', f); 20. WriteLn('Noua valoare a lui N este : ', n); 21. 22. ReadLn; {asteptam sa fie apasat Enter} 23. end. Bun. Am calculat din nou factorialul, dar, de data aceasta, functia noastra Fact a primit un parametru prin valoare, pe care-l foloseste sa calculeze factorialul. Pe scurt, o data intrati in corpul functiei (care este apelata ca Fact(N), X este egal cu N. Ce vreau sa remarcati este faptul ca, desi am dat o noua valoare lui X in interiorul functiei, aceasta nu este transmisa inapoi lui N, dovada fiind faptul ca noua valoare a lui N (care este afisata) este aceeasi cu cea introdusa de la tastatura. Din punctul de vedere al functiei si al metodei de lucru, admitand ca valoarea lui N era egala cu 5, puteam apela Fact(5). Numele generic al parametrului ("prin valoare") este dat tocmai din acest motiv: indiferent ca functia este apelata cu o constanta sau o variabila, doar valoarea ei este transmisa. Sa vedem acelasi cod, singura diferenta fiind ca acum folosim un parametru prin adresa.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var i, n, f: integer;
2.

3.

function Fact(var X: Integer): Longint; {X este un parametru transmis prin adresa} 4. var lFact: Longint; {variabila locala} 5. begin 6. lFact := 1; 7. 8. for i := 1 to X do 9. lFact := lFact * i; 10. 11. X := -1; 12. Fact := lFact; {am asignat rezultatul in numele functiei !} 13. end; 14. 15.begin 16. Write('Dati N: '); ReadLn(n); 17. 18. F := Fact(N); 19. WriteLn('Factorial de N este egal cu : ', f); 20. WriteLn('Noua valoare a lui N este : ', n); 21.

22. ReadLn; {asteptam sa fie apasat Enter} 23. end.

Faptul ca parametrul este transmis prin adresa este simbolizat de cuvantul var care-l precede. Programul afiseaza noua valoare a lui N, asa cum era de asteptat, egala cu -1, dovada ca variabila N a fost modificata in functie. Diferenta principala intre parametrii transmisi prin valoare si cei transmisi prin adresa este faptul ca, in cazul celor transmisi prin valoare, variabila trimisa ca parametru este copiata intr-o zona de memorie temporara si trimisa functiei, ca si copie, in timp ce in cazul celor transmisi prin adresa variabila trimisa ajunge in functie neschimbata, ca original. Din acest motiv, transmiterea parametrilor prin adresa poate rapidiza executia programului (totusi, sa nu va asteptati la minuni vorbim de milisecunde si chiar mai putin). Atentie: Un subprogram poate avea o lista de parametri micsti: o parte dintre ei sa fie trimisi prin valoare, iar altii prin adresa. Tot ce conteaza este modul de declarare al listei. De remarcat ca parametrii listati in headerul subprogramului se numesc parametri formali (X este un parametru formal in programul de mai sus), care sunt inlocuiti de parametri efectivi, in momentul apelului subprogramului (N este un parametru efectiv in programul de mai sus). Atentie: Numarul, tipul si ordinea parametrilor efectivi trebuie sa corespunda cu numarul, tipul si ordinea parametrilor formali !

Vizibilitatea variabilelor
Dupa cum am explicat mai sus, se pot declara variabile in interiorul subprogramelor, chiar si cu nume de variabile care exista deja definite in programul principal. Problema care se ridica este urmatoarea : de unde stie compilatorul (si implicit, programatorul) care variabila va fi folosita in anumite zone ale programului ? Nu trebuie sa va speriati, este foarte simplu si usor de inteles. Variabilele globale ale programului sunt vizibile oriunde in program. Daca un subprogram isi defineste o variabila cu acelasi nume, atunci variabila locala e prioritara in acel subprogram (si in posibilele subprograme ale subprogramului !). Sa vedem un exemplu.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. var i, n, f, lFact: integer;


2.

3.

function Fact(X: Integer): Longint; {X prin valoare} 4. var lFact: Longint; {variabila locala} 5. begin

este

un

parametru,

transmis

6. 7.
8.

lFact := 1; WriteLn('lFact local for i := 1 to X do lFact := lFact * i;

= ', lFact);

9.

10. 11.

12. 13. 14.

X := -1; Fact := lFact; {am asignat rezultatul in numele functiei !} end;

15. 16.begin 17. Write('Dati N: '); ReadLn(n); 18. 19. lFact := 157; 20. WriteLn('lFact global = ', lFact); 21. 22. F := Fact(N); 23. WriteLn('Factorial de N este egal cu : ', f); 24. 25. ReadLn; {asteptam sa fie apasat Enter} 26. end.

Acest program va afisa urmatoarele linii (pentru N egal cu 5):


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. 2. 3. 4.

Dati N: 5 lFact global = 157 lFact local = 1 Factorial de N este egal cu : 120

Recursivitate
Un lucru important de stiut, legat de subprograme, este ca ele sunt necesare daca vrem sa folosimrecursivitate. Un subprogram este recursiv daca in implementarea lui se apeleaza pe el insusi. Recursivitatea poate fi un concept destul de greu de inteles, asa ca vom incepe cu un exemplu. Sa vedem cum rescriem functia care calculeaza factorialul, folosind recursivitatea.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. function Fact(X: Integer): Longint;


2. begin 3. if X > 1 4. then Fact := Fact(X - 1) * X 5. else Fact := 1 6. end;

Dupa se poate vedea, recursivitatea permite si formularea mai eleganta a solutiei. Sa incercam sa intelegem ce se intampla. Factorial de N (notat si N!) este definit ca o inmultire succesiva a numerelor de la 1 la N (1 x 2 x ... x N). Din asta putem vedea ca N! este egal cu (N-1)! x N. La randul lui, (N-1)! = (N-2)! x (N-1) si asta poate continua, pana cand N este egal cu 1. Daca incercam sa calculam 1! folosind aceeasi relatie (adica 1! = 0! x 1) o sa cam dam gres, fiindca 0, inmultit cu orice numar, da 0. Pe scurt, daca avem un caz initial caruia ii stim rezultatul, iar restul cazurilor se pot rezolva in functie de cazul initial, problema poate fi rezolvata recursiv. Cazul initial, pe functia de mai sus, este cazul in care X nu este mai mare decat 1 (adica este mai mic sau egal !), acest caz avand rezultatul 1. Pentru orice alta valoare pozitiva a lui X, rezolvarea se face in functie de X-1, pana cand X ajunge in cazul initial. Ca urmare, aceste doua relatii de mai sus: N! = (N-1)! x N 1! = 1 sunt tot ce ne trebuie pentru a ne defini functia recursiva de calculare a factorialului. Sa vedem ce se intampla, pas cu pas, pentru N egal cu 3.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. 2. 3. 4. 5.

Fact(3) X = 3 -> apelam Fact(2) si inmultim cu 3 X = 2 -> apelam Fact(1) si inmultim cu 2 X = 1 -> 1, se termina functia, revenim in apelul precedent Fact = 1, care inmultit cu 2 este egal cu 2, revenim in apelul precedent 6. Fact = 2, care inmultit cu 3 este egal cu 6, se termina functia si revenim in locul unde a fost initial apelata functia.

Deci, daca avem o problema care poate fi exprimata prin subprobleme ale ei si putem gasi o conditie de terminare a apelurilor recursive (in acest caz, X = 1), problema poate fi rezolvata printr-un subprogram recursiv. Atentie: Apelurile recursive consuma relativ multa memorie. Daca o problema poate fi rezolvata iterativ (fara apeluri recursive), e de preferat (in general) ca problema sa fie rezolvata iterativ. O lista prea lunga de apeluri recursive poate genera "stack overflow" si bloca programul / calculatorul. Pentru edificare, atasez acelasi program care calculeaza factorialul, modificat pentru a afisa ce se intampla. Sper sa va fie de ajutor, impreuna cu explicatiile de mai sus. Codul sursa al programului:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt;
2.

3. const lin = 9; 4.

line = '-----------------------------------------------------------------'; 5. Wait = 1000; 6. 7. var i, n, f, lFact, test: longint; 8. 9. function Fact(X: Integer): Longint; {X este un parametru, transmis prin valoare} 10. begin 11. if X > 1 12. then 13. begin 14. WriteLn('Fact(', X, ') = Fact(', X - 1 ,') * ', X); 15. WriteLn(line); 16. Delay(Wait); 17. 18. Fact := Fact(X - 1) * X; 19. Delay(Wait); 20. 21. TextColor(LightGreen); 22. if Test > 0 then 23. Test := Test * X; 24. GotoXY(40, (N - X) * 2 + lin); 25. Write('Fact(', X,') = ', Test); 26. end 27. else 28. begin 29. TextColor(LightRed); 30. WriteLn('X = 1 ' + 31. 'Fact(1) = 1, caz initial !'); 32. TextColor(LightGray); 33. WriteLn(line); 34. Delay(Wait); 35. WriteLn('Functia s-a terminat, revenim din apel ^^^'); 36. Delay(Wait); 37. Fact := 1; 38. Test := 1; 39. end; 40. end; 41. 42.begin 43. test := 0; 44. repeat {verificam daca 1 <= N <= 6} 45. ClrScr; 46. Write('Dati N (maxim 6): '); ReadLn(n); 47. until (N > 0) and (N < 7); 48. ClrScr; 49. 50. TextColor(LightRed);

51. 52. 53.


54.

55. 56. 57. 59. 60. 61. 63. 64. 65. 67. 68. 69. 70. 71. 73. 74.

GotoXY(Length(line) div 2 - 16 ,2); WriteLn('Calculul factorialului - recursiv'); WriteLn(line); WriteLn; TextColor(LightGray); WriteLn('Se apeleaza Fact(', N,') ...'); Delay(Wait); TextColor(lightGray); GotoXY(1, lin); F := Fact(N); Delay(Wait); GotoXY(1, N * 2 + lin + 3); TextColor(LightGray); Write('Fact(', N, ') este egal cu : '); TextColor(LightGreen); WriteLn(f); TextColor(LightGray); Write('... apasa orice tasta pentru a termina programul ...');

58.

62.

66.

72. While Keypressed Do Readkey; {daca s-a apasat o tasta in timp ce programul rula, 75. va astepta totusi apasarea urmatoarei taste} 76. ReadKey; 77. end. Surse si executabil - Download Screenshot din timpul rularii programului:

Lucrul cu fisiere
Toate programele facute pana acum acceptau, ca sursa de date, tastatura, iar ca iesire, monitorul. Cu toate acestea, Pascal permite folosirea fisierelor. Sunt convins ca v-ati intrebat, cel putin o data, de ce jocurile se instaleaza cu o multime de fisiere aditionale, in afara de executabilul propriu-zis. Raspunsul e simplu: resursele respectivului joc se afla in acele fisiere (harti, imagini, sunete, etc). Executabilul jocului citeste si scrie acele fisiere in functie de necesitati (scrie, de exemplu, in fisierul de high-scores). Sa vedem cum putem folosi si noi fisiere, in Pascal. Pentru inceput trebuie sa stiti ca Pascal ofera trei tipuri de fisiere: fisiere text fisiere cu tip fisiere fara tip Modul de lucru (accesare, citire, scriere) difera, cel putin partial, la fiecare tip de fisier. Sa incepem cu inceputul.

Fisiere text in Pascal (text files)


Sa presupunem ca vrem sa citim doua numere de pe prima linie a unui fisier text, si apoi matricea cu respectivul numar de linii si coloane, dintr-un fisier text (creat cu notepad sau orice alternativa a acestuia). Fisierul ar putea avea urmatorul continut:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. 2 5 2. 1 2 3 4 5 3. 6 7 8 9 10

Sa vedem un program care citeste acest fisier si afiseaza datele citite pe monitor.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var fis: Text; 3. lins, cols, i, j: integer; 4. matrice: array[1 .. 20, 1 .. 20] of integer;
5. begin 6. ClrScr; 7. Assign(fis, 'fisier.txt'); 8. Reset(fis); 9. 10. ReadLn(fis, lins, cols); 11. for i := 1 to lins do 12. begin

13. 14. 15. 16. 17.


18.

for j := 1 to cols do Read(fis, matrice[i, j]); ReadLn(fis); end; Close(fis);

19. 20. 21. 22. 23.

WriteLn('Matricea citita din fisier este:'#13#10); for i := 1 to lins do {#13#10 = Enter} begin {#13 = Carriage Return} for j := 1 to cols do {#10 = Line Feed} write(matrice[i,j] : 3); 24. writeln; 25. end; 26. Write(#13#10'Apasati orice tasta pentru a iesi ...'#8#8#8#8); 27. ReadKey; {#8 = BackSpace} 28. end. Declaratia unui fisier text se face identic cu declararea unei variabile obisnuite, iar tipul variabilei esteText. Fisier Text . Restul variabilelor nu are rost sa le explic, le puteti intelege daca ati parcurs tutorialele precedente. Sa vedem ce proceduri si functii avem la dispozitie pentru lucrul cu fisiere text.

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE TEXT

Nume Assign

Descriere Asigneaza un fisier (definit prin calea catre el) catre o variabila de tip fisier. Toate operatiile ulterioare care folosesc acel fisier vor utiliza variabila acestuia. Asocierea dintre variabila si respectivul fisier va exista pana la urmatoarea asignare a variabilei catre alt fisier. Calea catre fisier trebuie sa fie o cale definita prin 0 sau mai multe directoare, separate prin semnul backslash \, urmate de numele complet al fisierului. Daca aceasta cale este inceputa direct cu semnul backslash, atunci este folosita ca si cum ar fi inceput direct in radacina ( C:\Folder\fisier.txt este identic cu\Folder\fisier.txt, daca programul este rulat dintr-un director de pe C:. Daca este dat doar numele fisierului, atunci fisierul este cautat in directorul curent (cel de unde este rulat programul). Numele fisierului trebuie sa se conformeze standardului DOS de denumire a fisierelor, adica 8.3 (nume de maxim 8 caractere, fara spatii, si extensie (optionala) de maxim 3 caractere. Un caz special este cel in care calea catre fisier este sirul vid (adica '' doua apostroafe, unul dupa celalalt). In acest caz, variabila de fisier este asignata intrarii / iesirii standard. Dupa o asignare a variabilei catre sirul

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE TEXT

vid, folosirea proceduriiReset va asocia variabila catre intrarea standard, iar folosirea procedurii ReWrite va asocia aceasta variabila cu iesirea standard. Restrictie: procedura Assign nu poate fi folosita pe un fisier deja deschis. Deschide un fisier existent pentru citire. Daca fisierul nu exista, aceasta procedura va genera o eroare. Reset Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer-ul) este setata la inceputul acestuia (de acolo poate incepe citirea). Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la intrarea standard (tastatura, de obicei). Creaza un fisier nou si il deschide pentru scriere. Daca fisierul exista, atunci el este sters si recreat (gol). Daca variabila de fisier este asignata unui fisier deschis, acesta va inchis, sters, recreat si redeschis. Rewrite Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer) este setata la inceputul acestuia. Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la iesirea standard (monitorul, de obicei). Deschide fisierul ales (prin folosirea procedurii Assign) pentru scriere. Daca fisierul nu exista, atunci aceasta procedura va genera o eroare. Daca fisierul este deja deschis, atunci el este inchis si redeschis. Pozitia in fisier (file pointer) este setata la sfarsitul acestuia. Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la iesirea standard (monitorul, de obicei). Inchide fisierul desemnat de variabila de fisier, daca respectivul fisier a fost deschis folosind una din procedurile Reset, Rewrite sau Append. Close Fisierul asociat cu variabila de fisier este adus la zi cu toate modificarile operate asupra lui, inainte de a fi inchis. EoLN Aceasta functie (acronim de la End of LiNe) returneaza True daca pozitia in fisier (file pointer-ul) este la sfarsitul unei linii (marcaj #13#10) sau la

Append

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE TEXT

sfarsitul fisierului. Returneaza False in caz contrar. Functia poate fi apelata fara parametru sau cu un parametru de tip Text (fisier text). Daca este apelata fara parametru, atunci fisierul este considerat a fi fisierul standard de intrare (tastatura). Verifica daca mai sunt date pe linia curenta, de la pozitia curenta pana la sfarsitul liniei. Daca nu mai sunt date pana la sfarsitul liniei (doar spatii sau tab-uri), va returna True, returnand False in caz contrar. SeekEoLN Restrictii: Fisierul trebuie sa fie deschis. Poate fi folosita doar cu fisiere text. Aceasta functie (acronim de la End of File) returneaza True daca pozitia in fisier (file pointer) este la sfarsitul fisierului. Returneaza False in caz contrar. EoF Functia poate fi apelata fara parametru sau cu un parametru de tip Text (fisier text). Daca este apelata fara parametru, atunci fisierul este considerat a fi fisierul standard de intrare (tastatura). Verifica daca mai sunt date in fisier, de la pozitia curent pana la sfarsitul fisierului. Daca nu mai sunt date pana la sfarsitul fisierului (doar spatii sau tab-uri), va returnaTrue, returnand False in caz contrar. SeekEoF Restrictii: Fisierul trebuie sa fie deschis. Poate fi folosita doar cu fisiere text.
Daca ati trecut prin explicatiile date in tabelul de mai sus, ar trebui sa stiti destul de multe pentru a folosi un fisier text fara probleme. Sa vedem un mic program care citeste prima linie dintr-un fisier text si o adauga, inversata, la sfarsitul fisierului.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var fis: Text; 3. linie: String; 4. i: integer; 5. c: Char;


6. begin 7. ClrScr; 8. Assign(fis, 'fisier.txt'); 9. Reset(fis);

10.

11. 12. 13. 15.

ReadLn(fis, linie); WriteLn('Prima linie din fisier este urmatoarea:'); WriteLn(linie+#13#10);

14. WriteLn('Vom adauga linia, inversata, in fisier, la sfarsitul acestuia.'); 16. WriteLn; 17. 18. for i := 1 to Length(linie) div 2 do {bucla aceasta inverseaza sirul de caractere} 19. begin 20. c := linie[i]; 21. linie[i] := linie[Length(linie) - i + 1]; 22. linie[Length(linie) - i + 1] := c; 23. end; 24. 25. Append(fis); 26. WriteLn(fis, #13#10 + linie); 27. Close(fis); 28. Write(#13#10'S-a facut ! Apasati orice tasta pentru a iesi ...'); 29. ReadKey; 30. end. Ultimul program care va folosi fisiere text in acest tutorial va citi date dintr-un fisier si le va salva in alt fisier.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var fis: Text; 3. linie: String; 4. i: integer; 5. c: Char;


6. begin 7. ClrScr; 8. Assign(fis, 'fisier.in'); 9. Reset(fis); 10. 11. ReadLn(fis, linie); 12. Close(fis); 13. 14. WriteLn('Prima linie din fisier este urmatoarea:'); 15. WriteLn(linie+#13#10); 16. 17. Assign(fis, 'fisier.out'); 18. Rewrite(fis); 19. WriteLn(fis, linie); 20. Close(fis); 21. 22. Write(#13#10'S-a facut ! Apasati orice tasta pentru a iesi ...');

23.

24. end.

ReadKey;

Atentie: presupun ca este evident ca toate fisierele de intrare folosite in aceste programe vor trebui create manual inainte de pornirea programului.

Fisiere cu tip in Pascal (typed files)


Acum, dupa ce-ati aflat ce-i cu fisierele text in Pascal, o sa-mi spuneti ca jocurile pe care le mentionam mai sus nu folosesc fisiere text, sau foarte rar... si nu va pot contrazice. Asa este. Fisierele text, desi permit salvarea a orice date in ele, sunt limitate de faptul ca nu ne permit citirea unui anumit caracter, decat daca am citit toate caracterele dinaintea lui. Imaginati-va un fisier text de cativa megabytes (mega-octeti, daca vreti ), din care vrem sa citim caracterul cu indicele 1.123.194 ... va trebui sa citim un milion de caractere inainte de a putea citi caracterul care ne intereseaza. Aici intra in joc fisierele cu tip. Ele permit citirea secventiala a datelor (ca si fisierele text), dar si citirea aleatorie (random) din fisier. Spre deosebire de fisierele text, de unde puteam citi doar siruri de caractere (nu va lasati pacaliti de faptul ca ReadLn citeste si numere ... le converteste intern din string in valoare numerica !), din fisiere fara tip se pot citi doar valori de acelasi tip ca si fisierul in sine. Fisierele cu tip sunt, practic, o varianta a vectorilor (array, if you please). Pot stoca date de un singur tip, cel setat in declararea variabilei de fisier, dar sunt limitate de spatiul disponibil pe hard-disk (si, in versiunile vechi de Pascal, cum ar fi Borland Pascal, de o marime maxima de 2 GB / fisier - tineti totusi cont ca in 1992, cand a aparut Borland Pascal 7.0 nu sunt sigur daca existau, inca, hard-disk-uri atat de mari !). Haideti sa vedem un mic program care scrie un set de date aleatorii intr-un fisier cu tip (tip integer, pentru inceput), iar apoi le reciteste si afiseaza a 20-a valoare din fisier.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var fis: file of integer; 3. i, val: integer;


4. begin 5. ClrScr; 6. Randomize; 7. Assign(fis, 'fisier.bin'); 8. Rewrite(fis); 9. 10. for i := 1 to 100 do 11. begin 12. val := Random(20000) + 1; {valori intre 1 si 20000} 13. Write(fis, val); 14. end; 15. Close(fis);

16.

17. 18. 19. 21. 22. 24. 26.

Assign(fis, 'fisier.bin'); ReSet(fis); Seek(fis, 19); {indexul incepe de la 0} Read(fis, i); WriteLn('A 20-a valoare din fisier este : ',i); Close(fis);

20.

23. 25. Write(#13#10'S-a facut ! Apasati orice tasta pentru a iesi ...'); ReadKey; 28. end. 27. Este de remarcat faptul ca fiecare element din fisier ocupa 2 bytes, in acest caz (integer). Lista de proceduri si functii care pot fi folosite la manipularea fisierelor cu tip sunt date in tabelul de mai jos. Explicatiile date in acest tabel sunt doar complementare celor date in tabelul de proceduri si functii dat pentru folosirea cu fisiere text.

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE CU TIP

Nume Assign Identic cu fisierele text.

Descriere Deschide un fisier existent (pentru citire / scriere). Daca fisierul nu exista, aceasta procedura va genera o eroare.

Reset

Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer-ul) este setata la inceputul acestuia. Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la intrarea standard (tastatura, de obicei). Creaza un fisier nou si il deschide (pentru scriere / citire). Daca fisierul exista, atunci el este sters si recreat (gol). Daca variabila de fisier este asignata unui fisier deschis, acesta va inchis, sters, recreat si redeschis.

Rewrite

Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer) este setata la inceputul acestuia. Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la iesirea standard (monitorul, de obicei).

Close

Inchide fisierul desemnat de variabila de fisier, daca respectivul fisier a fost deschis folosind una din procedurile Reset sau Rewrite.

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE CU TIP

Fisierul asociat cu variabila de fisier este adus la zi cu toate modificarile operate asupra lui, inainte de a fi inchis. Returneaza numarul de componente din fisierul desemna de variabila de fisier. Marimea actuala a fisierului poate fi aflata inmultind rezultatul acestei functii cu numarul de bytes folositi de fiecare componenta. FileSize Restrictii: Fisierul trebuie sa fie deschis. Nu poate fi folosita cu fisiere text. Returneaza pozitia in fisier (file pointer-ul). Daca pozitia este chiar la inceputul fisierului, atunci aceasta functie returneaza 0. Daca pozitia este la sfarsitul fisierului, atunci rezultatul lui FilePos este egal cu cel al functie FileSize, prezentata mai sus. Restrictii: Fisierul trebuie sa fie deschis. Nu poate fi folosita cu fisiere text. Muta pozitia in fisier (file pointer) la cea specificata. Urmatoarea citire sau scriere se face din acel loc. Numarul primei componente din fisier este 0. Noua pozitie care poate fi specificata este de tip Longint, deci nu poate merge mai departe de 2 GB. Pentru a scrie la sfarsitul fisierului (dupa ultima componenta) se poate folosi cu impreuna cu rezultatul functiei FileSize. Seek Daca pozitia este chiar la inceputul fisierului, atunci aceasta functie returneaza 0. Daca pozitia este la sfarsitul fisierului, atunci rezultatul lui FilePos este egal cu cel al functie FileSize, prezentata mai sus. Restrictii: Fisierul trebuie sa fie deschis. Nu poate fi folosita cu fisiere text. Trunchiaza fisierul de la pozitia curenta in fisier (file pointer). Toate componentele de dupa pozitia actuala in fisier sunt sterse. Truncate Restrictii: Fisierul trebuie sa fie deschis. Nu poate fi folosita cu fisiere text.

FilePos

Niciodata nu mi-a placut restrictia care spunea ca aceasta procedura / functie nu poate fi folosita cu fisiere text, asa ca am cautat o solutie. Solutia evidenta este sa folositi un fisier cu componente de tipChar (practic, text), putand astfel folosi si functii gen FileSize, FilePos, Seek, Truncate. Totusi, probabil ca ati vrea sa aveti grija la sfarsiturile de linie / fisier

Fisiere fara tip in Pascal (untyped files)


Fisierele fara tip pot fi privite ca niste fisier cu tip byte, cu diferenta ca datele din aceste fisiere nu pot fi citite/scrise cu procedurile obisnuite (Read, Write), folosind BlockRead/BlockWrite, pentru transferuri la viteza mare. Sa vedem ce s-a modificat si ce s-a adaugat, din punct de vedere al instructiunilor care pot fi folosite.

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE CU TIP

Nume Assign Identic cu fisierele cu tip.

Descriere In cazul fisierelor fara tip, aceasta procedura accepta si un parametru de tip Word, care specifica numarul de bytes avut de o componenta din fisier (RecSize). In mod implicit, RecSize este egal cu 128. Este preferabil sa il setati pe 1, avand astfel control absolut asupra citirilor / scrierilor facute in fisier. Formatului apelului acestei proceduri este urmatorul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

Reset

1. Reset(var F: File[; RecSize: Word]);

Rewrite

In cazul fisierelor fara tip, aceasta procedura accepta si un parametru de tip Word, care specifica numarul de bytes avut de o componenta din fisier (RecSize). In mod implicit, RecSize este egal cu 128. Este preferabil sa il setati pe 1, avand astfel control absolut asupra citirilor / scrierilor facute in fisier. Formatului apelului acestei proceduri este urmatorul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Rewrite(var F: File[; RecSize: Word]);

Close FileSize FilePos Seek

Identic cu fisierele cu tip. Identic cu fisierele cu tip. Identic cu fisierele cu tip. Identic cu fisierele cu tip.

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE CU TIP

Truncate

Identic cu fisierele cu tip. Citeste din fisierul selectat un numar specificat de bytes, intr-o variabila declarata de utilizator. Formatul apelului este urmatorul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. BlockRead(var F: File; var Buffer;

Count: Word; [;var Result: Word]); F este un fisier fara tip, Buffer poate fi orice variabila, Count este un numar intreg, iar Result este o variabila intreaga. Aceasta functie citeste un numar de Count (sau mai putin) componente (marimea unei componente este specificata de Reset si Rewrite) din fisierul F in memorie, in variabila Buffer. Numarul de componente citite BlockRead este returnat in variabila Result(daca este folosita). Daca variabila Result nu este folosita, o eroare I/O este generata in cazul in care numarul de componente citite este diferit de numarul specificat in apel (Count). Daca Result este egala cu Count, atunci operatia a avut efectul dorit. Numarul de bytes cititi este, in cazul optim, Count * RecSize (RecSize este 128 de bytes, daca nu este specificat altfel). Daca numarul Count * RecSize este mai mare decat 65535 (64 KB), se va genera o eroare. Pozitia in fisier este mutata la sfarsitul zonei citite, ca efect al instructiunii BlockRead. Restrictii: Fisierul trebuie sa fie deschis. Nu poate fi folosita decat cu fisiere fara tip. BlockWrite Scrie in fisierul selectat un numar specificat de bytes, dintr-o variabila declarata de utilizator. Formatul apelului este urmatorul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. BlockWrite(var F: File; var Buffer;

Count: Word; [;var Result: Word]);

F este un fisier fara tip, Buffer poate fi orice variabila, Count este un numar intreg, iar Result este o variabila intreaga.

PROCEDURI SI FUNCTII FOLOSITE LA LUCRUL CU FISIERE CU TIP

Aceasta functie scrie un numar de Count (sau mai putin) componente (marimea unei componente este specificata de Reset si Rewrite) in fisierul F din memorie, din variabila Buffer. Numarul de componente scrise este returnat in variabilaResult (daca este folosita). Daca variabila Result nu este folosita, o eroare I/O este generata in cazul in care numarul de componente scrise este diferit de numarul specificat in apel (Count). Daca Result este egala cu Count, atunci operatia a avut efectul dorit. Numarul de bytes scrisi este, in cazul optim, Count * RecSize (RecSize este 128 de bytes, daca nu este specificat altfel). Daca numarul Count * RecSize este mai mare decat 65535 (64 KB), se va genera o eroare. Pozitia in fisier este mutata la sfarsitul zonei scrise, ca efect al instructiunii BlockWrite. Restrictii: Fisierul trebuie sa fie deschis. Nu poate fi folosita decat cu fisiere fara tip.
In continuare, un exemplu de program care copiaza un fisier (fara niciun fel de verificari).
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. var src, dest: file; 3. buffer: array[1 .. 32768] of byte; {buffer de 32 KB} 4. cale_src, cale_dest: string; 5. read_bytes: word;
6. begin 7. ClrScr; 8. Write('Dati calea catre fisierul sursa: '); 9. ReadLn(cale_src); 10. 11. Write('Dati calea destinatie: '); 12. ReadLn(cale_dest); 13. 14. Assign(src, cale_src); 15. Reset(src, 1); 16. 17. Assign(dest, cale_dest); 18. Rewrite(dest, 1); 19. 20. While not Eof(src) Do {atat timp cat nu am ajuns la sfarsitul fisierului ...}

21. 22.

Begin BlockRead(src, buffer, 32768, read_bytes); {vrem sa citim 32 KB, dar verificam cat am citit} 23. BlockWrite(dest, buffer, read_bytes); {cat am citit, atat scriem} 24. End; 25. Close(src); 26. Close(dest); 27. WriteLn(#13#10'Fisierul a fost copiat !'); 28. ReadKey; 29. end.

Daca fisierul care se doreste copiat nu exista, sau daca fisierul destinatie nu are extensie (lol ) sau intervine orice alta problema, programul va returna erori. Nu este dat decat pentru a exemplifica un mod de lucru cu fisierele fara tip.

Lectia 3 (din tutorialele de Pascal)


Acesta este un exemplu de program (mic) care arata o parte din potentialul primelor trei tutoriale de Pascal postate pana in acest moment.

Creat si testat doar pe Borland Pascal 7.0, deci sa nu va aud Aici e codul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt; 2. const spaced = ' '; 3. select = ' * '; 4. var c: char; 5. sel: integer;
6. begin 7. clrscr; 8. c := #0; 9. sel := 1; 10. {afisam meniul initial} 11. TextColor(Yellow); 12. TextBackground(Blue); {galben pe albastru pentru optiunea selectata} 13. WriteLn(select, '1. BitCell.info'); 14. 15. TextColor(LightGray); 16. TextBackground(Black); 17. WriteLn(spaced, '2. a doua optiune'); {gri deschis pe negru pentru restul} 18. WriteLn(spaced, '3. a treia optiune'); 19. WriteLn(spaced, '4. a patra optiune');

20. 21. 22. 23.


24.

WriteLn(spaced, WriteLn(spaced, WriteLn(spaced, WriteLn(#13#10,

'5. a cincea optiune'); '6. a sasea optiune'); '7. a saptea optiune'); 'Press Esc to Exit ...');

25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 46. 47. 48. 49. 50. 51. 52. 53. 54. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68.

44. 45.

repeat c := ReadKey; {asteptam o tasta} case c of #0: {daca e tasta cu cod extins} begin c := ReadKey; {citim codul extins al tastei} case c of #72: {0 - 72 = codul tastei sageata sus} begin if sel > 1 then {nu putem selecta 0 sau mai mic} sel := sel - 1; end; #80: {0 - 80 = codul tastei sageata jos} begin if sel < 7 then {nu putem selecta mai mult de 7} sel := sel + 1; end; else writeln('0 - ', ord(c)); end; clrscr; WriteLn(spaced, WriteLn(spaced, WriteLn(spaced, WriteLn(spaced, WriteLn(spaced, WriteLn(spaced, WriteLn(spaced, WriteLn(#13#10, GotoXY(1, sel); '1. BitCell.info'); '2. a doua optiune'); '3. a treia optiune'); '4. a patra optiune'); '5. a cincea optiune'); '6. a sasea optiune'); '7. a saptea optiune'); 'Press Esc to Exit ...');

55. TextColor(Yellow); TextBackground(Blue); case sel of 1: WriteLn(select, '1. 2: WriteLn(select, '2. 3: WriteLn(select, '3. 4: WriteLn(select, '4. 5: WriteLn(select, '5. 6: WriteLn(select, '6. 7: WriteLn(select, '7. end; TextColor(LightGray); TextBackground(Black);

BitCell.info'); a doua optiune'); a treia optiune'); a patra optiune'); a cincea optiune'); a sasea optiune'); a saptea optiune');

69. 70. {

end; else WriteLn(ord(c));} {comentat pentru a nu afisa codul tastei apasate} 71. end; 72. 73. until (c = #27); {caracterul cu codul ASCII 27 corespunde tastei Esc} 74. {deci folosim tasta Esc pentru a iesi din program} 75. end.

Niste explicatii: uses crt; - este vorba de biblioteca (unit) de functii si proceduri care faciliteaza lucrul in modul text in Pascal. Daca linia asta lipseste nu veti putea folosi o parte din functiile si procedurile de prin program. ClrScr - (clear screen) sterge orice text de pe ecran si readuce culorile de afisare la valorile predefinite. TextColor - seteaza culoarea textului (in modul text). Definita in unitul CRT. TextBackGround - seteaza culoarea fondului (in modul text). Definita in unitul CRT. ReadKey - asteapta apasarea unei taste si returneaza caracterul apasat (nu "prinde" taste gen Ctrl, Shift, CapsLock, etc). Daca tasta are cod extins (tastele functionale, sagetile, etc), atunci va returna 0 si va trebui ca functia ReadKey sa fie apelata din nou pentru a primi codul extins al tastei. GotoXY - seteaza pozitia cursorului de text. Determina locul de pornire pentru urmatoarea afisare. Screenshot-uri din timpul rularii programului:

Lectia 4 (din tutorialele de Pascal)


Acesta este un exemplu de program (mic) care arata o parte din potentialul primelor patru tutoriale de Pascal.

Creat si testat doar pe Borland Pascal 7.0, ati fost avertizati Aici e codul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. Program Text_miscator; 2. uses crt; 3. var N, i, start, dif1, dif2: integer; 4. s: String; 5. linii, coloane: array[1 .. 80] of byte; 6. SuntAranjate: Boolean;
7. begin 8. ClrScr; 9. S := 'BitCell.info - IT forum - programare si algoritmica, hardware si altele'; 10. N := Length(S); {Length returneaza lungimea sirului de caractere} 11. 12. Randomize; {initializeaza variabila interna RandSeed cu o valoare luata din ora sistemului} 13. {aceasta variabila este variabila de la care porneste generatorul de numere aleatoare} 14.

15. 16. 17.

for i := 1 to n do begin linii[i] := Random(49) + 1; {pozitii random, dar fara ultima linie / coloana} 18. coloane[i] := Random(79) + 1; 19. gotoxy(coloane[i], linii[i]); 20. write(s[i]); 21. end; 22. 23. start := 40 - (N div 2); 24. 25. repeat 26. SuntAranjate := True; 27. for i := 1 to N do 28. begin 29. if (linii[i] <> 12) or (coloane[i] <> start + i - 1) then 30. begin 31. {calculam noua pozitie} 32. dif1 := abs(coloane[i] - (start + i - 1)); {abs = functia modul din matematica} 33. dif2 := abs(linii[i] - 12); 34. 35. if ((dif1 = 0) and (dif2 = 0)) or (s[i] = ' ') 36. then Continue {continuam bucla FOR, cu urmatoarea valoare a lui i} 37. else 38. begin 39. GotoXY(coloane[i], linii[i]); {stergem litera din vechea pozitie} 40. TextColor(Black); 41. Write(s[i]); 42. end; 43. SuntAranjate := False; 44. 45. if dif2 > dif1 46. then 47. begin 48. if linii[i] > 12 49. then Dec(linii[i]) 50. else Inc(linii[i]); 51. end 52. else 53. begin 54. if coloane[i] > (start + i - 1) 55. then Dec(coloane[i]) 56. else Inc(coloane[i]); 57. end; 58. 59. {reafisam litera in noua pozitie}

60. 61. 62.


63.

GotoXY(coloane[i], linii[i]); TextColor(LightGray); Write(s[i]);

64. 65. 66.

end; end; Delay(50); {acest interval de asteptare poate fi modificat pentru viteza} 67. until SuntAranjate; 68. 69. GotoXY(start, 12); {pe ecran, in modul text, sunt 80 de coloane} 70. Write(S); {asa ca afisam textul de la pozitia 40 minus jumatate din text} 71. ReadLn; 72. end.

Niste explicatii: Randomize - pregateste generatorul de numere random (aleatoare) Random - genereaza un numar random, intre 0 si N - 1. abs - returneaza valoarea absoluta a unui numar. abs(5) = abs(-5) = 5 Inc - creste valoarea variabilei folosite ca parametru cu 1 sau o valoare specificata. Dec - scade valoarea variabilei folosite ca parametru cu 1 sau o valoare specificata. Delay - opreste (pauzeaza) executia programului pentru un numar specificat de milisecunde. Screenshot-uri din timpul rularii programului:

Program exemplu - Star Field


Lectia 5 (din tutorialele de Pascal)
Acesta este un exemplu de (mic) program care arata o parte din potentialul primelor cinci tutoriale de Pascal postate pana in acest moment.

Creat si testat doar pe Borland Pascal 7.0, deci sa nu va aud Urmeaza codul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

1. uses crt, graph; 2. type star = record 3. X, Y, Z: Integer; 4. { pozitia si departarea "stelei" } 5. end;
6. 8.

7. const N = 250; {numarul de "stele"} 9. var gd, gm: Integer; {init graphics mode} 10. i, Sx, Sy: integer; 11. stars: array[1 .. N] of star;
12.

13.

procedure InitStars; {initializeaza "N" stele : pozitie si departare} 14. var i: Integer; 15. begin 16. Sx := GetMaxX; {numarul de coloane in modul grafic} 17. Sy := GetMaxY; {numarul de linii in modul grafic} 18. 19. Randomize; 20. for i := 1 to N do 21. begin 22. stars[i].X := Random(Sx - 9) + 5; {pozitia} 23. stars[i].Y := Random(Sy - 9) + 5; 24. stars[i].Z := Random(250) + 1; {departarea trebuie sa fie} 25. end; {cat mai aleatorie la inceput} 26. end; 27. 28. procedure MoveStars; 29. var i, X, Y, Z: Integer; 30. color, speed: Byte; 31. pause: Boolean;

32. 33. 34. 35. 36. 37. 38. 39.

begin pause := False; speed := 5; repeat {bucla infinita ... este oprita daca se apasa tasta Escape} if not pause then for i := 1 to N do begin X := round((stars[i].X * 256) / stars[i].Z) + Sx shr 1; {calcularea pozitiei unei stele, in functie de Z (adancime)} 40. Y := round((stars[i].Y * 256) / stars[i].Z) + Sy shr 1; {shr 1 = div 2. Shift pe biti catre dreapta, adica impartire intreaga la 2} 41. SetColor(Black); 42. Rectangle(X, Y, X+1, Y+2); 43. 44. if (X < 2) or (X > Sx - 2) or {daca "steaua" iese din monitor,} 45. (Y < 2) or (Y > Sy - 2) or {ii schimbam pozitia si departarea} 46. (stars[i].Z < 10) then 47. begin 48. stars[i].X := Random(Sx - 9) + 5; 49. stars[i].Y := Random(Sy - 9) + 5; 50. stars[i].Z := Random(20) + 230; {departarea trebuie sa fie maxima} 51. end; 52. Dec(stars[i].Z); 53. 54. X := Round((stars[i].X * 256) / stars[i].Z) + Sx shr 1;{noua coloana a "stelei"} 55. Y := Round((stars[i].Y * 256) / stars[i].Z) + Sy shr 1;{noua linie a "stelei"} 56. 57. case (stars[i].Z div 3) of {cu cat "steaua" e mai departata,} 58. 65: color := DarkGray; {cu atat e mai inchisa la culoare} 59. 35: color := LightGray; 60. 20: color := White; 61. end; 62. 63. SetColor(color); 64. if stars[i].Z > 120 65. then PutPixel(X, Y, color) {cu cat e mai aproape steaua,} 66. else Rectangle(X, Y, X+1, Y+1) {cu atat e mai mare} 67. end; 68. 69. if KeyPressed then 70. begin 71. case UpCase(ReadKey) of

72. 73.
iesim}

#27 : Break;

{s-a apasat Escape, asa ca

'P' : pause := not pause; {s-a apasat P, punem pauza sau o scoatem} 74. '+' : if (speed > 1) then {plus - crestem viteza} 75. dec(speed); 76. '-' : if (speed < 80) then {minus - scadem viteza} 77. inc(speed); 78. end; 79. end; 80. 81. Delay(speed); 82. until False; 83. end; 84. 85.begin 86. gd := 0; 87. InitGraph(gd, gm, ''); 88. 89. InitStars; 90. MoveStars; 91. 92. CloseGraph; 93. end.

Functiile si procedurile legate de afisare le voi explica intr-un tutorial separat. Screenshot din timpul rularii programului:

S-ar putea să vă placă și