Programarea Calculatoarelor si Limbaje de Programare

316
Dumitru Dragomir PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE Editura Fundaţiei Universitare „Dunărea de Jos” Galaţi – 2006

description

Programarea Calculatoarelor si Limbaje de Programare

Transcript of Programarea Calculatoarelor si Limbaje de Programare

Page 1: Programarea Calculatoarelor si Limbaje de Programare

Dumitru Dragomir

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE

Editura Fundaţiei Universitare „Dunărea de Jos” Galaţi – 2006

Page 2: Programarea Calculatoarelor si Limbaje de Programare

Dumitru Dragomir

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE

Editura Fundaţiei Universitare „Dunărea de Jos” Galaţi – 2006

Page 3: Programarea Calculatoarelor si Limbaje de Programare

UNIVERSITATEA „DUNĂREA DE JOS” DIN GALAŢI FACULTATEA DE NAVE

Editura Fundaţiei Universitare „Dunărea de Jos” din Galaţi este acreditată de CNCSIS

Referenţi ştiinţifici

Prof. Dr. Ing. Viorel Mânzu Prof. Dr. Ing. Leonard Domnişoru

Editura Fundaţiei Universitare www.editura.ugal.ro „Dunărea de Jos”, Galaţi, 2006 [email protected] ISBN : 973 - 627 - 260 – 5

Page 4: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare I

CUPRINS

Introducere ...........................................................................................................................1 Cap.1. Elemente de bază în informatică ............................................................................3

§.1.1. Definiţii de bază ......................................................................................................3 §.1.2. Sisteme de numeraţie...............................................................................................3 §.1.3. Reprezentarea informaţiei în calculator...................................................................5 §.1.4. Codificarea informaţiei în calculator.......................................................................5 §.1.5. Reprezentarea datelor ..............................................................................................6 §.1.6. Structura fizică (hardware) a unui calculator ..........................................................9 §.1.7. Structura operaţională a unui sistem de calcul ......................................................13 §.1.8. Organizarea funcţională a unui sistem de calcul ...................................................15 §.1.9. Dispozitive periferice ............................................................................................17

1.9.1. Dispozitive de intrare........................................................................................17 1.9.2. Dispozitive de ieşire..........................................................................................19 1.9.3. Memoriile externe.............................................................................................23

§.1.10. Organizarea datelor în memoria externă. Fişiere ................................................25 1.10.1. Structurarea fişierelor .....................................................................................25 1.10.2. Operaţii cu fişiere............................................................................................26 1.10.3. Tipuri de fişiere...............................................................................................28

§.1.11. Noţiuni privind structura software a calculatorului.............................................29 1.11.1. Ierarhia programelor .......................................................................................29

§.1.12. Elemente de ingineria programării ......................................................................30 1.12.1. Generalităţi......................................................................................................30 1.12.2. Modularizarea .................................................................................................30 1.12.3. Teorema fundamentală a ingineriei programării ............................................31 1.12.4. Date, tipuri şi structuri de date........................................................................32 1.12.5. Structuri de programe. Programare structurată...............................................33 1.12.6. Metode de programare ....................................................................................37

§.1.13. Programe şi limbaje de programare.....................................................................37 1.13.1. Portabilitatea programelor ..............................................................................38 1.13.2. Fazele de elaborare a unui program executabil. .............................................39

Cap.2. Limbajul C ..............................................................................................................43

§2.1. Caractere.................................................................................................................43 §2.2. Atomi lexicali .........................................................................................................43

2.2.1. Identificatori......................................................................................................43 2.2.2. Numere..............................................................................................................43 2.2.3. Constante ..........................................................................................................44 2.2.4. Delimitatori de comentariu ...............................................................................44 2.2.5. Cuvinte cheie ....................................................................................................44 2.2.6. Operatori ...........................................................................................................44

2.2.6.1. Operatori unari ..........................................................................................44 2.2.6.2. Operatori binari .........................................................................................45 2.2.6.3. Operatorul ternar condiţional ....................................................................48 2.2.6.4. Operatorul de atribuire simplă şi compusă ...............................................49

2.2.7. Precedenţa operatorilor .....................................................................................50

Page 5: Programarea Calculatoarelor si Limbaje de Programare

Cuprins II

§2.3. Tipuri de date standard ...........................................................................................50 2.3.1. Tipuri de bază ...................................................................................................50 2.3.2. Modificatori de tipuri........................................................................................51 2.3.2. Stocare în memorie şi domenii de valori ..........................................................51 2.3.4. Tipul enumeraţie ...............................................................................................51 2.3.5. Tipul structură...................................................................................................52 2.3.6. Tipul uniune......................................................................................................53 2.3.7. Date nemodificabile. Declaraţia const ..............................................................53 2.3.8. Declaraţia typedef .............................................................................................54

§2.4. Conversii de tipuri de date......................................................................................54 2.4.1. Conversia automată de tip.................................................................................54 2.4.2. Conversia explicită de tip. Operatorul cast.......................................................54

§2.5. Instrucţiuni..............................................................................................................55 2.5.1. Instrucţiunea expresie .......................................................................................55 2.5.2. Instrucţiunea de decizie ....................................................................................56 2.5.3. Instrucţiunea de selecţie....................................................................................56 2.5.4. Instrucţiunea de ciclare for ...............................................................................57 2.5.5. Instrucţiunea de ciclare cu test iniţial, while.....................................................57 2.5.6. Instrucţiunea de ciclare cu test final, do-while .................................................58 2.5.7. Instrucţiunea continue.......................................................................................58 2.5.8. Instrucţiunea de salt, goto .................................................................................58

§2.6. Tablouri ..................................................................................................................59 §2.7. Adrese şi pointeri....................................................................................................60

2.7.1. Definiţia pointerilor ..........................................................................................60 2.7.2. Utilizarea variabilelor pointer...........................................................................61 2.7.3. Iniţializarea variabilelor pointer........................................................................61 2.7.4. Relaţia dintre pointeri şi tablouri ......................................................................61 2.7.5. Pointeri către pointeri........................................................................................62 2.7.6. Aritmetica pointerilor .......................................................................................62

§2.8. Funcţii.....................................................................................................................63 2.8.1. Prototipul unei funcţii .......................................................................................63 2.8.2. Definirea unei funcţii ........................................................................................63 2.8.3. Apelul unei funcţii ............................................................................................63 2.8.4. Instrucţiunea return ...........................................................................................64 2.8.5. Funcţia main .....................................................................................................64 2.8.6. Exemplu de folosire a funcţiilor într-un program C .........................................64 2.8.7. Transferul argumentelor funcţiilor....................................................................65

§2.9. Directive preprocesor .............................................................................................69 2.9.1. Directiva include...............................................................................................69 2.9.2. Directiva define.................................................................................................70 2.9.3. Directiva undef .................................................................................................70 2.9.4. Directive de compilare condiţionată .................................................................70

Cap.3. Elemente de limbaj C++ ........................................................................................72

§3.1. Operaţii de intrare/ieşire cu consola .......................................................................72 §3.2. Supraîncărcarea funcţiilor ......................................................................................72 §3.3. Utilizarea argumentelor prestabilite .......................................................................73 §3.4. Alocarea dinamică a memoriei ...............................................................................73

Page 6: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare III

§3.5. Conceptul de clasă ..................................................................................................73 3.5.1. Structura în C++ ...............................................................................................74 3.5.2. Clasa în C++ .....................................................................................................76 3.5.3. Funcţii speciale ale clasei. Constructori şi destructori......................................76 3.5.4. Autoreferinţa unui obiect al clasei. Cuvântul cheie this ...................................80 3.5.5. Membrii statici ai clasei....................................................................................80 3.5.6. Funcţii prietene .................................................................................................80 3.5.7. Supradefinirea operatorilor ...............................................................................81

Cap.4. Programarea în limbajul C sub sistemul DOS ....................................................83

§.4.1. Structura unui program C ......................................................................................83 §.4.2. Fişiere antet ...........................................................................................................83 §.4.3. Funcţii de bibliotecă standard................................................................................83

4.3.1. Funcţii de conversie a datelor ...........................................................................84 4.3.2. Funcţii matematice............................................................................................84 4.3.3. Funcţii de intrare/ieşire ale consolei .................................................................86

4.3.3.1. Funcţii de intrare de la tastatură ................................................................86 4.3.3.2. Funcţii de acces la ecranul text .................................................................87

4.3.4. Funcţii de intrare/ieşire standard.......................................................................88 4.3.4.1. Intrări/ieşiri standard .................................................................................88 4.3.4.2. Intrări/ieşiri în flux (de la/spre fişiere) ......................................................91

4.3.5. Funcţii de lucru cu şiruri de caractere...............................................................95 4.3.6. Funcţii de clasificare şi conversie a caracterelor ..............................................95 4.3.7. Funcţii de acces la directoare şi dispozitive......................................................96 4.3.8. Funcţii de alocare a memoriei...........................................................................97 4.3.9. Funcţii grafice DOS..........................................................................................98

Cap.5. Elemente de operabilitate sub Windows ............................................................107

§5.1. Relaţia calculator – mediu de execuţie .................................................................107 §5.2. Sarcini şi tehnici de realizare a sarcinilor.............................................................108

5.2.1. Interdependenţa sarcinilor...............................................................................108 5.2.2. Tehnica unitasking..........................................................................................109 5.2.3. Tehnica multitasking.......................................................................................112

§5.3. Mediul obiectual ...................................................................................................112 5.3.1. Tehnica de programare orientată pe obiect.....................................................112

§5.4. Mediu de programare ...........................................................................................115 5.4.1. Medii de programare integrate, medii integrate de dezvoltare a aplicaţiilor ..116 5.4.2. Elaborarea unui program în limbaj C într-un mediu de programare integrat .117

Cap. 6. Mediul Visual BASIC pentru EXCEL ..............................................................119

§6.1. Generalităţi ...........................................................................................................119 §6.2. Obiecte şi colecţii .................................................................................................119

6.2.1. Utilizarea obiectelor........................................................................................120 6.2.2. Variabile obiect...............................................................................................120 6.2.3. Proprietăţi care reprezintă obiecte ..................................................................121 6.2.4. Adresarea obiectelor .......................................................................................121 6.2.5. Folosirea sau manipularea proprietăţilor obiectelor .......................................122 6.2.6. Activarea obiectelor........................................................................................122

Page 7: Programarea Calculatoarelor si Limbaje de Programare

Cuprins IV

§6.3. Tipuri de date........................................................................................................123 §6.4. Constante şi variabile ...........................................................................................123

6.4.1.Constante .........................................................................................................123 6.4.2. Variabile..........................................................................................................124 6.4.3. Vizibilitatea constantelor şi variabilelor .........................................................126 6.4.4. Durata de viaţă variabilelor.............................................................................126

§6.5. Tipuri de date definite de utilizator ......................................................................127 §6.6. Expresii.................................................................................................................127 §6.7. Conversii de tip.....................................................................................................128

6.7.1. Conversia de tip automată...............................................................................128 6.7.2. Conversia de tip explicită ...............................................................................129

§6.8. Enunţurile Visual BASIC .....................................................................................130 §6.9. Comentarii ............................................................................................................130 §6.10. Proceduri.............................................................................................................131

6.10.1. Subrutine.......................................................................................................131 6.10.2. Subrutine.......................................................................................................132 6.10.3. Apelul procedurilor.......................................................................................133

§6.11. Foile pentru module............................................................................................133 §6.12. Structuri de control al execuţiei în Visual BASIC .............................................134

6.12.1. Structura bialternanţă ....................................................................................134 6.12.2. Structura monoalternanţă ..............................................................................134 6.12.3. Structura multialternanţă (selectoare)...........................................................134 6.12.4. Structura repetitivă contorizată explicit ........................................................135 6.12.5. Structura repetitivă contorizată implicit .......................................................136 6.12.6. Structura repetitivă condiţionată anterior .....................................................136 6.12.7. Structura repetitivă condiţionată posterior....................................................137 6.12.8. Instrucţiunea de salt ......................................................................................137

§6.13. Pseudoprocedura.................................................................................................138 Cap. 7. Resurse de interfaţare grafică............................................................................139

§7.1. Generalităţi ...........................................................................................................139 §7.2. Tehnici de interacţiune .........................................................................................140

7.2.1. Dispozitive logice de intrare ...........................................................................140 7.2.1.1. LOCATOR..............................................................................................140 7.2.1.2. STROKE .................................................................................................140 7.2.1.3. VALUATOR...........................................................................................141 7.2.1.4. CHOICE..................................................................................................141 7.2.1.5. PICK........................................................................................................141 7.2.1.6. STRING ..................................................................................................142

7.2.2. Modurile de operare ale dispozitivelor logice de intrare ................................142 7.2.2.1. Modul Cerere ..........................................................................................142 7.2.2.2. Modul Eşantionare ..................................................................................142 7.2.2.3. Modul Eveniment....................................................................................143

§7.3. Resurse de dialog..................................................................................................143 7.3.1. Crearea unei cutii de dialog definită de utilizator...........................................143 7.3.2. Controlul interactiv al proprietăţilor obiectelor ..............................................145 7.3.4. Controlul programat al proprietăţilor obiectelor.............................................145

§7.4. Integrarea unei aplicaţii în mediul de aplicaţie.....................................................147

Page 8: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare V

7.4.1. Generalităţi......................................................................................................147 7.4.2. Controlul prin program al obiectelor aplicaţiei suport....................................148 7.4.3. Personalizarea aplicaţiei .................................................................................149

Cap.8. Limbajul FORTRAN. Versiunea FTN95...........................................................151

§8.1. Prezentare generală...............................................................................................151 §8.2. Convenţii sintactice generale................................................................................151 §8.3. Tipuri de date, declarare, iniţializare ....................................................................152 §8.4. Parametrizarea ......................................................................................................153 §8.5. Atribuirea implicită a tipului ................................................................................154 §8.6. Tipuri de date definite de utilizator (date structurate) ..........................................154 §8.7. Operatori şi expresii .............................................................................................155

8.7.1. Operatori unari................................................................................................155 8.7.2. Operatori binari...............................................................................................155 8.7.3. Precedenţa operatorilor ...................................................................................155 8.7.4. Operatori în expresii numerice .......................................................................155 8.7.5. Conversia de tip ..............................................................................................156 8.7.6. Operatori la nivel de caracter..........................................................................156 8.7.7. Operatori relaţionali........................................................................................156 8.7.8. Operatori logici ...............................................................................................156

§8.8. Tablouri ................................................................................................................157 8.8.1. Tablouri de mărime fixă .................................................................................157 8.8.2. Tablouri de mărime variabilă..........................................................................158

§8.9. Structuri de control ...............................................................................................158 8.9.1. Instrucţiunea de salt necondiţionat, GO TO ...................................................158 8.9.2. Instrucţiunea alternativă, IF ............................................................................158 8.9.3. Blocul de alternative IF...................................................................................159 8.9.4. Blocul alternativă multiplă SELECT CASE...................................................159 8.9.5. Ciclul repetitiv contorizat DO.........................................................................160 8.9.6. Ciclul DO indefinit .........................................................................................160 8.9.7. Ciclul DO WHILE..........................................................................................161 8.9.8. Ciclul DO implicit ..........................................................................................161 8.9.9. Etichetarea (numirea) structurilor de control..................................................161

§8.10. Unităţi de program şi proceduri..........................................................................162 8.10.1. Generalităţi....................................................................................................162 8.10.2. Programe principale......................................................................................162 8.10.3. Subrutine.......................................................................................................162 8.10.4. Instrucţiunea STOP.......................................................................................163 8.10.5. Funcţii ...........................................................................................................163 8.10.6. Argumente reale şi formale. Argumente opţionale.......................................163 8.10.7. Conservarea valorilor. Atributul SAVE........................................................165 8.10.8. Module de program.......................................................................................165 8.10.9. Vizibilitatea datelor din module. Atributele PUBLIC şi PRIVATE ............166 8.10.10. Fişiere externe. Directiva INCLUDE .........................................................166

§8.11. Operaţii de intrare/ieşire .....................................................................................167 8.11.1. Instrucţiunea FORMAT................................................................................167 8.11.2. Instrucţiuni pentru transferul datelor ............................................................169

8.11.2.1. Instrucţiunea READ..............................................................................169

Page 9: Programarea Calculatoarelor si Limbaje de Programare

Cuprins VI

8.11.2.2. Instrucţiunea WRITE ............................................................................170 8.11.2.3. Instrucţiunea PRINT .............................................................................170 8.11.2.4. Instrucţiunea OPEN ..............................................................................170 8.11.2.5. Instrucţiunea CLOSE ............................................................................172 8.11.2.6. Instrucţiunea INQUIRE ........................................................................172 8.11.2.7. Instrucţiunile de poziţionare în fişier BACKSPACE şi REWIND .......174

§8.12. Variabile pointer şi ţinte .....................................................................................175 8.12.2. Asocierea pointerilor cu ţintele. Dezasocierea pointerilor............................176 8.12.3. Alocarea dinamică a memoriei pentru tablouri.............................................178

§8.13. Mediul PLATO3 IDE .........................................................................................178 8.13.1. Generalităţi....................................................................................................178 8.13.2. Construirea şi rularea unui proiect................................................................179

Cap.9. Limbajul AutoLISP pentru AutoCAD...............................................................182

§9.1. Generalităţi ...........................................................................................................182 §9.2. Lista ca structură de bază în AutoLISP. Funcţii...................................................182

9.2.1. Lista ................................................................................................................182 9.2.2. Funcţia ............................................................................................................183

§9.3. Evaluarea în AutoLISP.........................................................................................184 9.3.1. REP – ciclul de funcţional bază în AutoLISP.................................................184 9.3.2. Evaluarea simbolurilor....................................................................................185

§9.4. Convenţii sintactice în AutoLISP.........................................................................185 §9.5. Funcţii primitive în AutoLISP..............................................................................185 §9.6. Predicate de bază în AutoLISP.............................................................................187 §9.7. Funcţii de test logic în AutoLISP .........................................................................189 §9.8. Funcţiile READ şi EVAL.....................................................................................189 §9.9. Funcţii alternativă .................................................................................................190 §9.10. Expresii ciclice ...................................................................................................190 §9.11. Funcţia program..................................................................................................191 §9.12. Funcţii de test numeric .......................................................................................191 §9.13. Funcţii de prelucrare a listelor ............................................................................191 §9.14. Funcţii numerice.................................................................................................192 §9.15. Comenzi definite de utilizator ............................................................................194 §9.16. Comunicarea prin AutoLISP ..............................................................................194

9.16.1. Funcţii de conversie valorică ........................................................................194 9.16.2. Funcţii de operare asupra şirurilor de caractere............................................195 9.16.3. Funcţii de intrare/ieşire .................................................................................195 9.16.4. Realizarea dialogului dintre AutoCAD şi AutoLISP....................................198

§9.17. Accesul la baza de date a entităţilor AutoCAD..................................................200 9.17.1. Funcţii de manipulare a entităţilor grafice....................................................200 9.17.2. Funcţii de acces la tabela de simboluri .........................................................202 9.17.3. Funcţii pentru manipularea seturilor de selecţie ...........................................202

Cap.10. Aplicaţii de programare în C şi C++ ................................................................204

§10.1. Elaborarea unui program în limbaj C într-un mediu de programare integrat.....204 10.1.1. Generalităţi asupra mediului de lucru...........................................................204 10.1.2. Lansarea în lucru a compilatorului de C.......................................................205 10.1.3. Utilizarea meniului mediului de programare ................................................205

Page 10: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare VII

10.1.4. Aplicaţie........................................................................................................208 §10.2. Programe simple în C .........................................................................................209 §10.3. Folosirea structurilor ca tipuri de date complexe ...............................................211 §10.4. Aplicaţii simple în C++ ......................................................................................212 §10.5. Aplicaţii de utilizare a tablourilor.......................................................................213 §10.6. Aplicaţii la transmiterea tablourilor ca pointeri..................................................214 §10.7. Alocarea dinamică a memoriei ...........................................................................215 §10.8. Funcţii de acces la ecranul text...........................................................................218 §10.9. Accesul la ecranul grafic ....................................................................................220 §10.10. Aplicaţie grafică pentru construcţia diagramelor .............................................223 §10.11. Aplicaţie grafică la utilizarea claselor ..............................................................227

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL........................232

§11.1. Generalităţi privind lucrul în EXCEL ................................................................232 11.1.1. Structura documentelor EXCEL...................................................................232 11.1.2. Conţinutul celulelor ......................................................................................232 11.1.3. Utilizarea formulelor şi funcţiilor .................................................................233

11.1.3.1. Formule .................................................................................................233 11.1.3.2. Exemplu de utilizare a formulelor. Calculul perimetrului şi suprafeţei cercului.................................................................................................................234 11.1.3.3. Funcţii EXCEL predefinite ...................................................................234

11.1.4. Formatarea celulelor .....................................................................................234 11.1.5. Macro comenzi şi macro funcţii ...................................................................235

11.1.5.1. Înregistrarea macro-comenzilor ............................................................235 11.1.5.2. Execuţia unei macro-comenzi ...............................................................235 11.1.5.3. Definirea unei macro-funcţii .................................................................236 11.1.5.4. Asocierea unei macro-comenzi cu un element de interacţiune.............236

§11.2. Utilizarea programului EXCEL pentru crearea unui document de calcul simplu: calculul variaţiilor unor funcţii şi crearea unei diagrame centralizatoare .....................237

11.2.1. Intrarea în program .......................................................................................237 11.2.2. Operaţii elementare frecvente.......................................................................237

11.2.2.1. Operaţii de selectare..............................................................................237 11.2.2.2. Operaţia de mutare a unei entităţi (foaie, celulă, rând, coloană)...........238 11.2.2.3. Operaţia de copiere a unei entităţi.........................................................238 11.2.2.4. Operaţia de inserare a unei entităţi........................................................238 11.2.2.5. Operaţia de ştergere a unei entităţi........................................................238 11.2.2.6. Intrarea în regimul de editare intracelulară ...........................................238

11.2.3. Aranjarea convenabilă a documentului.........................................................238 11.2.4. Crearea tabelului ...........................................................................................239 11.2.5. Crearea diagramei centralizatoare ................................................................239 11.2.6. Crearea de macrocomenzi prin înregistrare ..................................................241

11.2.6.1. Comutare de la foaie de lucru la foaie de diagramă..............................241 11.2.6.2. Comutarea de la foaia de diagramă la foaia de lucru ............................242

11.2.7. Crearea de obiecte de interacţiune grafică ....................................................242 11.2.7.1. Crearea unui buton de comutare din foaia de lucru în foaia cu diagrama ....................................................................................................... 242 11.2.7.2. Crearea unui buton de comutare din foaia cu diagrama în foaia de lucru .....................................................................................................................242

Page 11: Programarea Calculatoarelor si Limbaje de Programare

Cuprins VIII

11.2.7.3. Crearea unei cutii de dialog pentru comutarea de la tabel la diagramă ..............................................................................................................243

11.2.8. Salvarea fişierului .........................................................................................244 §11.3. Folosirea înregistrărilor de macrocomenzi în construirea aplicaţiilor................245

11.3.1. Fazele de realizare a unei aplicaţii prin folosirea înregistratorului de macrocomenzi ..245 11.3.2. Definirea problemei ......................................................................................245 11.3.3. Rezolvarea neprogramată .............................................................................245 11.3.4. Rezolvarea programată. Automatizarea aplicaţiei ........................................247

§11.4. Folosirea funcţiilor definite de utilizator sub EXCEL .......................................250 11.4.1. Baze teoretice................................................................................................250 11.4.2. Realizarea aplicaţiei sub EXCEL .................................................................251

§11.5. Folosirea obiectelor simple de interacţiune grafică din EXCEL........................254 11.5.1. Crearea tabelului funcţiei..............................................................................254 11.5.2. Generarea diagramei funcţiei........................................................................255 11.5.3. Crearea unui duplicat al tabelului funcţiei prin metoda referinţelor.............255 11.5.4. Crearea unei cutii de dialog pentru interacţiune ...........................................255 11.5.5. Crearea macrocomenzilor de interacţiune ....................................................256 11.5.6. Realizarea legăturilor de interacţiune ...........................................................258

§11.6. Folosirea obiectelor de interacţiune grafică programabile din EXCEL .............259 11.6.1. Definirea temei .............................................................................................259 11.6.2. Construirea foii de calcul..............................................................................259

11.6.2.1. Atribuiri de nume pentru domenii de celule .........................................259 11.6.2.2. Completarea conţinutului celulelor .......................................................260

11.6.3. Construirea diagramei funcţiei......................................................................261 11.6.4. Construirea cutiei de dialog ..........................................................................261 11.6.5. Crearea subrutinelor de comandă ale instrumentelor de dialog....................263 11.6.6. Finalizarea aplicaţiei .....................................................................................265

§11.7. Aplicaţie de folosire programată a instrumentelor pentru rezolvarea şi aproximarea funcţiilor ...................................................................................................266

11.7.1. Definirea temei .............................................................................................266 11.7.2. Rezolvarea neprogramată .............................................................................266

11.7.2.1. Crearea fişierului...................................................................................266 11.7.2.2. Completarea tabelului ...........................................................................266 11.7.2.3. Crearea diagramei funcţiei ....................................................................267 11.7.2.4. Determinarea soluţiilor din intervalul de definiţie ................................267

11.7.3. Automatizarea aplicaţiei prin programare ....................................................268 11.7.3.1. Crearea elementelor de control .............................................................268 11.7.3.2. Crearea modulelor de program .............................................................270

11.7.4. Asamblarea aplicaţiei....................................................................................272 11.7.5. Protecţia aplicaţiei.........................................................................................272 11.7.6. Observaţii finale............................................................................................273

§11.8. Aplicaţie la integrarea ecuaţiilor diferenţiale prin metode Euler .......................273 11.8.1. Obiectivul lucrării .........................................................................................273 11.8.2. Crearea aplicaţiei ..........................................................................................274

11.8.2.1. Completarea tabelului ...........................................................................274 11.8.2.2. Crearea diagramei .................................................................................275

11.8.3. Crearea unui instrument de informare ..........................................................275 11.8.3.1. Crearea unei cutii de dialog ..................................................................275

Page 12: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare IX

11.8.4. Crearea subrutinelor obiectelor de interacţiune.................................................276 11.8.5. Integrarea aplicaţiei ...........................................................................................278

Cap.12. Aplicaţii în FORTRAN ......................................................................................279

§12.1. Calculul unei plutiri drepte folosind FORTRAN ...............................................279 12.1.1. Definirea temei .............................................................................................279 12.1.2. Etape de lucru ...............................................................................................279

§12.2. Lucrul cu fişiere în FORTRAN..........................................................................283 12.2.1. Definirea temei .............................................................................................283 12.2.2. Etape de lucru ...............................................................................................283

§12.3. Conversia datelor între fişiere în FORTRAN.....................................................285 12.3.1. Definirea temei .............................................................................................285 12.3.2. Etape de lucru ...............................................................................................286

§12.4. Aplicaţii interactive sub Windows în FORTRAN..............................................292 12.4.1. Definirea temei .............................................................................................292 12.4.2. Etape de lucru ...............................................................................................292

Cap.13. Aplicaţii în AutoLISP ........................................................................................296

§13.1. Desenarea unor drapele folosind AutoLISP .......................................................296 13.1.1. Scrierea programului AutoLISP ...................................................................296 13.1.2. Explicaţii privind funcţionarea programului.................................................296 13.1.3. Încărcarea şi utilizarea programului .............................................................297

§13.2. Calculul aproximativ al soluţiilor unei ecuaţii ...................................................297 13.2.1. Scrierea programului AutoLISP ...................................................................297 13.2.2. Explicaţii privind funcţionarea programului.................................................298 13.2.3. Exploatarea programului...............................................................................299

§13.3. Desenul secţiunii printr-un arbore cu canal de pană...........................................299 13.3.1. Scrierea programului AutoLISP ...................................................................299 13.3.2. Explicaţii privind funcţionarea programului.................................................300 13.3.3. Utilizarea programului..................................................................................301

§13.4. Generarea unui fişier de date ..............................................................................301 13.4.1. Scrierea programului AutoLISP ...................................................................301 13.4.2. Explicaţii privind funcţionarea programului.................................................301 13.4.3. Utilizarea programului..................................................................................302

§13.5. Desenarea unei diagrame cu date citite din fişier ...............................................302 13.5.1. Scrierea programului AutoLISP ...................................................................302 13.5.2. Explicaţii privind funcţionarea programului.................................................303 13.5.3. Utilizarea programului..................................................................................303

Bibliografie .......................................................................................................................304

Page 13: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 1

Introducere Lucrarea de faţă îşi propune să acopere, nevoile programatorului de aplicaţie inginerească

care, spre deosebire de informaticianul de specialitate pură, are de făcut faţă unor sarcini

practice izvorâte, cel mai adesea, din specificul interdisciplinar al programelor folosite în

activitatea de proiectare.

Într-o asemenea conjunctură profesională, programatorul de aplicaţie este mai puţin

solicitat de sarcini de profunzime informatică şi mai mult de nevoia de a acoperi o arie

aplicativă cu extindere mare. Într-adevăr, fiind obligat să lucreze cu mai multe programe în

cadrul aceleiaşi teme de proiectare, una dintre sarcinile mari consumatoare de efort este aceea

de a realiza o serie de acţiuni cum ar fi:

- Suplinirea lipsurilor unui produs soft prin crearea de programe de aplicaţie în mediul de

dezvoltare integrat oferit de produsul soft respectiv;

- Atunci când produsul soft nu conţine un mediu integrat de dezvoltare a aplicaţiilor,

crearea unui instrument adiţional folosind resurse externe produsului soft în cauză;

- Interfaţarea diverselor produse soft folosite, prin instrumente de tip import/export de date

între aplicaţii diferite folosind convertoare de date existente sau create prin acţiuni de

programare, transfer de comenzi între aplicaţii prin tehnici specifice aplicaţiilor folosite.

Acţiunile enumerate mai sus sunt numai câteva dintre posibilele opţiuni de urmat şi ele

evidenţiază necesitatea cunoaşterii mai multor limbaje şi tehnici de programare în medii de

lucru diferite.

Din acest motiv autorul şi-a propus să expună câteva dintre limbajele mai des folosite de

către programatorii de aplicaţie inginerească, optând pentru limbajele C, C++, Visual Basic

for Applications (VBA) în Excel, Fortran şi AutoLISP.

Raţiunile acestei alegeri sunt următoarele:

- Larga răspândire a limbajului C la acest moment;

- Uşurinţa în manipulare a limbajului Visual Basic în Excel şi gradul mare de

compatibilitate a acestuia cu dialectele folosite în AutoCAD şi MicroStation V8;

- Tezaurul acumulat de programatorii de Fortran în cei peste 50 de ani de la apariţia acestui

limbaj, tezaur concretizat în imense biblioteci de programe, multe dintre ele uşor accesibile;

- Flexibilitatea şi puterea limbajului AutoLISP ca generator de funcţii de comandă în

AutoCAD menite să lărgească posibilităţile acestuia, şi posibilitatea interfaţării lui uşoare cu

dialectul VBA din AutoCAD.

Page 14: Programarea Calculatoarelor si Limbaje de Programare

Dumitru Dragomir 2

Evident că, prin această alegere, lucrarea nu epuizează domeniul de opţiuni ale

programatorului de aplicaţie inginerească dar poate constitui un ghid pentru formarea unei

orientări corecte.

Pentru a veni în ajutorul cititorului acestei lucrări au fost incluse şi o serie de aplicaţii în

sprijinul materialului de bază.

Autorul îşi exprimă speranţa de a fi putut împărtăşi ceva din experienţa de peste 30 de ani

în programarea aplicativă acelora care au nevoie de îndrumare în acest domeniu.

Autorul

Page 15: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 3

Capitolul 1. Elemente de bază în informatică

§.1.1. Definiţii de bază Informaţia este un mesaj obiectiv (concret) care elimină nedeterminările în cunoaştere. Informaţia variază în funcţie de contextul la care se referă. Se poate vorbi despre: - Natura informaţiei, legată de domeniul la care se referă; - Canalul (sau uneori suportul) informaţiei, reprezentând modalitatea de transmitere a

informaţiei. Orice proces de transmitere a unei informaţii presupune existenţa a doi parteneri: - un emiţător de informaţie; - un receptor de informaţie. Informatica reprezintă un complex de discipline prin care se asigură prelucrarea raţională

a informaţiilor prin intermediul maşinilor automate. Ca urmare a dezvoltării sale ca ştiinţă, informatica este divizată în următoarele subdomenii: - Arhitectura calculatoarelor, disciplină care se ocupă cu organizarea componentelor

fizice (hardware) ale calculatoarelor; - Sisteme de operare, disciplină care se ocupă cu organizarea programelor care

controlează resursele şi acţiunile calculatorului; - Algoritmi şi structuri de date, disciplină care se ocupă cu metodele de obţinere a

aplicaţiilor, reprezentarea informaţiilor, optimizarea aplicaţiilor; - Limbaje de programare, disciplină care se ocupă cu regulile care guvernează notaţiile

de reprezentare a algoritmilor şi structurilor de date; - Ingineria programării, disciplină care se ocupă cu automatizarea şi eficientizarea

activităţilor de proiectare şi realizare a aplicaţiilor; - Calcule numerice şi simbolice, disciplină care se ocupă cu elaborarea de modele

matematice destinate simulării obiectelor şi fenomenelor reale; - Sisteme de gestiune a bazelor de date, disciplină care se ocupă cu organizarea

cantităţilor mari de date; - Inteligenţă artificială, disciplină care se ocupă cu simularea comportamentelor

inteligente; - Animaţie şi robotică, disciplină care se ocupă cu generarea şi prelucrarea imaginilor şi,

respectiv, acţionarea roboţilor. §.1.2. Sisteme de numeraţie În general se vorbeşte despre un "sistem de numeraţie în baza q" ca despre un sistem care

are următoarele caracteristici: 1. Foloseşte un alfabet cu un număr de q simboluri diferite între ele, numite cifre, care

formează un şir de numere consecutive; 2. Prima cifră din şir este 0; 3. Cifra cu valoarea cea mai mare este cu o unitate mai mică decât baza sistemului, deci are

valoarea q-1; 4. În funcţie de poziţia lor în numărul N, cifrele se înmulţesc cu puteri crescătoare ale bazei

q, obţinându-se dezvoltarea numărului N după puterile bazei în forma: N(q) = an an-1 an-2 … a2 a1 a0 = an · qn + an-1 · qn-1 + an-2 · qn-2 + … + a2 · q2 + a1 · q1 + a0 · q0 Notaţia N(q) arată că numărul N este scris în baza q. Iată, mai jos, câteva exemple de sisteme de numeraţie:

Page 16: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 4

Sistemul zecimal, foloseşte alfabetul 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, baza fiind q=10. De exemplu: N(10) = 723(10) = 7 · 102 + 2 · 101 + 3 · 100 = 7 · 100 + 2 · 10 + 3 · 1 Sistemul binar, foloseşte alfabetul 0, 1, baza fiind q=2. De exemplu: N(2) = 1011(2) = 1 · 23 + 0 · 22 + 1 · 21 + 1 · 20 = 8 + 0 + 2 + 1 = 11(10) Sistemul binar este folosit la reprezentarea informaţiei la nivelul de bază al calculatorului,

acolo unde informaţia este tradusă prin mărimi care nu pot avea decât două valori (curentul circulă sau nu circulă, există impuls electric sau nu există, câmpul magnetic are un sens sau sensul contrar, starea logică este adevărat sau fals).

El are avantajul de a reflecta în modul cel mai direct corespondenţa dintre valoarea numerică şi starea datelor (informaţiei) în calculator. Are însă dezavantajul de a necesita la scrierea pe hârtie un spaţiu cu atât mai mare cu cât valoarea reprezentată este mai mare.

Sistemul octal, foloseşte alfabetul 0, 1, 2, 3, 4, 5, 6, 7, baza fiind q=8. De exemplu: N(8) = 125(8) = 1 · 82 + 2 · 81 + 5 · 80 = 64 + 16 + 5 = 85(10) Sistemul hexazecimal, foloseşte alfabetul 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, baza

fiind q=16. De exemplu: N(16) = 2A3B(16) = 2 · 163 + 10 · 162 + 3 · 161 + 11 · 160 = 2 · 4096 + 10 · 256 +3 · 16 + 11 =

= 10811(10) Sistemul hexazecimal a fost conceput pentru a economisi spaţiu de scriere la reprezentarea

numerelor mari. De asemenea, aşa cum se va vedea în continuare, între el şi sistemul binar cu care se află

într-o relaţie de multiplicitate, există o corespondenţă care se poate folosi la conversia dintr-un sistem în altul.

Conversia din baza 2 în baza 16 Acest tip de conversie este des folosit de către programatorii care lucrează direct cu

adresele fizice de memorie pentru a converti valorile numerice dintr-un sistem în altul. Fie numărul binar: 1111(2) = 1 · 23 + 1 · 22 + 1 · 21 + 1 · 20 = 8 + 4 + 2 + 1 = 15(10) Dar 15 este numărul cel mai mare reprezentabil printr-o singură cifră în baza 16, această

cifră fiind F. Aşadar, o grupare de 4 cifre binare poate, folosind diferite combinaţii de 0 şi 1 să

reprezinte o cifră binară din sistemul hexazecimal. În acest caz, pentru un număr oarecare în baza 2, se poate defini o procedură de

convertire la baza 16 după cum urmează: - Se completează numărul binar la stânga cu zerouri până când se obţine un multiplu de 4

al numărului de cifre; - Se separă grupe de câte 4 cifre binare care se convertesc la forma hexazecimală. De exemplu: Fie numărul 101101. Etapele de convertire sunt: - Completarea cu zerouri produce numărul 00101101; - Separarea pe grupe de câte 4 cifre binare produce grupele 0010, cu valoarea zecimală 2 şi

reprezentarea hexazecimală prin simbolul 2, şi 1101 cu valoarea zecimală 13 şi reprezentarea hexazecimală prin simbolul D.

Aşadar numărul 101101(2) = 2D(16)

Page 17: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 5

În practica informatică nu se mai foloseşte notaţia (2) pentru baza binară, dar pentru baza 16 se foloseşte postfixarea cu litera H (de la hexazecimal).

Deci, se obişnuieşte să se scrie: 101101 = 2DH §.1.3. Reprezentarea informaţiei în calculator Forma cea mai simplă sub care se poate reprezenta informaţia, formă numită informaţie

elementară, este evenimentul cu două stări: Adevărat sau Fals. Din punct de vedere electric aceasta corespunde situaţiei unui comutator care se poate afla

într-una din situaţiile din figura 1.3.1.

Închis (curentul circulă), starea logică echivalentă fiind Adevărat;

Deschis (curentul nu circulă), starea logică echivalentă fiind Fals.

Fig.1.3.1 Acestor două stări logice li se asociază valorile numerice: 1 pentru Adevărat, şi 0 pentru Fals. De aici rezultă că sistemul binar ca sistem de numeraţie, este sistemul care se potriveşte cel

mai bine nevoilor de reprezentare a informaţiei în calculator deoarece corespondenţa dintre el şi logica elementară binară este directă.

Informaţia elementară se mai numeşte şi BIT (de la BInary digiT – cifră binară). Bit-ul poate avea stările 0 sau 1 şi mai este denumit atom de informaţie.

BYTE-ul (sau octetul) reprezintă o grupare de 8 biţi şi este o unitate de bază a măsurării cantităţii de informaţie.

Multiplii byte-ului se obţin folosind ca factori de multiplicare: 210 = 1024 byte = 1 Kbyte 220 = 1024 Kbyte = 1 Mbyte 230 = 1024 Mbyte = 1 Gbyte În concluzie, calculatorul este un ansamblu de circuite electronice şi componente mecanice

care poartă denumirea de parte fizică (HARDWARE – parte tare) dar şi un set de programe (metode de prelucrare a informaţiei) şi de date care poartă denumirea de parte logică (SOFTWARE – parte moale).

§.1.4. Codificarea informaţiei în calculator Pentru codificarea informaţiei în calculator se foloseşte codul ASCII (American Standard

Code for Information Interchange – Codul american standard pentru interschimb de informaţii). Acest cod este un cod pe 8 biţi (sau pe un octet). El se împarte în două secţiuni:

- Codul ASCII pentru caractere de bază. Acesta foloseşte numai primii 7 biţi realizând 128 de caractere, dintre care:

= codurile 00H … 1FH (0 … 31) reprezintă caractere de control. De exemplu: 00H NUL; 07H BEL – avertizare sonoră; 09H HT – caracterul TAB – tabulator orizontal; 0DH CR – caracterul Cariage Return – salt la început de rând; 10H DEL – caracterul Delete – ştergerea caracterului curent;

Page 18: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 6

08H BS – caracterul Back Space – ştergerea caracterului anterior; 1BH ESC – caracterul Escape – abandonarea procedurii curente; … etc. = codurile 20H … 2FH, 3AH … 40H, 5BH … 60H, 7BH … 7FH – semne speciale; = codurile 30H … 39H – cifrele 0 … 9; = codurile 41H … 5AH – literele mari ale alfabetului latin; = codurile 61H … 7AH – literele mici ale alfabetului latin; - Codul ASCII pentru setul de caractere extins, foloseşte toţi cei 8 biţi ai octetului

realizând alte 128 de caractere, şi anume: = 48 de caractere străine, cum ar fi: caracterele străine de limba engleză, provenite din alfabetele europene; simboluri monetare – cent, liră, yen, pesetas, franc; semne speciale de punctuaţie; = 48 de caractere pentru construirea de chenare (caractere semigrafice); = 32 de caractere pentru grupul caracterelor ştiinţifice: litere greceşti; simboluri matematice speciale: integrala, ridicarea la pătrat, rădăcina pătrată. §.1. 5. Reprezentarea datelor Data este informaţia prelucrată de calculator. Ea este un model de reprezentare a

informaţiei accesibil unităţii de prelucrare a calculatorului. Din punct de vedere logic, data poate fi reprezentată printr-un triplet de forma:

d=(i, v, a) unde: d = data: i = identificatorul datei; v = valoarea datei; a = atributele asociate datei. Identificatorul datei este un simbol (nume) asociat datei pentru a o distinge de alte date şi

pentru a se putea face referiri la ea în timpul procesului de prelucrarea a datelor. În cazul bazelor de date simple constând dintr-o simplă enumerare a unor date din aceeaşi familie (de acelaşi tip), identificatorul poate fi subînţeles, confundându-se cu indicele numeric al datei în bază. Necesitatea unui identificator (simplu sau compus) apare în bazele de date complicate conţinând date de naturi diferite şi/sau cu structurare pe mai multe nivele, eventual cu apartenenţă la diferite clase de apartenenţă (sau cu proprietari diferiţi).

Valoarea datei este proprietatea datei de a fi exprimabilă într-un sistem de unităţi de măsură şi într-un anumit domeniu de valori. Datele pot fi variabile (modificabile în timpul execuţiei programului) sau constante (nemodificabile).

Atributele datei sunt proprietăţi ale datei care determină modul în care ea poate fi tratată în cursul procesului de prelucrare.

Ca exemple de atribute se pot menţiona: - tipul datei: = tip numeric (întreg sau real); = tip logic (valorile adevărat sau fals); = tip alfanumeric (caractere sau şiruri de caractere). - precizia reprezentării interne, este legată de capacitatea limitată de stocare a unei date de

un anumit tip numeric. Astfel, pot exista: = date numerice reale în simplă precizie;

Page 19: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 7

= date numerice reale în dublă precizie (stocate într-o zonă de memorie de lungime dublă).

Reprezentarea datelor alfanumerice (caractere) Pentru reprezentarea datelor alfanumerice se foloseşte codul ASCII. De exemplu, caracterul A având codul hexazecimal 41H are codul binar 01000001 iar

caracterul a are codul hexazecimal 61H sau în binar 01100001. Toate aceste caractere necesită un singur octet pentru a fi reprezentate.

Reprezentarea numerelor În funcţie de tipul lor, numerele pot fi reprezentate în cadrul următoarelor convenţii: A. Reprezentarea numerelor întregi fără semn. Aici se pot deosebi următoarele cazuri:

= Reprezentarea pe un singur octet. În acest sistem pot fi reprezentate numere între valorile binare 00000000 şi 11111111 respectiv de la 00H până la FFH, adică între 0 şi 255; = Reprezentarea pe doi octeţi, de la 0000H până la FFFFH, adică de la 0 la 65535.

B. Reprezentarea numerelor întregi cu semn. Aici se deosebesc două cazuri: a. Reprezentarea prin mărime şi semn (reprezentare în cod direct). În această convenţie se foloseşte bitul de rang cel mai înalt ca indicator de semn, cu semnificaţiile: 0 – nu există semn, adică numărul este pozitiv, şi 1 – există semn, adică numărul este negativ. Folosind un singur octet (byte), bitul 7 este folosit ca indicator de semn iar biţii 6,5,…,1,0 sunt folosiţi pentru reprezentarea directă a valorii numărului. De exemplu codul binar 11111111 reprezintă numărul –127 iar codul binar 01111111 reprezintă numărul +127 Dezavantajul acestui sistem este acela că naşte o ambiguitate şi anume numărul 0 are două reprezentări, adică 00000000 pentru + 0 şi 10000000 pentru – 0. Din acest motiv, cât şi din altele, apar dificultăţi la modelarea operaţiilor matematice cu ajutorul circuitelor electronice, fiind necesare două proceduri aritmetice diferite: una pentru adunare şi alta pentru scădere, plus o procedură de identificare a semnului pentru a se lua decizia privind procedura aritmetică de aplicat. De aceea se preferă o adoua variantă, şi anume: b. Reprezentarea numerelor negative în cod complementar faţă de 2. Fie Nn un număr întreg nenegativ reprezentat prin n cifre binare. Complementul faţă de 2 al lui Nn este nN :

nNn2nN −= De exemplu, fie numărul 10 şi numărul –3. Ele se reprezintă astfel: 10 = 00001010 (reprezentare directă) -3 = 28 – 00000011 = 100000000 – 00000011 011111101 complementul faţă de 2 al numărului 3 În acest caz, operaţia 10 + (-3) este: 00001010 + 11111101 100000111 Se neglijează bitul de rangul 8 (al nouălea bit, cel care a rezultat 1) şi rezultă numărul binar 00000111 adică numărul zecimal 7. Se observă că prin acest procedeu se

Page 20: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 8

foloseşte o singură operaţie de adunare directă, atât la adunare cât şi la scădere. În concluzie, cu ajutorul a n cifre binare se pot reprezenta numere întregi N în domeniul: -2n-1 ≤ N ≤ 2n-1 - 1 Aşadar: - numerele întregi cu semn reprezentabile pe 1 octet (pe 8 biţi) se pot reprezenta în intervalul: - 28-1 = 27 = - 128 ≤ N ≤ 28-1 – 1 = 127 - numerele întregi cu semn reprezentabile pe 2 octeţi (pe 16 biţi) se pot reprezenta în intervalul: - 216-1 = 215 = - 32768 ≤ N ≤ 216-1 – 1 = 32767 - numerele întregi cu semn reprezentabile pe 4 octeţi (pe 32 biţi) se pot reprezenta în intervalul: - 232-1 = 231 = - 2147483648 ≤ N ≤ 232-1 – 1 = 2147483647

C. Reprezentarea numerelor reale în virgulă mobilă. Această reprezentare se inspiră din reprezentarea numerelor zecimale în notaţie ştiinţifică. De exemplu, în notaţie ştiinţifică, numărul 12.5 se poate scrie: 12.5 = 125 · 10-1 = + 125 E –1 La ultima formă de scriere se disting : - un simbol pentru semnul numărului (+ sau minus); - mantisa – în acest caz 125; - semnul exponentului (aici -); - valoarea exponentului (aici 1). În cazul unei reprezentări pe 4 octeţi (32 de biţi) se folosesc: 1 bit pentru semnul numărului, cu valoarea 0 pentru plus şi 1 pentru minus; 1 bit pentru semnul exponentului; 7 biţi pentru valoarea exponentului; 23 biţi pentru mantisă. Harta repartiţiei biţilor în cuprinsul cuvântului (grupului) de 4 octeţi este următoarea:

Sem

n nu

măr

Se

mn

expo

nent

Valoarea

exponentului

Valoarea mantisei

Aşadar, mărimea numărului reprezentat în virgulă mobilă şi precizia reprezentării lui

depind de număril de octeţi pe care se face reprezentarea. Ca şi în cazul numerelor întregi, şi la numerele în virgulă mobilă există posibilitatea

stocării pe lungimi extinse (dubla precizie). D. Reprezentarea numerelor reale în virgulă fixă. Am lăsat intenţionat la urmă această modalitate de reprezentare. Aici se presupune

existenţa imaginară a unei virgule care desparte numărul de biţi folosiţi în două grupuri, unul pentru partea întreagă şi altul pentru cea fracţionară. Pe lângă faptul că acest mod de

Page 21: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 9

reprezentare crează complicaţii constructive, modelul de reprezentare variind la diferite calculatoare, domeniul de variaţie al numerelor este mult mai restrâns iar precizia de reprezentare nu este nici pe departe satisfăcătoare, şi din acest motiv în prezent nu mai este folosit.

Reprezentarea altor tipuri de date. Imaginile şi sunetele pot constitui şi ele stocuri de date. În acest caz există două căi

principiale de reprezentare: A. Prin coduri de definiţie, reprezentând combinaţii de caractere alfanumerice şi coduri

numerice. De exemplu, într-o bază de date, o combinaţie de valori numerice de forma: frecvenţă (în cicli/secundă), durată (în milisecunde) poate constitui codificarea unui sunet, ca mai jos: 1000, 2000 care ar putea însemna definirea unui sunet cu frecvenţa de 1000 Hz cu o durată de 2

secunde Pentru imagini, o combinaţie de forma: LINE 0, 0, 12, 5 ar putea semnifica trasarea unei linii între punctele de coordonate x=0, y=0 şi x=12, y=5,

pe un ecran pentru care, anterior, a fost stabilită o zonă de lucru şi o scară de reprezentare. B. Prin digitizare, care înseamnă transformarea datelor de stocat în succesiuni de biţi

codificate după anumite reguli. De exemplu, pentru imagini este foarte frecvent folosit formatul de stocare BMP (BitMaP

sau hartă de biţi). §.1. 6. Structura fizică (hardware) a unui calculator

Module de interfaţă cu consola

CD HDDFloppy Display Tastatură

Extensie de magistrală Magistrală

Module de interfaţă serială

Module de interfaţă paralelă

Module de interfaţă cu discurile

RAMROMCPU

Fig.1.6.1

Pe blocuri funcţionale principale, calculatorul prezintă următoarele componente principale: - CPU (Central Processing Unit) – unitatea centrală de prelucrare, este partea din

calculator care coordonează şi controlează toate funcţiile de transfer şi prelucrare a semnalelor electrice care reprezintă comenzi şi date. Ea identifică instrucţiunile dintr-un program, execută operaţii aritmetice şi activează circuitele electronice anexă cărora le transmite ordine de activitate prin intermediul magistralei;

- Magistrala, reprezintă un fascicol de n×8 conductori electrici paraleli (n=1,2,4,8) pe care circulă semnalele electrice care reprezintă comenzi şi date;

Page 22: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 10

- Memoria calculatorului, este de două tipuri: = ROM (Read Only Memory) – memorie care poate fi numai citită. Aceasta este

memoria permanentă care nu se şterge la oprirea calculatorului. Ea conţine un set de programe de bază care se execută la pornirea calculatorului, ajutând la iniţializarea modului său de funcţionare;

= RAM (Random Access Memory) – memorie cu acces aleatoriu. Aceasta este memoria dinamică, adică o memorie din care se poate citi dar se poate şi scrie. Ea se şterge la oprirea calculatorului, motiv pentru care se mai numeşte şi memorie volatilă. În această zonă de memorie se încarcă programele care se execută în timpul funcţionării calculatorului. De asemenea, această memorie poate servi şi ca stoc temporar pentru acele date cu frecvenţă mare de utilizare, pentru a se economisi timp când este necesară folosirea acestor date;

- Modulele de interfaţare cu dispozitivele periferice. În această categorie intră următoarele dispozitive:

= modulele de interfaţă cu consola. Consola este dispozitivul de intrare/ieşire standard al calculatorului (care nu poate lipsi), format din tastatură ca dispozitiv de intrare (introducere a datelor) şi display ca dispozitiv de ieşire (extragere a datelor). În aceste module se include şi placa grafică, conţinând memoria video care deserveşte ecranul; = modulele de interfaţă cu discurile. Discurile sunt destinate stocării permanente a informaţiei. Accesul la ele se face pe cale magneto-mecanică (pentru discurile magnetice), mecanico-optică (pentru compact discuri). Deoarece intervine o componentă mecanică, accesul al informaţia stocată pe aceste discuri se realizează mult mai lent mult mai lent decât la memoria electronică (RAM) dar capacitatea de stocare este mult mai mare iar informaţia nu se şterge la oprirea calculatorului, motiv pentru care discurile sunt folosite pentru stocarea permanentă a informaţiei. Pe discuri se poate atât citi cât şi scrie (cu excepţia CD-urilor din categoria celor nerescriptibile). Discurile magnetice sunt de două tipuri: Floppy-discuri, de capacitate mică, circa 1,44 MB, dar portabile; Hard-discuri, de capacitate foarte mare, 10-20 GB sau mai mari, dar neportabile. Unităţile de citire corespunzătoare pentru aceste discuri sunt: FDD (Floppy Disk Drive) la care discul este amovibil (extractabil din unitate); HDD (Hard Disk Drive) la care discul este intern, inamovibil. =modulele de interfaţă paralelă şi serială. Interfaţa paralelă se realizează prin cabluri care conţin în principal 8 conductori pentru date şi alţi câţiva conductori pentru semnale de control şi sincronizare. Datele sunt transmise în serii de câte 8 biţi în paralel; Interfaţa serială se realizează prin cabluri care, în afara conductorilor pentru semnale de control şi sincronizare, conţin un singur conductor pentru date. Informaţia se transmite în trenuri de câte 8 impulsuri succesive, cîte unul pentru fiecare bit de informaţie.

- Extensia de magistrală, este o prelungire a magistralei, conductorii acesteia fiind conectaţi la o serie de "slot-uri" (socluri speciale) pe care se pot implanta (plug) alte module de interfaţare suplimentare, de exemplu cele pentru obţinerea sonorizărilor (placa de sunet), pentru comunicaţia telefonică (fax-modem), sau pentru conectarea în reţea (plăci de reţea).

Microprocesorul La calculatoarele moderne blocul CPU a fost realizat sub forma unui singur circuit integrat

denumit microprocesor. Istoric, primul microprocesor a fost realizat de firma INTEL sub numele de Intel 8008. A

Page 23: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 11

urmat apoi microprocesorul Intel 8080 având un set de instrucţiuni extins. Curând după aceea, firma ZILOG a realizat microprocesorul Z80 cu un set de instrucţiuni şi mai mare, circa dublu decât Intel 8080.

Toate aceste microprocesoare erau structurate pe 8 biţi şi puteau adresa o memorie de 64 KB, iar Z80 putea adresa succesiv mai multe blocuri de memorie de câte 64 KB denumite pagini de memorie.

În anul 1981 apare microprocesorul 8088 pe 16 biţi, eveniment care decalnşează evoluţia microprocesoarelor din familia 80x86, unde x=2, 3, 4, 5 (Pentium).

Au existat microprocesoarele simbolizate astfel: 80386SX – fără coprocesor matematic încorporat, şi 80386DX – cu coprocesor matematic încorporat. Coprocesorul matematic este un circuit separat sau încorporat în microprocesor care

realizează în mod hard operaţiile matematice, mult mai rapid decât în cazul realizării lor în mod soft (prin program).

Când microprocesorul nu conţinea coprocesorul matematic, acesta se putea adăuga pe placa de bază a calculatorului într-un soclu special prevăzut. În acest caz coprocesorul avea simbolizarea 80x87, de exemplu 80287 adăugabil la microprocesorul 80286, sau 80387 adăugabil la microprocesorul 80386.

Când simbolizarea microprocesorului era postfixată cu o cifră, aceasta semnifica dublarea sau triplarea frecvenţei sale de lucru. De exemplu, 80486SX2 sau 80486DX2 lucrau la frecvenţă dublă faţă de 80486SX sau 80486DX, iar 80486DX4 la frecvenţă triplă faţă de 80486DX.

Noua familie de microprocesoare poate accesa o memorie mult mai mare, de exemplu: 8086 până la 1MB de RAM 80286 până la 16MB de RAM 80386 şi 80486 până la 4GB de RAM. Totuşi, calculatoarele construite cu microprocesoare de acest tip nu fac uz, deocamdată,

decât de o mică parte a posibilităţilor lor de accesare de memorie RAM deoarece folosirea integrală a acestei capacităţi ar conduce la arhitecturi cu complicaţii atât în privinţa gabaritului cât şi a timpului de utilizare a întregii capacităţi de memorie.

Structura (fără detaliere) a microprocesorului este cea din figura 1.6.2. - UCC este Unitatea de Comandă şi Control. Ea are funcţiile: = extrage din memoria internă a calculatorului o instrucţiune a programului; = decodifică instrucţiunea pentru a afla ce operaţie trebuie executată şi ce date vor fi folosite; = extrage datele din memoria internă a calculatorului; = activează circuitele corespunzătoare din UAL pentru a executa operaţia cu datele solicitate. - UAL este Unitatea Aritmetico – Logică. Ea are funcţiile evidenţiate în figura 1.6.2. - Registrele proprii. Acestea sunt circuite de memorie conţinute de microprocesor. În

aceste registre sunt păstrate temporar înformaţiile care conţin datele de prelucrat şi instrucţiunile de executat.

Există următoarele tipuri de registre: = registru de date: păstrează datele de prelucrat şi rezultatele prelucrării; = registru de instrucţiuni: păstrează codul instrucţiunii în curs de execuţie; = registru contor de program: păstrează adresa instrucţiunii care urmează să se execute; = registru contor de date: păstrează adresa la care se găsesc datele care urmează să fie prelucrate. - UI este Unitatea de Interfaţă cu celelalte componente ale calculatorului. Ea asigură,

prin intermediul magistralei, legătura dintre microprocesor şi celelalte componente ale calculatorului: memoria internă şi sistemul de intrare/ieşire. Tot ea realizează şi funcţia de transfer a datelor de la/către microprocesor.

Page 24: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 12

Microprocesor

UAL

UCC

Memoria internă

Registre

Comparare

Adunare

Împărţire

Înmulţire

Scădere

Extragere de date

Extragere de instrucţiuni

Decodificarea instrucţiunii

Fig.1.6.2.

Microprocesorul funcţionează pe baza impulsurilor (tacturi) primite de la un oscilator

(sau ceas – clock). Feacvenţa impulsurilor poate fi una din valorile standard: 6, 12, 16, 25, 33, 40, 55, 66 MHz (sau mai mari). Cu cât frecvenţa de tact este mai mare, cu atât calculatorul este mai rapid.

Memoria internă a calculatorului Memoria internă a calculatorului are structura din figura 1.6.3.

Extensii de memorie Memoria expandată

Memoria de bază 640 KB

Fig.1.6.3. Componentele ei sunt următoarele: - Memoria de bază, de 640 KB, corespunde memoriei maxime de care dispuneau primele

calculatoare compatibile IBM-PC (începând cu microprocesorul 8086) pentru care a fost dezvoltat sistemul de operare DOS.

Aceasta este memoria de lucru care preia datele şi instrucţiunile din programe pentru execuţie şi în care se depun rezultatele;

- Memoria expandată, de 384 KB, care a fost adăugată ulterior pentru a mări posibilităţile de lucru;

- Extensii de memorie, care reprezintă memoria internă suplimentară celor 1084 KB (1 MB) aflată în configuraţia de bază a calculatorului. Ea este folosită pentru stocarea datelor programelor.

Page 25: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 13

Memoria virtuală a calculatorului Această memorie nu există din punct de vedere fizic în acelaşi mod ca memoria internă,

deci nu ca spaţiu de memorie realizat prin circuite electronice. Ea este un spaţiu rezervat pe hard disc, văzută şi exploatată de calculator asemănător cu

memoria RAM. Periodic, între memoria internă şi cea virtuală, se face un transfer de date astfel: - porţiuni de program şi de date care temporar nu vor mai fi folosite, sunt transferate pe discul

dur, eliberând memoria RAM pentru acele părţi de informaţie care trebuie accesate rapid; - porţiunile de progrm şi de date care urmează să intre în uz sunt citite de pe discul dur şi

sunt stocate în RAM pentru execuţie şi prelucrare; - porţiunile de program şi de date devenite inutile sunt şterse, după caz, fie din RAM fie de

pe hard disc. Memoria CMOS La calculatoarele mai recente a fost adăugat un nou tip de memorie care poate fi scris şi

citit ca şi memoria RAM, dar care nu se şterge la oprirea calculatorului. Acest lucru este posibil deoarece acest tip de circuite are un consum extrem de scăzut şi poate fi menţinut activ şi după oprirea calculatorului prin alimentarea de la un acumulator care se reîncarcă în timpul funcţionării calculatorului. În această memorie se stochează:

- configuraţia calculatorului; - data calendaristică; - ora; - parola de acces; - etc. Totuşi, deoarece până la urmă orice acumulator se descarcă, pentru a nu se pierde datele

stocate în acest tip de memorie trebuie respectate următoarele măsuri: - periodic, fie şi numai pentru câteva minute, calculatorul trebuie pornit; - acumulatorul nu trebuie demontat de pe placa de bază şi nu trebuie scurtcircuitat. Memoria cache Acest tip de memorie este folosit începând de la microprocesorul 80386. El are valorile

standard de 64, 128, 256 şi 512 KB şi serveşte ca stoc tampon separat pentru microprocesor, îmbunătăţindu-i performanţele.

§.1.7. Structura operaţională a unui sistem de calcul

Succesul sistemelor de calcul moderne are la bază folosirea interactivităţii grafice ca instrument de lucru de bază.

Grafica interactivă poate fi definită ca fiind totalitatea metodelor şi tehnicilor de introducere, extragere şi conversie a informaţiei spre sau de la echipamentele specifice tehnicii de calcul, astfel construite încât, pentru operatorul uman, informaţia să aibă caracter grafic.

Sistemul grafic este un ansamblu format din echipamente şi programe specializate în tratarea şi reprezentarea grafică a informaţiei.

Prin aceste caracteristici ale sistemelor de calcul cu interacţiune grafică operaţiile pe care le execută operatorul au un caracter natural, sunt rapid executabile, recunoaşterea informaţiilor furnizate de calculator fiind rapidă şi comodă.

Pentru realizarea acestui obiectiv, sistemul de calcul este prevăzut cu o serie de dispozitive periferice specializate.

Page 26: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 14

O

Memorie externă

Relaţie vizuală Relaţie tactilă

Printer

Plotter

Display

Relaţie externă (conectare la reţea)

Unitate centrală

Video cameră Scanner

Tabletă grafică

Digitizoare

Light-pen

Interceptor

Controlere de cursor grafic

Track-ball

Joy-stick

Mouse

Tastatură

Operator

Fig.1.7.1.

Page 27: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 15

Structura fizică a unui sistem de calcul este cea reprezentată în figura 1.7.1. Conform acesteia schimbul de informaţii dintre operator şi unitatea centrală se desfăşoară pe două laturi: Relaţia tactilă şi Relaţia vizuală. Fiecare dintre ele este deservită de o serie de dispozitive periferice de intrare/ieşire. Componentele evidenţiate sunt descrise mai jos.

Relaţia tactilă, este cea comandată de operator, prin care acesta introduce informaţie în calculator. Ea se realizează prin următoarele dispozitive de intrare: - Tastatura – este dispozitivul de intrare minimal, absolut necesar pentru introducerea

textelor comenzilor şi a datelor numerice sau de tip şir de text; - Controlerul de cursor grafic este o denumire generică pentru unul dintre următoarele

dispozitive de intrare: = Mouse – este un dispozitiv care controlează mişcarea cursorului grafic pe ecran prin controlul deplasărilor pe direcţiile x-y ale ecranului. Acest dispozitiv este complementar tastaturii. Serveşte şi la introducerea poziţiilor în care se punctează pentru a declanşa comenzi dependente de poziţia de aplicare a punctării (clic); = Joy-stick – este un dispozitiv care controlează direcţia şi viteza de mişcare a cursorului prin unghiul de înclinare al unei manete; = Track-ball – este de fapt un mouse răsturnat, operatorul acţionând direct asupra bilei.

- Interceptorul, concretizat prin creionul optic (light-pen) serveşte la interceptarea pe ecran a unei zone de interes;

- Digitizorul, este folosit pentru a transforma o informaţie grafică externă în informaţie digitală stocabilă în memoria calculatorului. Se folosesc în mod curent următoarele dispozitive: = Tableta grafică – serveşte la transformarea mişcării de urmărire manuală a unui contur existent pe hârtie sau de desenare a unui asemenea contur, într-o succesiune de puncte reprezentate prin coordonate x,y exprimate numeric (evident în cod binar) constituind o informaţie de tip vectorial (succesiune de segmente orientate definite prin capetele lor); = Scannerul şi camera video citesc o imagine punct cu punct, primul de pe hârtie iar cea de a doua în mod direct. Informaţia generată este de tip raster (matrice constituită din linii şi coloane de puncte ale imaginii); Relaţia vizuală, este cea prin care operatorul primeşte informaţiile prelucrate de

calculator. Ea se realizează prin următoarele dispozitive de ieşire: - Display – este dispozitivul de afişare minimal. Poate fi de diferite tipuri dintre care

menţionăm tubul catodic sau matircea de afişare cu cristale lichide; - Plotter – este un dispozitiv de desenare cu peniţă sau de tăiere cu cuţit (cutter).

Materializează desene de tip vectorial, adică compuse din succesiuni de vectori (segmente orientate);

- Printer – este un dispozitiv de imprimare sub formă raster (matrice de puncte). Uneori, prin abuz de limbaj, se foloseşte termenul de plotter pentru printere de dimensiuni mari, dar această utilizare nu este corectă şi nu este recunoscută de dicţionarele de termeni informatici.

§.1.8. Organizarea funcţională a unui sistem de calcul Conform figurii 1.8.1, funcţia principală a unui sistem de calcul este aceea de memorare,

prelucrare şi regăsire a datelor. În raport cu staţia de lucru ca sistem de intrare/ieşire a informaţiilor, utilizatorul operează asupra datelor din sistem, în cadrul interacţiunii la staţia de lucru, prin intermediul funcţiilor de introducere a datelor (folosind ca periferice de intrare tastatura, mouse-ul, tableta grafică, etc) şi a funcţiei de afişare a datelor prin intermediul display-ului.

Page 28: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 16

O

Interacţiune la staţia de

lucru

Utilizator

Ieşire în format direct citibil

Ieşire în format maşină

Staţie de lucru

Post procesareBaza de

date

Memorare asociativă

Regăsire asociativă

Analiză

Introducere date

Afişare date

Memorare-prelucrare-regăsire

Fig.1.8.1.

În cadrul sistemului, în raport cu baza de date care stochează datele de o anumită natură asociate entităţilor memorate în baza de date, se evidenţiază:

- Funcţia de memorare asociativă care introduce datele în baza de date după ce efectuează prelucrările necesare asocierii dintre datele care descriu entităţile stocate în bază şi atributele care caracterizează aceste entităţi. Asocierea se face pe baza unei reguli de asociere stabilită în funcţie de structura bazei de date, şi în concordanţă cu necesităţile de definire a entităţii de stocat în bază. De exemplu, o mingie de tenis poate fi descrisă ca o sferă cu o anumită rază, dar această informaţie nu este suficientă. Ea trebuie asociată cu poziţia ei în raport cu un reper (de exemplu solul pe care eventual se poate lua în considerare proiectarea unei umbre). Dacă programul grafic are în vedere şi redarea aspectului fotografic al mingiei, informaţia privitoare la geometria şi poziţia acesteia trebuie însoţită şi de informaţia privind materialul din care ea este făcută. Alte informaţii, necesare aspectualizării fotografice, pot defini o sursă de lumină descrisă ca punctuală la distanţă finită (bec) sau la distanţă infinită (soare), cu o anumită intensitate luminoasă şi având o anumită culoare. Aceste din urmă informaţii (intensitatea şi culoarea) sunt atributele (la rândul lor date) asociate datelor despre sursa de lumină.

Un alt exemplu este acela al asociaţiei care este necesar a fi stabilită între denumirea unui produs ca identificator şi costul şi cantitatea de produs existentă în stoc, pentru ca gestiunea corectă a stocurilor de produse şi a valorilor lor să poată fi efectuată

- Funcţia de regăsire asociativă este într-un fel inversul funcţiei de memorare asociativă şi este necesară pentru a direcţiona în mod selectiv datele către modulul de afişare, dacă sunt cerute acolo informaţii despre anumite elemente din baza de date dorite, sau către modulul de analiză care efectuează calculele reclamate de anumite cerinţe ale aplicaţiei. Această funcţie se desfăşoară pe baza regulilor de dependenţă din cadrul bazei de date.

- Funcţia de analiză constă din totalitatea procedeelor de prelucrarea a informaţiei din baza de date, dintre aceste procedee de prelucrare selectându-se metoda adecvată tipului de informaţie de tratat. De exemplu, un set de date de forma dimensiune-poziţie ar putea defini latura unui pătrat şi poziţia în plan a centrului acestuia, dar ar putea defini şi raza unui cerc şi

Page 29: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 17

poziţia în spaţiu a centrului lui. În funcţie de atributul de tip asociat care indică dacă este vorba de pătrat sau de cerc, este selectat programul de desenare adecvat.

-Funcţia de post-procesare realizează conversia datelor de la forma de reprezentare în baza de date la o formă adecvată unei alte utilizări decât cea curente. Ea se aplică cel mai adesea în situaţiile în care informaţia stocată în baza de date este necesară altor programe aplicative decât aceluia care le-a generat. Aşa este cazul elaborării informaţiilor necesare pentru comanda maşinilor unelte cu comandă program sau dispozitivelor de afişare grafică pe hărtie. După caz ieşirea datelor de post-procesare se poate face în format maşină sub forma unor fişiere cu un anumit format de scriere, stocate pe suport magnetic (dischete sau bandă magnetică) sau pe suport optic (CD-ROM), sau în format direct citibil, adică în formă grafică sau text.

§.1.9. Dispozitive periferice Dispozitivele periferice sunt dispozitivele ataşate calculatorului cu rolul de a realiza

operaţiile de intrare/ieşire în şi din calculator a informaţiilor. 1.9.1. Dispozitive de intrare Tastatura Tastatura este dispozitivul de intrare standard prin care utilizatorul trimite comenzi

calculatorului sub forma unui şir de caractere. Fiecare caracter este generat la apăsarea unei taste sau combinaţie de taste. Tastatura conţine 4 blocuri de taste, ca în figura 1.9.1.

5

3

2

1

4

Fig.1.9.1.

1 – tastatura alfanumerică. Ea conţine:

- caracterele numerice: 0, 1, 2, … , 9 - caracterele literale: a, … , z şi A, … , Z - semne de punctuaţie şi speciale: . , ! ? … $ & % etc - bara spaţiu (space bar) - taste de comandă:

= tasta Enter – care produce succesiunea de caractere CR (carriage return – salt la început de rând) şi LF (line feed – începerea unei linii noi) = tasta Tab – saltul cursorului cu un anumit număr de caractere pe orizontală către dreapta = tasta Backspace pentru ştergerea caracterului de la stânga cursorului

2 – tastatura de editare. Aceasta conţine: - tastele direcţionale simbolizate prin săgeţile ← ↑ → ↓ servind la deplasarea cursorului în pagina de text cu câte o poziţie în sensurile indicate - tastele Page Up şi Page Down pentru deplasarea cursorului cu o pagină de text ecran în sus şi în jos

Page 30: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 18

- tastele Home şi End pentru deplasarea cursorului la începutul şi la sfârşitul textului - tasta Delete pentru ştergerea caracterului curent la programele editoare de text cu cursor de subliniere sau a caracterului de la dreapta la programele cu cursor de inserare - tasta Insert pentru comutarea modului de scriere a caracterelor din modul inserare în modul suprascriere şi invers

3 – tastatura numerică. Aceasta conţine cifrele 0, 1, 2, … , 9 şi semnele operatorilor aritmetici / * - + 4 - blocul tastelor funcţionale care conţine

- tasta Esc – abandonarea unei proceduri sau întreruperea executării unui program - tastele F1 … F12 asociate prin program anumitor comenzi - tasta Print Screen pentru intercepţii de imagine de pe ecran (iar în sistemul DOS şi pentru copierea la imprimantă a ecranului interceptat) - tasta Pause/Break pentru suspendarea executării unui program

5 – Led-uri pentru semnalizarea diferitelor stări de funcţionare. Tastele menţionate mai sus emit de regulă un caracter fiind denumite "taste calde". În afara lor există şi o serie de alte taste cunoscute sub denumirea de "taste reci" care nu

emit caractere dar care, dacă sunt apăsate în timp ce se apasă o tastă caldă schimbă caracterul emis aceasta. Acesta este cazul tastelor Shift, Ctrl şi Alt.

De exemplu: Shift + A generează A pe când numai A generează a, dacă Caps Lock nu este activă. Tastele comutatoare sunt taste care comută regimul de funcţionare al altor taste. Aici se

deosebesc: - tasta Caps Lock care, când aste apăsată comută de pe litere mici pe litere mari şi invers De exemplu, cu Caps Lock activat, Shift + A generează a - tasta Num Lock care comută tastatura numerică în tastatură de editare - tasta Insert pentru comutarea modului de scriere a caracterelor din modul inserare în modul suprascriere şi invers Dispozitivul mouse Mouse-ul este folosit pentru controlul cursorului grafic afişat pe ecran ca şi pentru

selecatrea unor obiecte grafice. Operaţiile posibile cu ajutorul mouse-ului sunt: - indicare prin poziţionarea cursorului prin deplasare; - clic, constând din apăsarea scurtă a unui buton al mouse-ului; - dublu clic, constând din dubla apăsare a butonului stânga la interval de timp scurt; - antrenare (drag and drop) constând din deplasarea mouse-ului cu butonul stânga apăsat. Scanner-ul Scannerul este un dispozitiv de introducere în calculator prin digitizare a imaginilor afşate

pe un suport bidimensional (pe hârtie). Digitizarea constă aici din citirea imaginii punct cu punct. Punctele citite sunt considerate aşezate sub forma unei reţele dreptunghiulare de careuri elementare de suprafaţă. Fiecare punct este descris printr-un un set de coduri numerice binare care descriu intensitaţile culorilor elementare componente. Un scanner se caracterizează prin:

- Rezoluţie, sau număr de puncte pe unitatea de lungime. De exemplu 300 dpi (dots per inch = puncte pe ţol):

- număr de culori discernute; - viteză de scanare; - suprafaţa maximă scanabilă.

Page 31: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 19

1.9.2. Dispozitive de ieşire Display-ul Generalităţi, tipuri constructive Display-ul sau dispozitivul de afişare (sau ecran, sau monitor) este dispozitivul de ieşire

standard al calculatorului care, împreună cu tastatura, compun ansamblul denumit consolă care, la unele calculatoare alcătuiesc un singur bloc constructiv (denumirea de consolă este moştenită de la vechile staţii de afişare care erau construite astfel).

Display-ul este controlat de un bloc electronic denumit placă video, al cărei rol este de a transforma informaţia binară primită de la microprocesor în semnalele electronice necesare afişării imaginii pe ecran (screen).

6Faza II

42

1234

135

Faza I

Fig.1.9.2. Fig.1.9.3.

Imaginea poate fi afişată în două moduri: - neîntreţesut (noninterlaced). Acest mod de afişare constă din afişarea pe ecran a liniilor

de imagine componente în mod succesiv, adică în ordinea 1, 2, 3, … , etc: - întreţesut (interlaced). La acest mod de afişare se deosebesc două faze:

= faza I (figura 1.9.2), în care sunt afişate succesiv toate liniile de indice impar: 1, 3, 5, … , etc; = faza II (figura 1.9.3), în care sunt afişate succesiv toate liniile de indice par: 2, 4, 6, … , etc.

Acest mod de afişare are ca efect atenuarea efectului de pâlpâire a imaginii pe ecran, uşurând solicitarea vizuală a utilizatorului şi este recomandat la afişarea imaginilor dinamice.

Din punct de vedere constructiv se deosebesc următoarele tipuri de display-uri: - display-uri pentru calculatoare de birou construite cu tub cinescopic; - display-uri pentru calculatoare portabile construite ca ecrane plate cu cristale lichide sau

cu plasmă; - display-uri pentru afişare pe ecran de proiecţie (sistem retroproiector sau proiector cu

rază laser dirijată); Organizarea suprafeţei de afişare a ecranului Display-ul poate funcţiona în două moduri principale: Modul video text, caracteristic sistemului de operare DOS. Acest mod de afişare consideră ecranul împărţit într-o reţea de dreptunghiuri, fiecare dintre

ele fiind capabil să afişeze câte un singur caracter tipăribil, ca în figura 1.9.4. Reţeaua de dreptunghiuri este constituită dintr-o succesiune verticală de linii orizontale, pe

fiecare linie existând acelaşi număr de dreptunghiuri aliniate pe verticală pe coloane. Un dreptunghi de afişare a unui caracter este o matrice de puncte de imagine (pixeli). Fiecare pixel este privit ca o arie elementară (careu) de imagine. Trebuie făcută o precizare. După cum se observă în dreapta figurii 1.9.4, fiecare pixel de

imagine poate fi codificat pe un singur bit prin valorile 0 şi 1 (stins respectiv aprins).

Page 32: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 20

Codificarea întregii matrici de pixeli este stocată undeva în memoria gestionată direct de sistemul de operare DOS şi nu este de competenţa programatorului să aibă acces la această zonă. Întreaga matrice de pixeli a caracterului este privită ca un bloc de date care are asociat ca identificator codul ASCII al caracterului.

caracte

coloana coloana 1 linia 25

linia 1

pixel pixel

Fig.1.9.4.

BGRLBGR BL

BG C

FG

Fig.1.9.5. Când se emite ordinul de afişare a unui caracter, în asociere cu codul ASCII al caracterului

se mai trimite şi un byte (octet) în care este conţinut codul de afişare al caracterului, care determină cum va avea loc afişarea.

Această codificare are structura din figura 1.9.5. Cei 8 biţi ai octetului sunt folosiţi astfel: Bitul 7 (BL – Blinking = clipire) are semnificaţiile: 0 – caracterul nu clipeşte şi 1 –

caracterul clipeşte; Biţii 6, 5 şi 4 determină combinaţia de culori fundamentale ale fondului BG (BackGround):

R (Red = roşu), G (Green = verde) şi B (Blue = albastru), fiecare putând avea valorile 0 – componentă lipsă sau 1 – componentă prezentă;

Bitul 3, notat cu L de la Light (luminos) este rezervat tonalităţii culorii caracterului (simbolizarea FG este pentru ForeGround – partea de deasupra fondului): 0 – culoare normală şi 1 – culoare strălucitoare;

Biţii 2, 1 şi 0 codifică componentele de culoare RGB ale caracterului. Obs: notaţiile BG şi FG nu sunt standard. Ele au fost folosite aici pentru economie de

scriere. În consecinţă, caracterul poate avea 16 culori iar fondul poate avea numai cele 8 culori

nestrălucitoare, conform tabelului 1.9.1. Aşadar, memorarea caracterului în modul text se face pe 2 octeţi, ca în figura 1.9.6. Din aceste considerente, memoria necesară pentru memorarea unui ecran de text se poate

calcula cu relaţia:

Page 33: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 21

Tabelul 1.9.1 Cod binar Valoare Culoare 0 0 0 0 0 Negru – BLACK 0 0 0 1 1 Albastru – BLUE 0 0 1 0 2 Verde – GREEN 0 0 1 1 3 Turcoaz - CYAN 0 1 0 0 4 Roşu – RED 0 1 0 1 5 Liliachiu – MAGENTA 0 1 1 0 6 Galben – YELLOW 0 1 1 1 7 Alb – WHITE 1 0 0 0 8 Gri – Gray 1 0 0 1 9 Albastru strălucitor – LIGHTBLUE 1 0 1 0 A Verde strălucitor – LIGHTGREEN 1 0 1 1 B Turcoaz strălucitor – LIGHTCYAN 1 1 0 0 C Roşu strălucitor – LIGHTRED 1 1 0 1 D Liliachiu strălucitor – LIGHTMAGENTA 1 1 1 0 E Galben strălucitor – LIGHTYELLOW 1 1 1 1 F Alb strălucitor

Octet 2 – Cod de culoare Octet 1 – Cod ASCII

Fig.1.9.6. Mvt = c·r·2 octeţi unde:

prin Mvt s-a notat memoria în modul video text; prin c s-a notat numărul de coloane de caractere; prin r s-a notat numărul de rânduri de caractere.

Pentru cazul r = 25 şi c = 80 se obţine: Mvt = 80·25·2 octeţi = 4000 octeţi < 4 KB Modul video grafic, folosit atât sub sistemul de operare DOS cât şi, în mod exclusiv, sub

sistemul Windows. În modul grafic ecranul este considerat ca o matrice de pixeli trataţi individual şi nu în

blocuri ca în modul video text. Performanţele unui display capabil de afişare în modul video grafic sunt măsurabile după

următoarele caracteristici: - Rezoluţie, adică produsul dintre numărul de pixeli pe o linie de imagine şi număruil de

linii de imagine (sau de pixeli pe coloană). Exemple de câteva asemenea rezoluţii sunt: 640×480 (rezoluţia VGA standard), 800×600, 1024×768, etc;

- Definiţie, adică distanţa minimă dintre două puncte pe ecran (de exemplu 0,28 mm); - Numărul de culori folosit pentru afişarea imaginii. Fiecare pixel are ataşat un cod de culoare. Fiecare culoare este codificată pe un anumit număr de biţi. Cea mai simplă codificare foloseşte un singur bit cu valorile 1 = aprins şi 0 = stins, deci se

pot codifica 2 culori şi anume alb şi negru. Formula generală de calcul a numărului de culori rezultate din modul de codificare, Nc,

este: Nc = 2b

Page 34: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 22

unde b = 1, 2, 4, 8, 16, 32 este numărul de biţi folosiţi la codificare În funcţie de modurile de codificare a culorilor, au existat monitoare cu: b = 1, deci Nc = 2 culori; b = 2, deci Nc = 4 culori; b = 4, deci Nc = 16 culori; b = 8, deci Nc = 256 culori; etc. Evolutiv, pot fi enumerate următoarele tipuri de plăci grafice şi monitoare: - monitoare HGC (Hercules Graphics Card): 720×340×2 (linii×coloane×culori); - monitoare CGA (Color Graphics Adapter): 320×200×4 sau 640×200×2; - monitoare EGA (Enhanced Graphics Adapter): 640×350×16; - monitoare VGA (Video Graphics Adapter): 800×600×16 sau 640×480×256; - monitoare MCGA (Multi Color Graphics Array): 640×480×256; - monitoare SVGA (Super Videu Graphics Array): 800×600×256 sau 1024×768×16; Practic, o dată cu monitoarele SVGA începe evoluţia sistemelor de afişare actuale. Formula de calcul pentru memoria video în modul grafic Mvg, este: Mvg = n·m·c/8 octeţi unde:

n = numărul de pixeli pe linie m = numărul de pixeli pe coloană c = numărul de biţi de codificare a culorii

De exemplu, pentru un monitor SVGA cu 800×600×256, c = 8 (28 = 256) şi memoria video necesară va fi:

Mvg = 800·600·8/8 = 480000 octeţi < 469 KB Rezultatul folosirii modului de afişare video grafic este un consum de memorie mare

precum şi scăderea vitezei de prelucrare a imaginilor. Pentru a compensa acest efect, se folosesc "plăcile cu accelerator grafic". Acestea conţin

un "coprocesor grafic" care preia din sarcinile unităţii centrale, având funcţii precum: - trasare de linii; - umpleri de contururi; - defilare de text; - deplasări de blocuri de imagine, etc. Imprimanta Imprimanta este un dispozitiv de transpunere a informaţiilor rezultate pe un suport

bidimensional (hârtie) prin parcurgere secvenţială (fără revenire). Componentele principale ale imprimantei sunt: - un mecanism de imprimare; - un mecanism de antrenare; - un bloc electronic de comandă; - un panou cu butoane şi indicatoare; Ca tipuri de imprimante folosite, se pot enumera cronologic: - Imprimante cu tambur cu caractere – în prezent nu mai sunt folosite; - Imprimante matriciale cu ace – sunt aproape ieşite din uz; - Imprimante cu jet de cerneală; - Imprimante cu laser (similare constructiv cu fotocopiatorul);

Page 35: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 23

- Imprimante termice. Caracteristicile principale ale imprimantelor sunt: - Rezoluţia, adică numărul de puncte afişate pe un ţol (se măsoară în dpi). De exemplu:

180, 300, 360, 600, 1200 dpi; - Viteza de imprimare se măsoară în cps (caractere pe secundă) la imprimantele lente şi în

ppm (pagini pe minut) la imprimantele rapide; - Dimensiunea maximă a hârtiei. Se deosebesc imprimante pentru formatele A3 (420×297

mm), A4 (210×297 mm), A5 (148×210 mm), B5 (182×257 mm); - Memoria proprie. Pentru a elibera calculatorul de o serie de sarcini de coordonare a

funcţionării imprimantei ca şi pentru a scuti operatorul de a aştepta terminarea lucrului imprimantei comandată direct de calculator, imprimantele actuale posedă un bloc de comandă şi o memorie proprie, ele fiind de fapt calculatoare specializate în imprimare. Ca urmare, informaţia este preluată în pachete mari de caătre imprimantă şi apoi imprimarea decurge independent de calculator. Cu cât memoria proprie este mai mare cu atât pachetele de informaţie transmise sunt mai mari şi intervenţia calculatorului mai rară.

Plotterul Plotterul este un dispozitiv de desenare (sau de tăiere – cutter-plotter) vectorial. El

desenează trasee bidimensionale în orice direcţie a hârtiei. În general plotterele sunt construite pentru formate de hârtie mai mari decât cele ale imprimantelor, sau chiar foarte mari.

Precizia de desenare este mare, în general de circa 300-800 dpi. Plotterul este compus dintr-o masă de lucru şi un braţ sau sistem mecanic de translaţie pe

două direcţii a capului de trasare (la unele sisteme o mişcare de translaţie se realizează prin rotirea hârtiei peste un tambur iar cealaltă mişcare de translaţie este realizată obiţnuit, prin glisarea capului de desenare pe o glisieră liniară).

Capul de desenare poate fi prevăzut cu un schimbător de tocuri cu peniţe, sau cu un dispozitiv pentru pulverizarea unui jet de cerneală.

1.9.3. Memoriile externe Discul magnetic În funcţie de suportul magnetic pe care sunt realizate discurile magnetice pot fi:

Disc

Capete de

Fig.1.9.7. Fig.1.9.8.

- Discuri flexibile (floppy discuri), realizate pe folii de plastic cu suprafaţa acoperită de un strat cu proprietăţi magnetice care poate fi magnetizat după două direcţii asociate cifrelor binare 0 şi 1. Au existat discuri de diferite diametre, în prezent rămânând în uz discurile de 3,25";

Page 36: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 24

- Discuri dure (hard discuri). Acestea sunt realizate sub formă de pachete de discuri din aluminiu acoperite cu un material paramagnetic (uşor magnetizabil) pe bază de oxid de fier.

În figura 1.9.8 este prezentat cazul unui singur disc pe care glisează un ansamblu cu capete de citire/scriere, în timp ce discul se roteşte. Informaţia poate fi stocată pe ambele feţe ale discului.

În figura 1.9.7 se observă modul de dispunere al informaţiilor pe disc. Înregistrările magnetice sunt dispuse pe "piste" circulare concentrice împărţite în "sectoare" conţinând fiecare câte 512 octeţi.

Totalitatea pistelor de aceeaşi rază formează un "cilindru". La discurile flexibile un cilindru are 2 piste (câte una

pe fiecare faţă a discului), iar la discurile dure (figura 1.9.9) un cilindru are un număr de piste egal cu dublul numărului discurilor din pachet.

Fig.1.9.9.

Pentru a putea fi utilizat, un disc magnetic trebuie mai întâi să fie formatat. Formatarea este operaţia de împărţire a discului în piste şi sectoare. Atenţie! Formatarea unui disc magnetic şterge definitiv informaţia existentă pe el anterior. Caracteristicile discurilor magnetice flexibile au fost simbolizate astfel: - Simplă densitate (Single Density) - SD - Dublă densitate (Double Densuty) - DD - Înaltă densitate (High Density) - HD - Densitate extinsă (Extended Density) - ED - Înregistrare pe o singură faţă (Single Side) - SS - Înregistrare pe ambele feţe (Double Side) - DS Capacităţile discurilor magnetice flexibile de 3,5"sunt (până în prezent) următoarele: - dublă densitate, dublă faţă (DD, DS) – 720 KB; - înaltă densitate, dublă faţă (HD, DS) – 1,44 MB; - densitate extinsă, dublă faţă (ED, DS) – 2,88 MB; Capacităţile hard discurilor au evoluat de-a lungul timpului conform următoarelor valori: 10MB, 40MB, 80MB, 120MB, 200MB, 340MB, 560MB, … , 10GB, … Caracteristicile de performanţă ale discurilor magnetice sunt: - Timpul mediu de acces (sau de căutare – seek time) este timpul în care are loc localizarea unui sector de pe o pistă pe disc. Valorile realizate de-a lungul timpului au fost: 25ms, 23ms, 18ms, 16ms, … , 5ms; - Viteza de transfer a informaţiei este cantitatea de informaţie transferată de la unitatea de disc la memoria internă. Ea se măsoară în KB/s. Se deosebesc valorile:

- pentru floppy disc – 20KB; - pentru hard discuri: 450, 600, 700, … , 28000, 46000 KB/s

Compact discul Compact discul este cunoscut sub prescurtarea CD. Se deosebesc: - CD-ROM (Compact Disk – Read Only Memory), CD-uri care pot fi numai citite; - CD-RW (Compact Disk ReWritable), sau reinscriptibil. Capacitatea unui CD este de circa 650MB, iar viteza este mai scăzută decât a discurilor

magnetice. Avantajul principal este posibilitatea stocării CD-urilor şi ea este evidentă în comparaţie cu floppy discurile.

Page 37: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 25

Caseta magnetică (streamer) Această modalitate de stocare a apărut într-un moment în care evoluţia hard discurilor

stagna iar CD-urile nu aveau încă o extindere suficientă. Astăzi se mai vorbeşte relativ puţin despre ele.

La vremea respectivă ele au oferit o capacitate de stocare mare (de circa câteva sute de MB) comparativ cu capacitatea de stocare de la acea vreme a hard discurilor (de numai câteva zeci de MB, până la circa 100MB).

Datorită nevoii de derulare a benzii, accesul la informaţie este secvenţial ceea ce, chiar de la acea vreme se prezenta ca un inconvenient, reducând drastic viteza de exploatare.

§.1.10. Organizarea datelor în memoria externă. Fişiere 1.10.1. Structurarea fişierelor Păstrarea datelor în memoriile externe (disc flexibil, disc dur, compact disc, etc) se

realizează prin gruparea ei în fişiere. Fişierul (File) este o colecţie de informaţii de o anumită natură şi destinaţie, care se

memorează împreună pe un suport de informaţie. În privinţa naturii lor fişierele pot fi împărţite în fişiere executabile constând din programe

sau module de programe, şi fişiere de date care conţin datele de intrare şi/sau de ieşire în/dintr-un proces de prelucrare de informaţie. O clasificare mai detaliată va fi prezentată mai jos.

O dată cu creşterea capacităţii de stocare pe suporturi de memorie externă, a apărut nevoia grupării fişierelor în colecţii de fişiere, pentru a uşura operaţiile de regăsire a fişierelor.

Astfel a apărut noţiunea de director, ca o colecţie de fişiere grupate împreună. În privinţa naturii fişierelor dintr-un director nu există nici o restricţie, criteriul de grupare fiind strict la latitudinea utilizatorului.

Pentru a permite o structurare convenabilă a fişierelor s-a acceptat convenţia ca un director să poată conţine la rândul său, nu numai fişiere, ci şi alte directoare (se foloseşte frecvent noţiunea de subdirector). Prin această convenţie se poate realiza o structură arborescentă sau ierarhică, aşa cum este cea prezentată în figura 1.10.1.

Se observă ramificarea continuă a structurii, pe nivele de ramificare. Primul nivel (nivel 0 sau rădăcină) reprezintă unitatea logică de memorie externă. Ramificarea are loc până când la un nod (director sau subdirector) nu se mai conectează nici un alt subdirector ci numai fişiere (pot exista şi directoare goale, care nu conţin nici un fişier ci există numai ca recipiente pentru eventuala stocare ulterioară a unor fişiere).

Considerând calculatorul ca pe un gestionar de suporturi externe de memorie (prin intermediul dispozitivelor de citire/scriere ataşate), se poate prezenta structura din figura 1.10.2.

Începând cu sistemul de operare Windows 95, noţiunea de director este lărgită. Apare noţiunea de folder care include în structurarea arborescentă a informaţiei, nu numai directoarele ca stocuri compartimentate de fişiere, ci şi alte structuri de gestiune a informaţiei, în special legate de modul de gestiune al comenzilor de execuţie a anumitor programe, prestabilite sau create de utilizator.

În figura 1.10.3 este prezentat un extras din fereastra aplicaţiei Windows Explorer. Se observă apariţia unei entităţi logice superioară calculatorului (My Computer) şi anume

"masa de lucru" (Desktop) la care se ramifică şi alte compartimente logice (foldere). Unul dintre acestea, conectat la My Computer, este Control Panel care, aşa cum se observă

din câmpul de afişare din partea dreaptă, nu conţine fişiere ci comenzi de lansare în lucru a unor programe destinate controlului modului de funcţionare al calculatorului.

Page 38: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 26

… fişier j2…k fişier j2…1

… fişier j22 fişier j21 …subdirector j22subdirector j21

… fişier j2 fişier j1 …subdirector j2subdirector j1

… … fişier mfişier 2 fişier 1 director j… director 2 director 1

Suport de memorie

Fig.1.10.1.

A: B: C: D: …

CD-ROM hard discfloppy discuri

Calculator

Fig.1.10.2.

1.10.2. Operaţii cu fişiere Pentru manipularea fişierelor trebuie stabilită mai întâi o convenţie de definire a operaţiilor

posibile cu fişierele. Se folosesc următoarele denumiri: - Crearea unui fişier. Aceasta este o operaţie efectuată de către un program creator de

fişiere, printr-o operaţie de scriere a fişierului pe suportul de memorie. Pentru a putea scrie fişierul, programul creator trebuie să cunoască următoarele elemente:

= suportul de memorie (unitatea de disc) pe care se va face scrierea; = directorul (subdirectorul) în care va fi inclus fişierul; = numele fişierului.

Toate aceste elemente compun aşa numita "cale" (path) către fişier. Sintaxa definirii unei căi este următoarea:

dispozitiv:\director\subdirector\…\subdirector\nume_fişier.tip De exemplu: D: \CosDocRom\UsrGuide\Pdf-doc\01intro.pdf În figura 1.10.4 se observă corespondenţa dintre această notaţie şi modul de accesare al

fişierelor din directorul final corespunzător, când se foloseşte aplicaţia Windows Explorer.

Page 39: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 27

Fig.1.10.3. - Consultarea (citire precedată de deschidere) unui fişier existent. Aceasta este o operaţie

de extragere de informaţie dintr-un fişier, fără modificarea lui. În figura 1.10.5 se observă fereastra Open a unei aplicaţii care este în curs de a deschide

fişierul de pe calea exemplificată mai sus. - Actualizarea unui fişier. Orice fişier de date este compus din date structurate sub forma

unor înregistrări. Înregistrările pot fi privite ca stocuri de informaţie elementare, componente ale fişierului.

Se deosebesc trei cazuri de actualizare: = adăugarea unei (sau unor) înregistrări, cu consecinţa lungirii fişierului; = ştergerea unei (sau unor) înregistrări, cu consecinţa scurtării fişierului; = modificarea unei (sau unor) înregistrări. În acest caz consecinţa poate fi de lungire, scurtare sau conservare a lungimii fişierului în funcţie de modul cum sunt definite înregistrările. Dacă acestea sunt de lungime fixă, fişierul nu îşi modifică lungimea. Dacă însă înregistrarea poate avea lungime variabilă, fişierul se lungeşte sau se scurtează după cum înregistrarea se modifică prin lungire sau scurtare.

- Copierea unui fişier. Prin această operaţie se obţine o copie identică a fişierului. Deoarece nici un sistem de operare nu tolerează existenţa în acelaşi director a mai multor fişiere cu acelaşi nume, copia poate avea:

= indiferent ce nume (acelaşi ca originalul sau diferit), dacă fişierul este plasat într-un alt director decât originalul; = obligatoriu alt nume decât originalul, dacă fişierul este plasat în acelaşi director cu originalul. În sistemul Windows 95 (sau superioare) este posibilă copierea unui fişier în acelaşi

director fără specificarea unui nume diferit dar, în mod automat, sistemul de operare va schimba numele din nume în Copy of nume, pentru a diferenţia fişierul nou creat prin copiere de cel original.

Page 40: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 28

Fig.1.10.4. Fig.1.10.5.

- Ştergerea unui fişier. Prin această operaţie fişierul nu este propriu-zis şters de pe suport deoarece operaţia ar putea dura prea mult ci, într-un fişier special denumit "Tabelă de alocare a fişierelor" (FAT – File Allocation Table) situat la începutul suportului şi invizibil pentru utilizator, spaţiul ocupat de fişier este marcat ca fiind liber. Aceasta permite ca următoarele operaţii de creare de fişiere noi sau de actualizare a fişierelor existente, să folosească acest spaţiu. Din acest motiv, anumite programe capabile să recupereze un fişier şters din greşeală, pot acţiona cu succes numai dacă încercarea de recuperare se face înainte de a efectua prima operaţie de scriere pe suport (creare sau actualizare). Acest procedeu este valabil numai în sistemul de operare DOS şi numai dacă între timp nu au fost folosite programe care necesită fişiere temporare (care se reactualizează automat, fără intervenţia explicită a operatorului). Cum sistemul Windows 95 foloseşte întotdeauna un astfel de fişier (denumit swap file) de lungime variabilă, pentru recuperarea fişierelor şterse din greşeală, în acest sistem a fost prevăzut un director special denumit Recycle Bin (recuperare binară) în care, pentru un anumit timp, sunt păstrate fişierele şterse. Dacă ele se şterg şi din acest director, recuperarea lor nu mai este posibilă.

- Mutarea unui fişier. Prin această operaţie un fişier poate fi mutat dintr-un director în altul. Şi această operaţie este simulată dacă mutarea se face pe acelaşi suport. De fapt fişierul rămâne pe loc dar, în tabela de alocare de fişiere, el este marcat ca aparţinând altui director.

Şi aici acţionează regula de a nu se admite mai multe fişiere cu acelaşi nume în acelaşi director. De aceea, mutarea fişierului se poate face:

= pe acelaşi disc: fişierul va trebui ca anterior să fie redenumit dacă în directorul destinaţie mai există un fişier cu acelaşi nume. Altfel fişierul mutat îl va substitui pe cel preexistent. Mutarea este fictivă din punct de vedere fizic, operaţia având loc numai în FAT ca schimbare de atribut de apartenenţă; = pe alt suport: este valabilă precauţia de mai sus privind denumirea. În plus, mutarea este reală, fişierul fiind scris la destinaţie şi şters (marcat ca spaţiu liber) pe suportul sursă.

- Redenumirea unui fişier constă din schimbarea numelui fişierului. Această operaţie este efectuată numai în tabela de alocare de fişiere.

1.10.3. Tipuri de fişiere Se pot distinge următoarele tipuri principale de fişiere:

Page 41: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 29

- Fişiere executabile care conţin programe executabile (cu extensia EXE sau COM) sau module executabile (de exemplu cele cu extensia DLL – Dynamic Link Library);

- Fişiere de date, care conţin date de diferite tipuri, eventual compuse din tipurile de mai jos;

- Fişiere de text, care conţin numai caractere ASCII tipăribile, eventual şi coduri de control pentru formatarea textelor şi aranjarea lor în pagină;

- Fişiere de imagine care conţin descrierile necesare afişării sau imprimării imaginilor. Acestea pot fi:

= vectoriale, compuse din comenzi sau definiţii necesare pentru trasarea de linii; = raster (matriciale), compuse din descrierea succesiunii de pixeli de afişat.

§.1.11. Noţiuni privind structura software a calculatorului Software-ul unui calculator este format din programele care pot fi executate de către

calculator în diverse scopuri. Programul este o colecţie organizată de comenzi de operaţii pe care calculatorul trebuie să

le efectueze. Aceste comenzi sunt numite instrucţiuni. Orice instrucţiune este tradusă, în final, într-una sau mai multe instrucţiuni elementare

recunoscute de microprocesor, exprimate în cod binar şi transmise microprocesorului spre execuţie.

Programe utilitare

Programe aplicative

Sistem de operare

Programmonitor

(nucleu ROM)

Fig.1.11.1.

1.11.1. Ierarhia programelor Simplificând lucrurile la extrem, se pot defini trei nivele

ierarhice în organizarea software a unui calculator (figura 1.11.1), şi anume:

- Programul monitor, este programul conţinut în memoria ROM a calculatorului. El este executat automat la punerea sub tensiune a calculatorului şi controlează secvenţa de iniţializare a funcţionării calculatorului.

Astfel, se realizează: = testarea conectării şi bunei funcţionări a dispozitivelor

periferice: tastatură, floppy disc, hard disc; = testarea memoriei RAM disponibile;

= încărcarea sistemului de operare. Prin intermediul acestui program se realizează exploatarea resurselor fizice de la nivelul

cel mai de jos al calculatorului. - Sistemul de operare. Acesta constă dintr-un set de programe care asigură exploatarea

optimă a resurselor fizice şi logice ale calculatorului. Funcţiile realizate de sistemul de operare sunt:

= Sesizarea şi tratarea evenimentelor apărute la perifericele de intrare (tastatură şi mouse); = Deservirea perifericelor de ieşire (ecran, discuri, imprimantă);

Cronologic, sistemele de operare folosite (mai cunoscute) au fost: - pe microcalculatoarele de 8 biţi: SFDX, CP/M; - pe minicalculatoare: RSX; - pe microcalculatoare compatibile IBM-PC: DOS, UNIX, OS/2; - pe microcalculatoare Mac Intosh: System; - Începând de la versiunea Windows 95, pe microcalculatoarele compatibile IBM-PC

sistemul de interfaţare grafică Windows a devenit sistem de operare înlocuind sistemul DOS.

Page 42: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 30

- Programele utilitare sunt programe aplicative foarte generale cum ar fi: = editoarele de texte; = compilatoarele pentru diverse limbaje; = gestionarele de informaţie pe discuri, ca de ex: Norton Commander, Xtree Gold, PC Shell, File Manager în versiunile de Windows mai vechi, Windows Explorer începând de la Windows 95; = programele de testare şi depanare a defectelor de pe discuri (de exemplu Scan Disk); = optimizatoarele de discuri; = etc.

- Programele aplicative sunt programe care rezolvă diverse aplicaţii specializate, realizate fie de către firmele producătoare de programe fie de către programatori individuali.

§.1.12. Elemente de ingineria programării 1.12.1. Generalităţi Termenul de ingineria programării a fost introdus pentru prima oară în 1968/1969. Deşi de

atunci, pentru clarificarea acestui concept, au fost elaborate multe studii, în principiu el presupune utilizarea riguroasă a unor metode şi instrumente adecvate pentru dezvoltarea de programe şi aplicarea exactă a unor principii de bază în activitatea de elaborare de programe pentru calculatoare.

Necesitatea elaborării acestei discipline a pornit de la productivitatea scăzută a activităţii de programare şi calităţii scăzute a rezultatelor acestei activităţi, precum şi de la costurile mari ocazionate de întreţinerea şi dezvoltarea ulterioară a programelor.

Se punea tot mai accentuat problema unor scheme generale de organizare a programelor astfel încât ele să poată fi ulterior uşor de citit, înţeles şi corectat.

1.12.2. Modularizarea Modularizarea este un concept pornit de la constatarea că este mai uşor de tratat o

problemă descompusă în componente decât aceeaşi problemă manipulată în întregime. De aceea programele medii şi mari sunt întotdeauna împărţite în module care sunt

asamblate sau apelate după anumite reguli. Spargerea programelor în module este dictată şi de limitările tehnice ale calculatoarelor,

limitări care există şi vor exista mereu. Prima şi cea mai critică resursă care dictează modularizarea este memoria electronică şi viteza de acces la ea.

Modularizarea îşi propune ca obiective: - descompunerea unei probleme complexe în subprobleme (module), pornind de la criterii

ca: omogenitatea funcţiilor de realizat, folosirea unor date comune, înţelegerea cât mai uşoară, etc:

- testarea corectitudinii unui modul independent de contextul de utilizare într-un program mai mare;

- construirea unui program complex prin asamblare de module (subprograme) scrise de mai alţi programatori, fără a fi nevoie de cunoaşterea structurii interne a programelor.

Pentru atingerea acestor obiective trebuie aplicate principii ca: - abstractizarea, prin care un grup de operaţii poate fi desemnat printr-un nume, fără a fi

necesară precizarea lor în detaliu; - compoziţia, pentru care construcţiile complexe sunt stabilite plecând de la componente

mai simple. Etapele principale ale modularizării sunt: - modularizarea funcţională în care se identifică şi se specifică funcţiile de prelucrare

Page 43: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 31

automată a datelor; - modularizarea structurală în care se specifică structura datelor; - modularizarea procedurală în care se specifică ordinea de execuţie a modulelor. 1.12.3. Teorema fundamentală a ingineriei programării Fie P şi Q două probleme pentru care trebuiesc scrise două programe distincte. Fie M o măsură pentru dimensiunea unei probleme şi fie C costul scrierii unui program

pentru acea problemă. Dacă M(P) > M(Q) este evident că C(P) > C(Q), adică scrierea unui program pentru o

problemă mai mare este mai scumpă decât scrierea unui program pentru o problemă mai mică. Fie acum două probleme separate P şi Q pe care ne propunem să le tratăm ca pe o

problemă combinată P+Q pentru care ne propunem să scriem un singur program combinat. Deoarece problemele sunt independente, programul trebuie să conţină şi efortul de corelare

între cele două probleme pentru a se evita interferenţele nedorite. Aşadar: M(P+Q) > M(P) + M(Q) şi, în consecinţă, relaţia deintre costuri va fi asemănătoare: C(P+Q) > C(P) + C(Q)

Fig.1.12.1.

A = curba erorilor comise la manipulare simultană B = curba erorilor comise la manipulare separată

Acest rezultat poate fi privi şi invers, adică este mai ieftin de creat două programe mici

decât unul mare. Acest lucru se explică prin faptul că, pe lângă altele, efortul de corelare a problemelor

poate avea ca rezultat producerea de erori de programare, pentru a căror eliminare sunt necesare cheltuieli suplimentare.

Într-adevăr, este demonstrat prin studii statistice că o persoană poate manipula în memoria sa imediată un număr de circa 7 ± 2 obiecte, entităţi sau concepte. Peste acest număr de elemente distincte utilizabile simultan, numărul de erori comise creşte din ce în ce mai rapid ca în diagrama din figura 1.12.1.

Aşadar, este demonstrat că C(P+Q) > C(P) + C(Q) De aici rezultă imediat "Teorema fundamentală a ingineriei programării": Fie P o problemă care poate fi descompusă în subproblemele tratabile separat P' şi P". Atunci: C(P) > C(P') + C(P") adică, costul rezolvării separate a componentelor unei probleme este mai scăzut decât acela

al rezolvării problemei în bloc.

Page 44: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 32

În cazul programelor , să zicem cu 1000 de linii, va fi mai ieftin de proiectat un program cu două module de câte 500 de linii decât un singur modul cu 1000 de linii.

În cazul extrem putem scrie 1000 de module cu câte o singură linie. Apare însă o nouă problemă. C(P') şi C(P") conţin şi costurile realizării interfeţei dintre

modulele P' şi P" şi programul care le conţine. Treptat preţul interfaţării creşte tot mai mult şi se poate ajunge la situaţia reflectată de figura 1.12.2.

Evident, costul realizării fiecărui modul depinde de mărimea sa şi va fi cu atât mai mic cu cât este mai mică dimensiunea modulului. În schimb, pe măsură ce numărul de module în care este descompus produsul este mai mare creşte costul realizării interfeţelor dintre module. Costul realizării întregului produs este suma celor două costuri şi va fi minim la o anumită combinaţie dimensiune medie de modul-număr de module, combinaţie optimă din punctul de vedere al costului, după depăşirea acestei valori obţinându-se din nou creşterea costului total.

Fig. 1.12.2. 1.12.4. Date, tipuri şi structuri de date Datele sunt informaţiile prelucrate de programe. Se deosebesc date elementare şi date

structurate. Tipurile de date elementare sunt următoarele: a. Tipul numeric. Acest tip include de obicei numerele întregi, reale şi complexe. În cadrul tipurilor numerice

se deosebesc subtipuri în funcţie de lungimea de memorie folosită pentru reprezentare şi care, pentru numerele reale determină precizia de reprezentare.

b. Tipul logic (sau Boolean). Acest tip cuprinde datele care pot avea valorile adevărat sau fals şi între care sunt posibile

operaţiile logice AND, OR şi NOT. c. Tipul şir de caractere. Acest tip de date conţine succesiuni finite de caractere (în cod ASCII), cea mai scurtă

succesiune fiind şirul vid (de lungime zero). Datele de aceste tip pot suporta operaţii de concatenare (alipire), ordonare, comparare, etc.

Unele limbaje recunosc tipul particular şir de caractere de lungime unitară sau tipul caracter, din care se formează şirurile de caractere.

d. Tipul pointer. Acesta este un tip de dată special care conţine adresa către o locaţie de memorie în care

Page 45: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 33

este stocată o dată de unul dintre tipurile de mai sus. Pentru a ajuta la localizarea exactă a datei, tipul pointer din limbajul C conţine nu numai adresa datei ci şi informaţia privind tipul ei, adică lungimea de stocare.

Pointerii sunt folosite în operaţiile de referire a unei date, operaţie care înlocuieşte transferul datei prin lista de argumente a unei funcţii sau proceduri.

Structuri de date. Datele individuale nu sunt suficiente pentru nevoile de programare. Adesea nevoile

practice impun manipularea de mulţimi de date de un anumit tip sau de tip compus. Se întâlnesc următoarele structuri de date:

a. Tabloul. Acesta este o colecţie de date de acelaşi tip aranjate într-o structură rectangulară k-dimensională.

Astfel, deosebim: - Tabloul unidimensional sau vectorul, constând dintr-un şir simplu de date de tip numeric

de o anumită lungime (număr de elemente); - Tabloul bidimensional sau matricea, constând dintr-o serie de un anumit număr de şiruri

de aceeaşi lungime. Echivalentul grafic este matricea cu n linii şi m coloane; - Tabloul tridimensional, sau masivul; - etc. b. Şirul. Un caz particular este şirul de caractere descris mai sus. Şirul poate fi compus şi

din numere (vectorul) dar şi din alte şiruri. c. Lista. O listă este o înşiruire de date de orice tip. 1.12.5. Structuri de programe. Programare structurată Un program descrie un proces de calcul prin instrucţiuni care descriu operaţiile pe care un

calculator le poate efectua într-o anumită ordine, succesivă sau, altfel spus, secvenţială. Astfel, dacă: S1, S2, … , Si-1, Si, Si+1, … ,Sn este un program secvenţial compus din instrucţiunile Si, i=1, … ,n, atunci: 1. S1 este prima instrucţiune care se execută 2. după execuţia instrucţiunii Si se transferă controlul la instrucţiunea Si+1 3. Sn este ultima instrucţiune de executat În practică, notaţia Si poate fi folosită atât pentru a desemna instrucţiuni separate cât şi

secvenţe întregi de instrucţiuni.

i

S1 S2 Sn…

Selector

Secvenţe

Condiţieîndeplinită

S2 S1

Nu Da

Fig.1.12.3. Fig.1.12.4.

Page 46: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 34

Un program structurat se compune din următoarele elemente de bază:

- Secvenţa - Structura alternativă - Structura repetitivă O secvenţă este o succesiune de instrucţiuni care

se execută succesiv, una după alta, în ordinea scrierii lor (a se vedea exemplul de mai sus).

Structura alternativă este de mai multe tipuri: Structura multialternativă, figura 1.12.3. La

această structură direcţionarea execuţiei pe o ramură sau alta dintre mai multe ramuri (alternative) se face în funcţie de valoarea unei variabile de test numeric (selector de caz). Echivalentul în pseudocod al schemei grafice din figura 1.12.3 este următorul:

CondiţieAdevărată Falsă

S

Fig.1.12.5.

dacă i este egal cu i1 execută S1; este egal cu i2 execută S2; … este egal cu in execută Sn;

Un exemplu de utilizare în limbaj C++ este următorul: switch(i) {case 1: case 2: case 3: y=1; break; case 4: y=2; break; default: y=0; }

rezultatul produs fiind y=1 pentru i=1, 2 sau 3, y=2 pentru i=4, şi y=0 pentru oricare altă valoare a lui i.

Structura bialternativă (sau blocul de decizie), figura 10 direcţionează execuţia pe una dintre două căi în funcţie de rezultatul afirmativ sau negativ (adevărat sau fals) al unui test logic.

Echivalentul în pseudocod al schemei logice din figura 1.12.4 este următorul: dacă condiţie este adevărată atunci execută secvenţa S1; altfel execută secvenţa S2; Un exemplu în limbaj C++ de bloc de decizie este:

if (a<b) minab=a; else minab=b;

ccea ce are ca rezultat stocarea în variabila minab a celei mai mici dintre valorile variabilelor a sau b.

O variantă a structurii din figura 1.12.4 este structura bialternativă cu o ramură vidă, figura 1.12.5. Pseudocodul corespunzător este:

dacă condiţie este adevărată atunci execută S Varianta în C++ a procedurii de mai sus , cu acelaşi efect, va fi:

minab=b if (a<b) minab=a;

Page 47: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 35

C SDa

Nu

C

S

Da

Nu

Fig.1.12.6. Fig.1.12.7.

Structura repetitivă, este o structură care repetă o secvenţă de instrucţiuni de un număr de ori determinat de valoarea unui test logic efectuat pe parcursul repetiţiei.

Există două variante de structură repetitivă. Structura repetitivă condiţionată anterior, figura 1.12.6. La această structură, testarea

condiţiei de repetare se face înaintea execuţiei secvenţei de repetat. Pseudocodul folosit pentru această structură este: cât timp condiţia C este adevărată execută S; Pentru a nu se ajunge la o situaţie de repetare la infinit, în cuprinsul secvenţei S variabila

asupra căreia se execută testul trebuie să îşi schimbe la un moment dat valoarea pentru ca testul să dea rezultat negativ şi repetiţia să se oprească.

De exemplu, în limbaj C++ valoarea lui n! se poate calcula astfel n=5; i=1; factn=1; while i<=n {factn=factn*i; i=i+1; }

La sfârşitul acestei porţiuni de program se obţine valoarea factn=120, adică valoarea lui 5!. Structura repetitivă condiţionată posterior, figura 1.12.7. La această structură testul

condiţiei de continuare a repetiţiei se face după executarea secvenţei S. În pseudocod această structură apare astfel: execută S cât timp condiţia C este adevărată; Un exemplu de astfel de structură, în limbajul C++, este următorul:

n=5; i=1; factn=1; do {factn=factn*i; i++; }while (i<=n);

având acelaşi rezultat ca mai sus, şi anume calculul lui 5!. Diferenţa de fond dintre structura repetitivă condiţionat anterior şi cea condiţionată

posterior este că, la cea de a doua, execuţia secvenţei S are loc cel puţin o dată chiar dacă condiţia de repetare nu este îndeplinită.

Page 48: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 36

Uneori se acceptă şi testul negativ al condiţiei C, adică repetarea să se producă până când o condiţie de oprire să fie îndeplinită. În acest caz, în figura 1.12.7 condiţiile Da şi Nu sunt inversate, iar pseudocodul apare astfel:

execută S până când C este adevărată; În limbajul Visual Basic o astfel de structură repetitivă, de asemenea pentru calculul lui n!

va apare astfel: n=5 i=1 factn=1 Do factn=factn*i i=i+1 Loop Until i>n A fost demonstrat faptul că orice program poate fi scris folosind numai trei tipuri de

structuri, denumite structuri fundamentale, şi anume: - structura secvenţială; - structura alternativă cu două ramuri; - structura repetitivă condiţionată anterior. Un program scris astfel, se numeşte program D-structurat (iniţiala D provenind de la

numele lui Dijkstra, cel care a introdus denumirea de programare structurată). Totuşi, limbajele actuale prevăd şi alte tipuri de structuri, unele fiind menţionate mai sus,

cu scopul de a uşura munca programatorului. Există astăzi un consens general de a evita, dacă se poate total, folosirea instrucţiunii de

salt necondiţionat GoTo, care are ca efect distrugerea structurării. Totuşi, se acceptă folosirea ei pentru cazuri de abandon forţat al execuţiei, ca ieşire de siguranţă dintr-un program sau procedură, şi numai precedată de un test de condiţie adecvat şi însoţită de măsuri adecvate de stabilire a valorilor variabilelor care ar mai fi necesare ulterior.

În concluzie, structurarea programelor urmăreşte realizarea unei cerinţe de rigurozitate şi anume principiul încapsulării (separării) acţiunilor care se poate enunţa ca eliminarea posibilităţii ca, prin instrucţiunile folosite într-un modul de program sau zonă de modul, să se declanşeze acţiuni dificil de controlat într-un alt modul sau zonă de modul concepută ca independentă. Din acest punct de vedere instrucţiunea GoTo este deosebit de nefastă.

Un alt principiu necesar a fi respectat este principiul încapsulării datelor care stipulează limitarea sau blocarea vizibilităţii variabilelor între diferitele module de program. Din acest principiu rezultă o clasificare a variabilelor în variabile locale care sunt vizibile numai în interiorul unui modul de program (procedură sau funcţie) şi variabile globale care sunt vizibile în tot cuprinsul programului, conform schemei din figura 1.12.8.

În acest scop, limbajele actuale folosesc instrucţiuni de declarare care, în funcţie de locul unde sunt inserate (înaintea definirii modulelor sau în interiorul modulelor) determină vizibilitatea globală sau locală. În acest mod, chiar dacă în modulul n, de exemplu, se foloseşte aceeaşi denumire pentru variabila L1 ca şi în modulul 1, modificarea valorii acelor variabile într-unul din module nu se reflectă în celălalt modul.

ProgramVariabile globale

G1…Gk

Modul 1Variabile locale

L1,…Ln1

Modul nVariabile locale

L1,…Lnn

Fig.1.12.8.

Cu alte cuvinte, chiar dacă cele două variabile au aceeaşi denumire, în memoria

Page 49: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 37

calculatorului ele sunt stocate la adrese diferite, fiind folosite în funcţie de apartenanţa la modulul în care sunt definite. Dimpotrivă, o variabilă globală fiind stocată la o adresă de memorie unică va fi văzută la fel de către toate modulele.

Scopul principiului încapsulării datelor este pe de o parte de a nu forţa programatorul să facă un efort prea mare pentru a crea şi manipula denumiri distincte de variabile, iar pe de altă parte pentru a evita ca o modificare a unei valori a unei variabile dintr-un anumit modul să se reflecte în mod nedorit într-un alt modul independent.

Declaraţiile de vizibilitate (locală sau globală) permit programatorului să controleze cu exactitate caracterul comun sau izolat al variabilelor folosite.

1.12.6. Metode de programare Metoda de programare Top-Down (sau de rafinare în paşi succesivi) Această metodă constă în construirea programelor de sus în jos, adică pornind de la blocuri

mari către blocuri tot mai mici, până la nivel de instrucţiuni simple. La început programul este văzut ca un bloc care rezolvă o problemă (figura 15 a). Se

analizează problema şi se descompune în blocuri succesive constituite din mulţimi de secvenţe (figura 112.9.b). Fiecare bloc sau secvenţă este descompusă în structuri conţinând secvenţe din ce în ce mai mici care la rândul lor sunt exprimate prin structuri, şi aşa mai departe, până la nivelul simplelor instrucţiuni. Această metodă permite programatorului să se concentreze asupra aspectelor de fond ale problemei de programat, amânând pentru mai târziu rezolvarea problemelor de detaliu, legate de implementarea programului cu un limbaj oarecare. De asemenea, pe măsură ce are loc rafinarea problemei, se pot rezolva gradual problemele de structurare a programului şi de încapsulare a datelor.

Aceasta este cea mai recomandată metodă de programare, mai ales pentru programele care se află la prima elaborare când nu toate problemele sunt lămurite.

Program Bloc 1 Bloc 2 Bloc n…

a b Fig.1.12.9.

Metoda de programare Bottom-Up. Această metodă este contrariul celei de mai înainte. Ea presupune construcţia programelor de

la bază la vârf, începând cu elaborarea instrucţiune cu instrucţiune a fiecărui modul şi apoi interfaţarea modulelor realizate, cu eventualele modificări necesare pentru succesul interfaţării.

Metoda a fost folosită intens în epocile timpurii ale activităţii de programare şi şi-a dovedit din plin ineficienţa prin complicaţiile pe care le crea şi prin marea risipă de timp cauzată de permanentele reconsiderări pe care le impunea practica şi care conduceau la reluarea repetată a procesului de la bază.

În prezent ea mai este folosită numai în măsură limitată, pentru asamblarea unor module existente şi verificate, în programe cu problematică foarte clară.

§.1.13. Programe şi limbaje de programare Prin program se înţelege o colecţie organizată de comenzi de operaţii pe care calculatorul

trebuie să le efectueze pentru îndeplinirea unei anumite sarcini. Aceste comenzi poartă denumirea de instrucţiuni.

Page 50: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 38

Orice instrucţiune a unui limbaj de programare oarecare este convertită în final în una sau mai multe instrucţiuni elementare recunoscute de microprocesor, exprimate în cod binar şi transmise microprocesorului spre execuţie.

Exprimarea în cod binar a comenzilor adresate microprocesorului poartă denumirea de limbaj maşină, şi acesta este propriu fiecărui tip (generaţie) de microprocesoare.

Cu excepţia acestui limbaj, care este situat la nivelul cel mai de jos (cel mai apropiat de microprocesor) există şi alte moduri de exprimare a comenzilor de execuţie denumite limbaje de programare.

Aceste limbaje reprezintă construcţii sintactice convenţionale, care fac uz de mnemonice scrise literal, mai inteligibile pentru programator.

Primul limbaj care a folosit tehnica mnemonicelor în locul codurilor binare a fost limbajul de asamblare care reprezintă o corespondenţă aproape directă în formă literală a limbajului maşină codificat binar. În acest limbaj fiecărei mnemonice literale îi corespunde un cod binar din limbajul maşină.

Au urmat o serie de alte limbaje în care o instrucţiune se traduce printr-un set de instrucţiuni în limbajul maşină. Această tehnică a urmărit pe de o parte creşterea productivităţii muncii de programare şi, pe de altă parte, uşurarea efortului de concepere şi manevrare a programelor.

Aceste limbaje sunt denumite limbaje de nivel înalt, de asemenea prin comparaţie cu limbajul de bază, acela al microprocesorului.

Exemple de astfel de limbaje sunt, în ordine cronologică: FORTRAN (RORmula TRANslator - 1956), COBOL (COmmon Bussines Oriented Language - 1960), ALGOL (ALGOrithmic Language – 1960) din care a derivat limbajul PASCAL, BASIC (Beginer's All purpose Symbolic Instruction Code- 1964), C (1971) din care derivă mai târziu limbajul JAVA.

Aceste limbaje sunt limbaje "procedurale" sau "algoritmice" deoarece ele descriu algoritmul sau succesiunea rezolvării unei probleme. La aceste limbaje ordinea de scriere a instrucţiunilor determină strict ordinea în care ele vor fi executate.

Nevoia de flexibilitate a programării în vederea rezolvării problemelor lumii reale a condus la căutarea de alternative la limbajele procedurale.

Astfel au apărut, într-o primă etapă, limbajele neprocedurale în care ordinea scrierii instrucţiunilor nu este în mod obligatoriu şi ordinea lor de execuţie. În aceste limbaje programatorul precizează problema care trebuie rezolvată şi mai puţin modul sau algoritmul de rezolvare a ei. Un exemplu de astfel de limbaj este limbajul LISP (LISt Processor) care are ca structură unică lista. Lista poate fi atât funcţie (noţiunea de instrucţiune sau subrutină nu există în acest limbaj) cât şi stoc de date. Datorită acestei ambivalenţe a listei, limbajul posedă capacitatea de a-şi rescrie listele ca şi cum ar rescrie un stoc de date şi prin aceasta el îşi poate rescrie funcţiile în chiar cursul execuţiei. Limbajul capătă în acest fel posibiltatea de a se automodifica în execuţie, posibilitate pe care celelalte limbaje nu o au. Din acest motiv, acest limbaj este foarte mult folosit în problemele de inteligenţă artificială care trebuie să aibă puterea de autoadaptare la condiţii de mediu variabile.

Totuşi, nici această tehnică de programare nu a dat în întregime satisfacţie, motiv pentru care a apărut programarea orientată pe obiecte. Fără a face uz de limbaje speciale, această tehnică foloseşte module de program care comunică între ele, conform schemelor prezentate în capitolele anterioare.

1.13.1. Portabilitatea programelor Portabilitatea este însuşirea unui program scris într-un anumit limbaj de a putea fi transpus

pe o altă maşină şi de a putea fi rulat cu mai multe sau mai puţine modificări. Se poate vorbi despre:

Page 51: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 39

- Portabilitatea programelor. Fie cazul unui program pentru care există un cod sursă (succesiune de instrucţiuni scrise în

formă text) asupra căruia nu se mai fac modificări. Acest program poate compilat pe un anumit calculator obţinându-se codul executabil (succesiunea de coduri binare pentru microprocesor) şi poate apoi să fie rulat pe calculatoare din aceeaşi familie (construite cu microprocesoare de acelaşi tip) fără a mai fi nevoie de nici o modificare a sursei sau recompilare. Acesta este cazul calculatoarelor din familia PC-urilor pe platforma WINDOWS sau DOS.

Dacă însă se folosesc maşini UNIX (calculatoare cu arhitecturi şi procesoare diferite construite pentru sistemul de operare UNIX) poate apare nevoia ca programul sursă să fie cel puţin recompilat pentru maşina respectivă dacă nu chiar rescris, modificând acele secvenţe care apelează funcţii efectuate în mod diferit în funcţie de maşină.

- Portabilitatea limbajelor (sau portabilitatea programelor sursă). Deoarece microprocesoarele au în general diferenţe de la tip la tip şi de la generaţie la

generaţie, cel mai neportabil limbaj este limbajul maşină. Dacă se scrie un program într-un astfel de limbaj (lucru foarte frecvent folosit la nivelul firmelor producătoare de soft de bază) el trebuie rescris şi recompilat pentru fiecare tip de maşină în parte.

Pe măsură ce se folosesc limbaje de nivel din ce în ce mai înalt portabilitatea acestora creşte, nemai fiind nevoie de rescrierea lor în funcţie de maşină dacă compilarea sursei se face pe maşina destinaţie. Acest lucru se întâmplă datorită faptului că, compilatorul sau programul de traducere în cod maşină, preia sarcina de a ţine cont de maşina pentru care face traducerea, scutindu-l pe programator de acest efort.

Legat de problema portabilităţii apare problema vitezei de execuţie. Deoarece programele în limbaj maşină se adresează direct microprocesorului, exprimarea

unei sarcini de efectuat printr-un set de instrucţiuni este cea mai scurtă posibil şi ca atare viteza de execuţie este cea mai mare posibil. La limbajele de nivel înalt acest mod de exprimare este unul indirect, o instrucţiune dintr-un set apelând nu direct o funcţie a microprocesurului ci un alt set de instrucţiuni. De aceea o portabilitate mare a unui limbaj se realizează în dauna vitezei de execuţie. Există metode de a ocoli acest inconvenient, şi ele constau în includerea în limbaj a unor posibilităţi de folosire directă a limbajului maşină în cadrul limbajului de nivel înalt respectiv. Totuşi această rezolvare face programul respectiv dependent de un anumit microprocesor (cel pentru care se folosesc respectivele instrucţiuni maşină) ceea ce compromite de fapt portabilitatea mărită a limbajului de nivel înalt.

1.13.2. Fazele de elaborare a unui program executabil Pentru elaborarea unui program trebuie parcurse următoarele faze: A. Stabilirea problemei. În această fază este definită problema de rezolvat, domeniile de definiţie ale valorilor

datelor manipulate şi metodele matematice şi logice de tratare a problemei. B. Stabilirea algoritmului de rezolvare a problemei Algoritmul de rezolvare descrie succesiunea etapelor de rezolvare a problemei, nodurile

decizionale care pot interveni şi deciziile care trebuie luate, modalităţile de introducere a datelor de intrare şi de conservare a rezultatelor.

În fazele A şi B nu este necesară cunoaşterea unui limbaj de programare. Algoritmul poate fi descris prin scheme logice sau prin pseudocod.

Page 52: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 40

Primeşte b

Primeşte c

c≠0

AfişeazăEROARE

Calculeazăa=b/c

Afişeazăvaloarea lui a

STOP

Fig.1.13.1.

De exemplu, operaţia a=b/c se poate descrie: a. Prin schemă logică, figura 1.13.1; b. Prin pseudocod: început primeşte a; primeşte b; dacă c ≠ 0 atunci { a = b/c; afişează a;} altfel afişează "EROARE"; sfârşit. Schema logică are avantajul că este mai uşor de înţeles

"dintr-o privire" dar are dezavantajul de a necesita spaţii mari pe hârtie.

Pe de altă parte folosirea regulilor programării structurate a restrâns drastic marea varietate de scheme logice posibile înainte de introducerea susnumitelor reguli, astfel încât ele nu mai sunt atât de necesare ca în trecut.

Programatorii cu experienţă preferă folosirea pseudocodului care este mai apropiat de modul în care va apare scris programul în final, când se va fi folosit un limbaj de programare structurat.

Pentru exemplul de mai sus, transpunerea pseudocodului în limbaj C++ va apare astfel: void main() {float a, b, c; cout << "b="; cin >> b; cout << "\nc="; cin >> c; if (c!=0) {a=b/c; cout << "\na=" << a;} else cout << "\nNu se poate imparti la 0"; } C. Implementarea programului. În această fază programatorul trebuie să opteze pentru limbajul care satisface cel mai bine

nevoile algoritmului. O dată opţiunea făcută trebuie parcurse următoarele etape: c1. Scrierea fişierului program sursă, care conţine instrucţiunile scrise în forma text. c2. Generarea programului cod obiect executabil. În această etapă la dispoziţia

programatorului stau următoarele două procedee de lucru: Procedeul interpretor. Prin procedeul interpretor se generează cod obiect executabil în cantitate limitată şi anume,

numai pentru linia (sau instrucţiunea) de program curentă. Simplificând lucrurile, se citeşte din fişierul sursă câte o linie de program care este convertită în cod obiect executabil care se rulează dacă în urma conversiei nu au rezultat erori.

Schema de lucru în procedeul interpretor este cea din figura 1.13.2. Conform figurii 1.13.2 fazele interpretării unei linii: - Analiza instrucţiunii din punct de vedere sintactic. În această fază se analizează

folosirea corectă a sintaxei limbajului; - Compilarea liniei. Această fază se concretizează prin convertirea instrucţiunii

respective în cod obiect executabil;

Page 53: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 41

- Execuţia liniei, fază în care codul obiect executabil obţinut este trimis către microprocesor (via sistemul de operare) care îl execută;

- Salt la linia următoare, dacă mai există.

Linia 1

Linia 2

Linia i

Linia i+1

Linia n

Fişier sursă

Analizăsintactică

Compilare

Execuţie

Salt la liniaurmătoare

Semnalareeroare

STOP

Interpretare linie i

eroare sintactică

erori de definire

erori de execuţie

Fig. 1.13.2. Erorile care pot apare în decursul acestor faze sunt: - Erori sintactice, cauzate de scrierea incorectă a instrucţiunii sau a parametrilor ei (date

sau variabile); - Erori de definire, cauzate de date sau variabile nedefinite sau folosire greşită a tipurilor

variabilelor; - Erori de execuţie, cauzate de depăşirea capacităţii de reprezentare a numerelor în

calculator în urma unor operaţii aritmetice care au produs erori cumulate, folosirea de operaţii aritmetice nepermise (împărţire la zero, radical sau logaritm din număr negativ, etc).

În toate aceste cazuri eroarea este semnalată şi programul este oprit. În afară de aceste erori mai există şi erorile de logică. Pe acestea sistemul nu le semnalează

ele ţinând de concepţia greşită a programatorului. Consecinţele acestor erori pot fi imprevizibile, de la aparenţa bunei desfăşurări a execuţiei dar cu rezultate eronate, şi până la oprirea datorită unor erori de execuţie sau, mai grav, blocarea sistemului de operare.

Avantajul programului interpretor este acela că erorile apărute într-o linie de program sunt depistate imediat, ceea ce face depanarea programului mai uşoară. În plus, programele scrise în limbaje interpretoare pot fi rulate şi pe părţi (cu unele restricţii), ceea ce, de asemenea, uşurează depanarea.

Un alt avantaj al unui program scris în limbaj de interpretare este acela de a permite alocarea dinamică a memoriei, adică variabilitatea în cursul execuţiei a zonei de memorie alocată memorării variabilelor. Acest lucru are un afect favorabil asupra economicităţii folosirii memoriei.

Page 54: Programarea Calculatoarelor si Limbaje de Programare

Capitolul 1. Elemente de bază în informatică 42

Dezavantajul major al procedeului rezultă din analiza timpului de execuţie consumat. Timpul total de execuţie al unei instrucţiuni se calculează cu relaţia:

Timp de execuţie total = Timp de analiză + Timp de compilare + Timp de execuţie efectivă Timpul de execuţie efectivă este cu mult mai mic decât ceilalţi timpi. În plus, în cazul unor

blocuri de program ciclice, o instrucţiune care se repetă este executată prin reparcurgerea tuturor etapelor de mai sus cu toate că ea a mai fost analizată şi compilată anterior.

Exemple de limbaje interpretoare sunt BASIC şi LISP. Procedeul compilator.

Editare fişier sursă

Compilare program,testare,

depanare

Corectareaerorilor

Scriere fişier executabil

Executare program

Fig. 1.13.3.

Acest procedeu separă complet faza de analiză sintactică şi cea de compilare de faza de execuţie. Mai exact, programul sursă este analizat sintactic şi compilat o singură dată iar codul obiect executabil rezultat poate fi executat ori de câte ori este nevoie.

Depanarea este ceva mai dificilă, dar execuţia este mult mai rapidă.

Fazele parcurse în cadrul acestui procedeu sunt cele ilustrate de figura 1.13.3.

Programul este scris cu ajutorul unui editor de text "curat" adică unul care nu generează caractere netipăribile.

Compilarea se face ţinând cont de aceleaşi exigenţe ca şi la interpretor dar se face global, pentru toate instrucţiunile o dată.

Pot urma, după caz, testarea şi depanarea programului şi, dacă lucrurile au decurs bine, se realizează generarea fişierului cod obiect executabil.

Atenţie! Denumirea de cod obiect este una moştenită prin tradiţie încă de pe vremea când tehnica programării orientată pe obiecte nu apăruse şi, deci, nu are nici o legătură cu aceasta. Ea este folosită pentru a diferenţia codul binar rezultat după compilare de cel textual sau sursă.

O fază despre care, pentru a nu complica lucrurile, nu am vorbit până acum, este faza de editare a legăturilor. Ea există atât în limbajele interpretoare cât şi în cele complilatoare dar este mai evidentă în acestea din urmă unde trebuie realizată explicit sub controlul programatorului, spre deosebire de limbajele interpretoare unde este realizată automat.

Programele mari sunt compuse din module de cod obiect realizate de programator sau preluate din biblioteci de module existente.

În cadrul acestor module, adresele de memorie ale secvenţelor de cod sunt fictive, începând întotdeauna de la zero, deoarece nu se poate cunoaşte dinainte configuraţia finală a programului în memorie. Acest tip de module sunt numite cod obiect relocabil (sau repoziţionabil). Faza de compilare este de fapt compusă din două faze:

- compilarea propriu-zisă, care produce modulele de cod obiect relocabil; - legarea modulelor sau faza de editare de legături (linkeditare) în care sunt căutate în

biblioteci modulele referite modulele compilate, sunt calculate noile adrese de memorie conform succesiunii modulelor, şi sunt rescrise aceste adrese în toate modulele concurente ale aceluiaşi program, rezultatul fiind codul obiect executabil.

În WINDOWS acest concept este generalizat, folosindu-se intens modulele de tip DLL (dynamic link libraries – biblioteci cu legare dinamică) editarea de legături făcându-se chiar în timpul execuţiei. Acest fapt poate produce o anume încetinire a execuţiei dar asigură flexibilitatea şi economicitatea folosirii memoriei ca şi reducerea efortului programatorului.

Page 55: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 43

Cap.2. Limbajul C §2.1. Caractere Caracterele folosite la scrierea programelor în limbajul C alcătuiesc mulţimea de mai jos: a. Litere mari: ABCDEFGHIJKLMNOPQRSTUVWXYZ b. Litere mici: abcdefghijklmnopqrstuvxyz c. Caracterul de subliniere: _ d. Caracterele numerice> 0123456789 Caracterele din categoriile a, b, c, d pot servi la scrierea constantelor, identificatorilor şi a

cuvintelor cheie care vor fi descrise mai târziu. Literele mari şi mici sunt interpretate distinct. Astfel, Functie şi functie sunt entităţi C diferite.

c. Caractere cu destinaţii diverse: ! “ % & | ‘ ( ) * + - , . / : ; < = > ? [ ] ^ { } ~ se folosesc fie cu valoarea recunoscută de limbajul C în scrierea instrucţiunilor C, a operatorilor, etc, fie, împreună cu acelea din categoriile a, b, c, d, în componenţa şirurilor de caractere.

f. Caractere netipăribile (secvenţe ESC). Aceste secvenţe sunt combinaţii speciale de caractere care, incluse într-un şir de caractere delimitat de ghilemele “...”, forţează trimiterea către dispozitivul de ieşire de destinaţie a unui caracter ASCII care nu are reprezentare grafică sau care nu poate fi afişat pe ecran prin scrierea obişnuită. Ele sunt următoarele:

\n pentru salt la linie nouă (New Line); \t pentru tabulare orizontală; \v pentru tabulare verticală; \b pentru backspace; \r pentru revenire la început de linie (Carriage Return); \f pentru avans la pagină nouă (Form Feed); \’ pentru tipărirea semnului apostrof ‘ ; \\ pentru tipărirea semnului backslash \ ; \ddd pentru caracter ASCII în notaţie octală, unde d simbolizează o cifră (digit); \xdd pentru caracter ASCII în notaţie hexazecimală; De exemplu, \015 este caracterul ASCII cu codul zecimal 1X8+5=13, acelaşi cu \x00D,

adică CR (Carriage Return).

§2.2. Atomi lexicali Atomii lexicali sunt caractere simple sau grupate care, în cursul procesului de compilare,

capătă o anumită semnificaţie în funcţie de sintaxa limbajului şi de contextul lor de apariţie. 2.2.1. Identificatori Identificatorii sunt nume utilizabile pentru reprezentarea variabilelor, constantelor,

tipurilor, funcţiilor şi etichetelor în cadrul programului. Aceste nume se crează prin specificarea lor în declaraţii.

Identificatorul este o secvenţă (grup) de caractere compusă din litere, cifre şi simbolul de subliniere _.

Este obligatoriu ca identificatorul să înceapă cu o literă sau cu caracterul _ dar, deoarece prin convenţie, identificatorii care încep cu _ au, în general, semnificaţii speciale (atribuite de furnizorii de medii de programare a aplicaţiilor în C), programatorii de C obişnuiţi trebuie să evite începerea unui identificator cu caracterul _.

Reamintim că C face distincţie între literele mari şi cele mici. De exemplu punct3d şi punct3D sunt identificatori diferiţi.

2.2.2. Numere Un număr este o secvenţă de cifre şi litere de forma pî.pz ez, unde pî este întreagă, pz este

Page 56: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 44

partea zecimală şi ez este exponentul zecimal de forma Ep sau ep unde p este puterea lui 10, cu semnul + sau -.

De exemplu: 1.23e+2 este echivalent cu 123. Observaţie: în limbajul C numărul nu are semn. Apariţia semnului - în faţa unui număr

este deja o aplicare a operatorului de negare aritmetică - aplicat numărului respectiv.

2.2.3. Constante Constantele sunt de două tipuri: a. Constante caracter, de forma ‘caracter’. De exemplu ‘A’. b. Constante şir, de forma “şir_de_caractere”. De exemplu “Sir”. Observaţie: în cuprinsul unei constante caracter ca şi al unei constante şir, pot intra

secvenţe ESC. De exemplu: ‘\t’ sau “Rezultate:\n”. 2.2.4. Delimitatori de comentariu Încadrarea între perechile /* şi */ a unui şir de caractere produce ignorarea acestuia de către

compilator. În C++ acelaşi efect se obţine şi pentru toate caracterele care urmează de la perechea // până la capătul liniei.

2.2.5. Cuvinte cheie Cuvintele cheie sunt identificatori predefiniţi care au înţeles special pentru compilatorul de

C. Aceste cuvinte nu pot fi redefinite iar utilizarea lor trebuie limitată la scopul predestinat. Iată, mai jos, câteva exemple de cuvinte cheie mai des utilizate:

asm do huge static auto double if struct

break else int switch case extern long typedef char far near union const float return unsigned

continue for short void default goto sizeof while

2.2.6. Operatori Operatorii sunt combinaţii de caractere speciale care specifică modul de atribuire şi de

transformare a valorilor (operanzilor). În funcţie de numărul de operanzi asupra cărora se aplică, operatorii pot fi clasificaţi în operatori unari, binari, ternari şi operatori de asignare combinaţi.

2.2.6.1. Operatori unari Un operator unar este aplicat asupra unui singur operand. Asociativitatea operatorilor,

adică ordinea de aplicare a operatorilor consecutivi, pentru această categorie, este de la dreapta la stânga. Aceşti operatori sunt:

a. Operatori de complementare: - Negarea aritmetică (-). Acest operator, aplicabil asupra unui operand întreg sau în

virgulă mobilă, produce valoarea negativă a operandului. De exemplu: short a=122, b; ..... b=-a; .....

produce atribuirea valorii -122 lui b.

Page 57: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 45

- Negare la nivel de bit (~). Acest operator, aplicabil numai valorilor întregi, transformă biţii 0 în 1 şi invers. De exemplu:

unsigned short a=0x0023; /* a=00000000100011 */ ..... a=~a; /* a=11111111011100 */ ..... produce rezultatul 0xFFDC atribuit lui a. - Negarea logică (!). Acest operator, NOT logic, aplicat asupra unui opeand de tip întreg,

virgulă mobilă sau pointer, produce valoarea zero dacă operandul este adevărat (diferit de zero) sau valoarea 1 dacă operandul este fals (egal cu zero). Rezultatul este de tip întreg. De exemplu:

int a=2, b=3, maxab; ..... if(!(a<b)) maxab=a; else maxab=b; ..... În acest exemplu (a<b) este o expresie formată cu operatorul relaţional <. Ea are ca rezultat

logic 1 dacă este adevărată şi 0 dacă este falsă. b. Operatori de indirectare şi adresă : - Operatorul de indirectare (*). Acest operator este folosit la definirea de variabile

pointer prin prefixarea operandului. Pe această cale se realizează o accesare indirectă, prin intermediul pointerului. Rezultatul este valoarea către care punctează operandul iar tipul rezultatului este tipul adresat de operand. De exemplu:

int * pv; defineşte pv ca un pointer către o valoare de tip întreg. Importanţa acestui mod de adresare se va putea vedea de abia la definiţia funcţiilor care

întorc ca rezultat pointeri către structuri conţinând rezultate obţinute în corpul funcţiilor. - Operatorul de adresare (&). Acest operator este folosit pentru aflarea adresei

operandului. Această adresă poate fi folosită pentru a fi atribuită unui pointer sau pentru a o transmite unei funcţii cu efect lateral asupra entităţii căreia îi aparţine adresa. De exemplu:

functie(a, &b); este apelul unei funcţii denumită functie care primeşte ca argumente valoarea a şi adresa

lui b. În corpul funcţiei au loc procese care modifică valoarea lui b (b poate fi şi o structură). La ieşirea din funcţie, orice evaluare a lui b va găsi noua sa valoare.

c. Operatorul de lungime sizeof: Acest operator, aplicat asupra unui operand oarecare, determină dimensiunea de memorie

alocată operandului respectiv. Forma de aplicare a operatorului este: sizeof(operand), iar rezultatul returnat este lungimea exprimată în octeţi necesară memorării operandului. Cu ajutorul operatorului sizeof se poate asigura independenţa de calculator a lungimii datelor, calculul acesteia căzând în sarcina compilatorului, ceea ce este deosebit de folositor în cadrul operaţiilor de alocare a memoriei.

2.2.6.2. Operatori binari Operatorii binari sunt aplicabili asupra a doi operanzi. În acest caz, asociativitatea este de

la stânga la dreapta. a. Operatori multiplicativi: - Înmulţirea (*), specifică înmulţirea operanzilor. De exemplu: float x=3.0, y; int i=2; ..... y=x*i;

Page 58: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 46

..... va produce rezultatul în virgulă mobilă 6.0 atribuit lui y. - Înpărţirea (/), specifică înpărţirea primului operand la al doilea. Dacă ambii operanzi

sunt întregi, rezultatul este rotunjit la valoarea întreagă cea mai apropiată de zero. De exemplu:

float x; int a=3, b=2; ..... x=a/b; ..... produce rezultatul întreg 1 convertit în virgulă mobilă şi atribuit lui x, deci x=1.0. - Modulo (%), specifică restul înpărţirii primului operand la al doilea. De exemplu: int a=8, b=3, r; ..... r=a%b; ..... produce rezultatul întreg 2 atribuit lui r; b. Operatori aditivi : - Adunarea (+), specifică adunarea primului operand cu al doilea, operanzii putând fi de

tip întreg sau în virgulă mobilă. - Scăderea (-), specifică scăderea celui de al doilea operand din primul, operanzii putând

avea tip întreg sau virgulă mobilă. Atât adunarea cât şi scăderea se pot aplica asupra unui prim operand de tip pointer şi unui

al doilea operand de tip întreg. Tehnica aplicată de compilator este asemănătoare în ambele cazuri şi constă din înmulţirea valorii întregi cu lungimea tipului către care punctează pointerul, urmată de adunarea sau, după caz, scăderea rezultatului obţinut din adresa operandului de tip pointer. Rezultatul este de tip pointer şi trebuie atribuit unei variabile pointer de acelaşi tip.

De exemplu:

#include <conio.h> #include <stdio.h> void main() {int i=3, j=2; float a[5]={0,1,2,3,4}, *pa1, *pb1; pa1=&a[4]-i; pb1=&a[3]-j; printf(“*pa1=%f, *pb1=%f\n”, *pa1, *pb1); getch(); }

În ambele cazuri pa1 şi pb1 reprezintă adresa celui de al doilea element al tabloului a şi ca urmare programul va afişa:

*pa1=1.000000, *pb1=1.000000 c. Operatori relaţionali: Aceşti operatori testează valabilitatea relaţiei dintre doi operanzi. Rezultatul produs este 1

dacă relaţia este adevărată, sau 0 dacă relaţia este falsă. Tipurile operanzilor pot fi oricare dintre tipurile întreg, virgulă mobilă sau pointer. Rezultatul produs este de tip întreg (int).

Comparaţiile între operanzi de tip pointer ai aceluiaşi masiv (tablou) de date au sens deoarece, în acest caz, se compară poziţia relativă a adreselor de memorie care cresc în ordinea de creştere a indicilor în tablou. Comparaţia dintre o dată oarecare şi una de tip pointer, în general, poate să nu aibă sens deoarece adresele de stocare ale datelor din masive

Page 59: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 47

diferite sunt stabilite de către compilator după o lege necontrolabilă de către programator. Există următorii operatori relaţionali: < a<b a strict mai mic decât b > a>b a strict mai mare decât b <= a<=b a mai mic sau egal cu b >= a>=b a mai mare sau egal cu b == a==b a egal cu b != a!=b a diferit de b d. Operatori de deplasare : Aceşti operatori sunt de două tipuri: - operatorul de deplasare la stânga <<, şi - operatorul de deplasare la dreapta >>. Operaţiile efectuabile cu aceşti operatori au formele: x << n şi x>>n. Atât x cât şi n sunt de

tip întreg, iar n trebuie să fie pozitiv şi mai mic în valoare sau egal cu numărul de biţi pe care este reprezentat x, altfel rezultatul este indefinit. Valoarea n reprezintă numărul de deplasări ale biţilor lui x. După deplasarea biţilor spre stânga sau spre dreapta, se face completarea cu zero la dreapta, respectiv la stânga.

De exemplu:

#include <conio.h> #include <stdio.h> void main() {unsigned x=65, y; y=x<<1; printf(“x=%u, y=%u\n”,x,y); getch(); }

În acest program valoarea întreagă fără semn x=65, adică 01000001, este deplasată la stânga cu o poziţie obţinându-se ca rezultat valoarea 10000010, adică 130, atribuită lui y şi, ca urmare, programul va afişa:

x=65, y=30

e. Operatori la nivel de bit: - ŞI la nivel de bit (&), produce ca rezultat 1 dacă ambii biţi sunt 1, şi 0 în caz contrar; - SAU INCLUSIV la nivel de bit (|), produce rezultatul 0 numai dacă ambii biţi sunt 0, şi

1 în caz contrar; - SAU EXCLUSIV la nivel de bit (^), produce rezultatul 1 dacă numai unul dintre biţi

este 1, şi 0 în caz contrar; Pentru toţi aceşti operatori, operanzii trebuie să fie de tip întreg, chiar dacă tipurile de

întregi sunt diferite. De exemplu:

#include <conio.h> #include <stdio.h> void main() {unsigned x=1, y=2, z=3, x1, y1, z1; x1=x&y; y1=x|y; z1=x^y; printf(“x&y=%u x|y=%u x^z=%u\n”, x1, y1,z1); getch(); }

Reprezentările binare sunt: pentru x 00000001, pentru y 00000010 şi pentru z 00000011. Rezultatele sunt: pentru x1=00000001 & 00000010 se obţine 00000000, adică valoarea zecimală 0;

Page 60: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 48

pentru y1=00000001 | 00000010 se obţine 00000011, adică valoarea zecimală 3; pentru z1=00000001 ^ 00000011 se obţine 00000010, adică valoarea zecimală 2, şi, ca urmare, programul va afişa: x&y=0 x|y=3 x^y=2 f. Operatori logici : În cazul utilizării operatorilor logici tipurile operanzilor pot fi întregi, virgulă mobilă sau

pointer, şi pot fi diferiţi între ei. Evaluarea operanzilor are loc de la stânga la dreapta. Dacă evaluarea primului operand este

suficientă pentru a determina rezultatul, evaluarea celui de al doilea operand nu mai are loc. Evaluarea operanzilor se face numai în sensul echivalării cu zero. Rezultatul operaţiei logice este 0 sau 1.

- ŞI logic (&&), produce ca rezultat valoarea 1 numai dacă ambii operanzi sunt diferiţi de 0.

- SAU INCLUSIV logic (||), produce ca rezultat valoarea 1 dacă cel puţin unul dintre operanzi este diferit de 0.

De exemplu: #include <conio.h> #include <stdio.h> void main() {float x1=1.5, x2=3, x; printf(“x=”); scanf(“%f”, &f); if(x>x1 && x<x2) printf(“x%f este interior domeniului x1=%f - x2=%f\n”,x,x1,x2); else printf(“x%f este exterior domeniului x1=%f - x2=%f\n”,x,x1,x2); getch(); }

Ca urmare a rulării acestui program, se va afişa cererea: x= Întroducând valoarea 1.6 programul va afişa:

x=1.600000 este interior domeniului x1=1.500000 - x2=3.000000

g. Operatorul de evaluare secvenţială (,) : Acest operator se foloseşte atunci când sintaxa limbajului impune o singură expresie, dar nevoile

de programare cer evaluarea mai multor expresii. În acest caz, expresiile separate prin virgule sunt evaluate de la stânga la dreapta, rezultatul final fiind cel provenit din evaluarea ultimei expresii.

Ca exemplu, să presupunem că o funcţie admite numai doi parametri, având forma f(x,y), dar x trebuie să fie obţinut din nişte operaţii intermediare. Se poate scrie, de exemplu:

f((a++, x-=a), y) ceea ce într-o scriere obişnuită ar fi apărut ca trei instrucţiuni: a=a+; x=x-a; f(x,y); Observaţie: A nu se confunda rolul virgulei ca separator al parametrilor funcţiei cu virgula

ca operator de secvenţiere a evaluării expresiilor din primul parametru (cel închis între paranteze) al funcţiei, rolurile lor fiind complet diferite în cele două contexte. În cazul expresiei secvenţiale (a++, x=-a) este evaluată mai întâi incrementarea lui a, adică a++, şi abia apoi operaţia x=x-a al cărei rezultat este transmis funcţiei f ca prim parametru.

2.2.6.3. Operatorul ternar condiţional Numit, pe scurt, operator condiţional, acesta are forma: operand1 ? operand2 : operand3

Page 61: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 49

Algoritmul de evaluare constă, mai întâi, din evaluarea lui operand1. Dacă acesta este adevărat (diferit de zero), rezultatul returnat este cel provenit din evaluarea lui operand2, iar altfel este returnat rezultatul provenit din evaluarea lui operand3. De exemplu:

maxab = a>b ? a : b; Operandul operand1 este, aici, expresia a>b. Dacă aceasta este adevărată, valoarea lui a ca

operand2 va fi returnată ca rezultat şi atribuită lui maxab, altfel lui maxab i se va atribui valoarea lui b ca operand3.

2.2.6.4. Operatorul de atribuire simplă şi compusă Operaţia de atribuire simplă foloseşte operatorul = şi are forma: operand1=operand2 şi constă în atribuirea valorii lui operand2 lui operand1. Pentru a reduce lungimea programelor sursă, a fost introdusă operaţia de atribuire

compusă, având forma generală: operand1 operator= operand2; ceea ce este echivalent cu: operand1 = operand1 operator operand2; Astfel, se pot forma combinaţiile:

Operaţie Echivalent Denumire şi efect a*=; a=a*b multiplicare cu atribuire - multiplicare lui a cu b şi atribuire lui a a/=b; a=a/b; înpărţire cu atribuire - înpărţirea lui a la b şi atribuire lui a a%=b; a=a%b; rest cu atribuire - a modulo b cu atribuire lui a a+=b; a=a+b; adunare cu atribuire - a adunat cu b şi atribuire lui a a-=b; a=a-b; scădere cu atribuire - b scăzut din a şi atribuire lui a a<<=n; a=a<<n; deplasare la stânga cu atribuire - deplasarea la stânga a lui a cu n biţi şi

atribuire lui a a>>=n; a=a>>n; deplasare la dreapta cu atribuire - deplasarea la dreapta a lui a cu n biţi

şi atribuire lui a a&=b; a=a&b; ŞI la nivel de biţi cu atribuire - a ŞI b cu atribuire lui a a|=b; a=a|b; SAU INCLUSIV la nivel de biţi cu atribuire - a SAU INCLUSIV b cu

atribuire lui a a^=b; a=a^b; SAU EXCLUSIV la nivel de biţi cu atribuire - a SAU EXCLUSIV b

cu atribuire lui a Tot cu scopul reducerii scrierii programelor sursă au fost introduşi şi operatorii unari de

incrementare ++ şi de decrementare --. Ei pot să apară în formele: a. forma prefixată: operator operand, adică ++operand sau -–operand, iar

rezultatul operaţiei este operand + 1 sau operand - 1, identic cu starea operandului după operaţie.

b. forma postfixată: operand operator, adică operand++ sau operand--, iar rezultatul operaţiei este în ambele cazuri operand, identic cu starea operandului înainte de operaţie, starea operandului după operaţie fiind, ca şi mai înainte, operand +1 sau operand - 1.

De exemplu: int x=2, y; ..... y=++x; ..... va avea ca rezultat y=x=3, deoarece x este mai întâi incrementat şi abia apoi rezultatul este atribuit lui y, pe când: y=x++

Page 62: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 50

va avea ca rezultat y=2 şi x=3, deoarece rezultatul lui x++ este starea dinainte de incrementare, adică valoarea 2 care este atribuită lui y, starea lui x după incrementarea postfixată fiind valoarea 3.

2.2.7. Precedenţa operatorilor Precedenţa reprezintă prioritatea la evaluare a unui operator. Aceasta este importantă

numai în prezenţa altui operator de precedenţă diferită. Expresiile formate cu operatori de precedenţă mai înaltă sunt evaluate primele.

În tabelul 2.1.1 operatorii sunt listaţi astfel: operatorii situaţi pe aceeaşi linie au aceeaşi preecedenţă, iar pe verticală operatorii de la începutul tabelului au precedenţa cea mai înaltă, cei de la sfârşit având precedenţa cea mai scăzută.

Dacă la un nivel al unei expresii apar mai mulţi operatori cu precedenţă egală, evaluarea se realizează, în funcţie de asociativitatea operatorului (direcţie de evaluare), de la stânga la dreapta (S → D) sau invers (D → S), după caz.

Tabelul 2.2.1. Tip de operaţie Operator Asociativitate

expresie ( ) [ ] -> . (S → D) unară - ~ ! * &(adresa) ++ -

- (D → S)

multiplicativă * / % (S → D) aditivă + - (S → D) deplasare << >> (S → D) relaţională (inegalitate) < > <= >= (S → D) relaţională (egalitate) == != (S → D) ŞI la nivel de biţi & (S → D) SAU EXCLUSIV la nivel de biţi ^ (S → D) SAU INCLUSIV la nivel de biţi | (S → D) ŞI logic && (S → D) SAU logic || (S → D) condiţie ternară ? : (D → S) atribuire simplă şi combinată = *= /= %= += -= (D → S) evaluare secvenţială , (S → D)

Datorită nivelelor de precedenţă ale operatorilor, compilatorul tinde să evalueze operaţiile prin considerarea grupărilor între operatori şi operanzi în raport cu aceste nivele. Pentru începători, este indicat ca ei să se folosească de paranteze pentru a delimita grupările dorite, cu scopul de a evita erorile datorate scăpărilor din vedere ale nivelelor de precedenţă.

§2.3. Tipuri de date standard 2.3.1. Tipuri de bază Tipurile de bază admise de limbajul C sunt următoarele: - Date de tip text, caractere simple sau şiruri de caractere, tip desemnat prin cuvântul cheie char; - Date de tip numeric întreg, pentru care se folosesc cuvintele cheie int, short şi long; - Date de tip real (în virgulă mobilă), desemnate prin cuvintele cheie float, double şi long

double; - Date de tip enumerativ, desemnate prin cuvântul cheie enum; - Pointeri, sau date care conţin ca informaţii adresa către locaţiile de memorie care conţin

Page 63: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 51

data propriu-zisă. Deoarece datele referite au propriul lor tip, pointerii sunt desemnaţi printr-o prefixare cu caracterul * a notaţiei entităţii pointer, prefixul * şi notaţia pointerului urmând unui cuvânt cheie care desemnează tipul, ca mai jos:

tip * nume_pointer şi se citeşte “nume_pointer punctând către tip”; - Tipul void care, după caz, dacă se referă la funcţii are semnificaţia de numic, iar dacă se

referă la pointeri are semnificaţia de orice. 2.3.2. Modificatori de tipuri Modificatorul de tip este un element ataşat tipurilor aritmetice întregi, referindu-se la

reprezentarea cu sau fără semn. Astfel, tipul signed (care, de altfel, este implicit) se referă la reprezentări cu semn, iar tipul

unsigned se referă la reprezentări fără semn (numere pozitive). Pot fi folosite abreviaţiile din tabelul 2.3.1.

Tabelul 2.3.1. Tip Abreviaţie

signed char char signed int signed, int signed short int signed short, short signed long int signed long, long unsigned char fără abreviaţie unsigned int unsigned unsigned short int unsigned short unsigned long int unsigned long

2.3.3. Stocare în memorie şi domenii de valori În tabelul 2.3.2 sunt redate numerele de octeţi necesare stocării în memorie şi domeniile de

valori reprezentabile pentru tipurile de bază. Tabelul 2.3.2

Tip Stocare Domeniu de valori char 1 -128...127 int 2 -32768...32767 short 2 -32768...32767 long 4 -2147483648... 2147483647 unsigned char 1 0...255 unsigfned int 2 0...65535 unsigned short 2 0...65535 unsigned long 4 0...4294967295 float 4 3.4E-38...3.4E+38 double 8 1.7E-308...1.7E+308 long double 10 3.4E-4932...1.1E+4932

2.3.4. Tipul enumeraţie Tipul enumeraţie este un tip întreg special, care permite unei variabile enumerative să ia

valori într-0 mulţime finită de numere întregi numite constante enumerative. Pot exista următoarele variante de definire:

enum nume_tip_enumerare {mulţime_enumerativă}

Page 64: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 52

unde: {mulţime_enumerativă} este o listă de forma: {definire_constanta_enumerativă_0,..., definire_constantă_enumerativă_0} iar: definire_constantă_enumerativă_i are forma: constantă_enumerativă_i [=valoare_atribuită_explicit] Astfel, se poate defini: enum meniu {aperitiv, supa, pilaf, placinta}; caz în care valorile atribuite de către compilator sunt: aperitiv=0, supa=1, pilaf=2,

placinta=3. Dacă se doreşte să se excludă aperitiv din meniu, dar să se păstreze aceleaşi numere,

trebuie să se definească: enum meniu {supa=1, pilaf, placinta}; Observaţie: valorile constantelor enumerative nu mai pot fi schimbate. O dată tipul definit, se pot defini variabilele enumerative în maniera: enum nume_tip_enumerare variabilă_enumerativă ca de exemplu: enum meniu fel_de_mancare Această definiţie stabileşte numai faptul că fel_de_mancare este de tipul meniu, adică

poate lua ca valori numai valorile definite în mulţimea enumerativă. Ulterior se poate scrie: fel_de_mancare=pilaf; ceea ce va produce atribuirea valorii întregi 2 variabilei fel_de_mancare.

2.3.5. Tipul structură Structura defineşte un stoc de date care pot fi de diferite tipuri. Sintaxa definiţiei

structurii foloseşte cuvântul cheie struct şi poate avea una dintre formele: struct nume_tip_structura {lista_membri_structura} [structura_1,...,structura_k]; struct nume_tip_structura structura_1 [,...,structura_k]; struct {lista_membri_structura} structura_1 [,...,structura_k]; În lista membrilor structurii nu pot intra constante cu atribuire iniţială, dar membrii

structurii pot fi de orice tip, inclusiv structuri. Astfel, se poate defini, de exemplu: struct punct2D {float x,y;} punctA; struct triunghi {punct2D a,b,c} ABC; struct cerc {punct2D centru; float raza} cerc_1;

Referirea unui membru al structurii se face prin notaţia structura.membru, ca de exemplu: punctA.x=2.5; punctA.y=3.0; cerc_1.centru=punctA; cerc_1.raza=5;

Deşi membrii structurilor nu pot fi iniţializaţi, structurile pot fi iniţializate după ce au fost definite ca tip.

Astfel, se poate scrie, de exemplu: struct punct2D r{0,0}, s{2,0}, t{0,2}; struct triunghi {r,s,t};

Dacă referirea structurii se face indirect, ca pointer, notaţia (*structura).membru se poate scrie prescurtat pstructura->membru, unde pstructura este un pointer de tip structură către un tip.

De exemplu:

Page 65: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 53

#include <conio.h> #include <stdio.h> struct punct2D {float x,y;}; void oglinda_oy(punct2D *pct) {pct->x=-pct->x;} void main() {struct punct2D A={5,3}; printf(“Punctul original A are x=%f si y=%f\n”, A.x, A.y); oglinda_oy(&A); printf(“Punctul oglindit A’ are x=%f si y=%f\n”, A.x, A.y); getch(); }

Ca urmare a rulării programul afişează: Punctul original A are x=5.000000 si y=3.000000 Punctul oglindit A’ are x=5.000000 si y=3.000000

Modul de folosire a adresării indirecte se observă din definiţia funcţiei oglinda_oy.

2.3.6. Tipul uniune Cuvântul cheie care desemnează acest tip este union. Din punct de vedere formal tipul uniune apare scris la fel ca tipul structură. Deosebirea este

că, în timp ce tipul structură alocă spaţiul de memorie pentru fiecare membru al structurii, tipul uniune alocă un singur spaţiu de memorie având lungimea egală cu lungimea celui mai lung tip de membru al uniunii. Astfel, tipul:

union orice_tip (char c; int i; float f; double d;) tip_data va permite salvarea în variabila tip_data a unei informaţii de oricare tip dintre cele

patru tipuri membre ale uniunii orice_tip. Referirea unui membru al uniunii se face, ca şi în cazul structurilor prin operatorul punct

(.) sub forma uniune. membru Orice dată este stocată în variabila uniune începând de la prima locaţie de memorie

rezervată uniunii şi este returnată conform tipului referit. Astfel, în exemplul următor:

#include <conio.h> #include <stdio.h> union tip_dublu {int i; float f;} ddata; void main() {ddata.f=1234.56e+5; printf(“ddata.f=%f\n”, ddata.f); printf(“ddata.i=%f\n”, ddata.i); getch() } rezultatul rulării va fi afişarea: ddata.f=123456000.000000 ddata.i=31040 ceea ce este corect pentru tipul float dar este greşit pentru tipul int. Aceasta se datorează faptului că citirea din memorie are loc numai pentru a parte a octeţilor stocaţi în uniune, conform tipului întreg.

Aceasta este o posibilă sursă de erori şi nu poate fi evitată decât prin grija strictă a programatorului de a ţine cont de ultimul tip stocat în uniune.

2.3.7. Date nemodificabile. Declaraţia const Pentru a preveni modificarea din greşeala programatorului a valorilor anumitor date care

trebuie să fie nemodificabile, se foloseşte declaraţia const, în forma:

Page 66: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 54

const tip_de_dată iniţializare_dată De exemplu:

const float pi=3.141593; are ca efect imposibilitatea de a mai schimba valoarea variabilei pi. În acest caz atribuirea: pi=2.5; va produce la compilare un mesaj de eroare care, în funcţie de compilatorul folosit, ar putea fi de forma: Error...: Cannot modify a const object

Observaţie: acelaşi efect îl are şi directiva preprocesor #define, dar mesajul de eroare este diferit.

2.3.8. Declaraţia typedef Această declaraţie are forma: typedef tip declaraţie şi are rolul de a crea denumiri sinonime pentru tipuri. De exemplu:

typedef int intreg; /* creaza un sinonim pentru tipul int */ typedef struct punct3D {float x,y,z} p3D; /* face ca punct3D si p3D sa fie utilizate cu acelasi rol */

§2.4. Conversii de tipuri de date 2.4.1. Conversia automată de tip Acest mod de conversie este realizat automat de către compilator la generarea codului

executabil, ori de câte ori într-o operaţie apar tipuri de date diferite. De exemplu, pentru a face operaţia:

rezultat_tip=valoare_int_1*valoare_float_2; compilatorul constată că în partea dreaptă tipul cel mai lung este float şi face o copie a lui

valoare_int_1 într-o zonă temporară de memorie de lungime sizeof(float), convertind acolo valoarea de tip int la valoare de tip float.

Apoi execută operaţia şi, la pasul următor, determină lungimea rezultatului operaţiei, adică sizeof(float) şi lungimea variabilei rezultat_tip, convertind valoarea rezultatului operaţiei la tipul variabilei rezultat_tip.

Dacă lungimea lui rezultat_tip este cel puţin egală cu lungimea rezultatului operaţiei, conversia se face fără erori.

Există o ierarhie a conversiei de la cea mai înaltă la cea mai scăzută, în ordinea: double → float → long → int → short Dacă conversia se face de la un nivel inferior la unul superior ea rezultă corectă. Dacă

conversia se face de la un nivel superior la unul inferior, ea poate rezulta eronată dacă mărimea numărului rezultat depăşeşte capacitatea de reprezentare a tipului destinaţie.

În exemplul anterior, dacă rezultat_tip este de tip int iar rezultatul operaţiei este mai mic decât 32767, numărul va fi convertit corect, altfel va fi convertit eronat.

2.4.2. Conversia explicită de tip. Operatorul cast Fie următoarea secvenţă de instrucţiuni:

val_float_1=3.0; val_int_2=4; val_int_3=5; rezultat_float=val_float_1+val_int_2/val_int_3;

Operaţia val_int_2/val_int_3, având doi operanzi de acelaşi tip (întreg), va avea rezultatul de tip int şi acesta, prin rotunjire, va fi egal cu zero. Ca urmare rezultat_float va căpăta valoarea 3.0.

Page 67: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 55

Dacă cel puţin unul dintre operanzii val_int_2 şi val_int_3 ar fi fost de tip float, înpărţirea lor ar fi fost convertibilă la tipul float (cel mai lung dintre tipurile float şi int) şi ar fi rezultat 0.8, iar rezultatul final ar fi fost cel corect, adică 3.8.

Deci, când din diferite motive legate de scrierea programului, nu este posibilă schimbarea tipului iniţial al datelor, se poate face uz de conversia explicită de tip folosind operatorul cast. Acesta are forma:

(tip) şi prefixează variabila a cărei conversie trebuie realizată. În consecinţă, pentru operaţia descrisă mai sus, se poate scrie una dintre variantele:

rezultat_float=val_float_1+(float)val_int_2/val_int_3; rezultat_float=val_float_1+val_int_2/(float)val_int_3; rezultat_float=val_float_1+(float)val_int_2/(float)val_int_3; ceea ce asigură, cel puţin pentru unul dintre operanzii val_int_2 şi val_int_3 (sau, respectiv, pentru ambii) conversia în timpul operaţiei la tipul specificat de operatorul cast şi, în consecinţă, producerea unui rezultat corect.

§2.5. Instrucţiuni Execuţia unui program scris în limbajul C este controlată prin instrucţiuni. Instrucţiunile pot fi: instrucţiuni simple, care vor fi trecute în revistă în acest capitol, sau

instrucţiuni compuse, formate din alte instrucţiuni. Instrucţiunile simple se termină cu caracterul “;” iar instrucţiunile compuse sunt

cuprinse între acolade {} şi se mai numesc şi blocuri. Pot fi folosite şi instrucţiuni vide care apar sub forma caracterului “;”. Orice instrucţiune poate fi precedată de o etichetă formată dintr-un nume urmat de

caracterul :, sub forma: nume_eticheta: Eticheta nu este utilă decât în cazul folosirii instrucţiunii goto sau switch. 2.5.1. Instrucţiunea expresie O expresie apare sub forma generală: expresie; Ca exemple de expresii se pot cita: - expresii de atribuire. De exemplu:

x=a+b; unde variabilei x i se atribuie suma variabilelor a şi b.

- expresii cu efect lateral. De exemplu: i++ unde i capătă valoarea i+1, sau f(x) unde este apelată funcţia f cu parametrul x. Aici se pot distinge cazurile:

a. O variabilă globală îşi modifică valoarea în corpul funcţiei f şi, în consecinţă, după apelul funcţiei f, programul va “vedea” această valoare modificată. Acelaşi lucru se întâmplă şi dacă x nu este variabilă globală dar este o adresă de variabilă, ca în cazul apelului funcţiei f(&x);. Acesta este cazul funcţiilor cu efect lateral;

b. funcţia f execută o anumită acţiune (de exemplu, tipăreşte pe ecran sau la imprimantă valoarea lui x) fără să aibă un alt efect;

c. funcţia f returnează un rezultat. Cum însă nu există nici o atribuire de forma y= f(x); rezultatul se pierde şi, în acest caz, nu există nici un efect.

Page 68: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 56

2.5.2. Instrucţiunea de decizie Forma generală a instrucţiunii de decizie este: if (condiţie) instrucţiune_1 [else instrucţiune_2] Instrucţiunile condiţionate instrucţiune_1 şi instrucţiune_2 pot fi instrucţiuni simple sau

compuse (blocuri), caz în care ele trebuie să fie încadrate de acolade. Alternativa else poate lipsi. Acţiunea instrucţiunii if este de a evalua mai întâi instrucţiunea condiţie şi, dacă aceasta

este adevărată (diferită de zero), de a executa instrucţiune_1 sau, în caz contrar, de a executa instrucţiune_2. De exemplu: if(a<=0) absa=-a; else absa=a;

Instrucţiunile if-else pot fi încuibate una în alta. În acest caz alternativa else se referă la ultima condiţionare if care nu are alternativă else. De exemplu: if(a<b) /* primul if */ if(c<a) minabc=c; /* al doilea if */ else minabc=a; /* primul else */ else /* al doilea else */ if(c<b) minabc=c; /* al treilea if */ else minabc=b; /* al treilea else */

Se observă din acest exemplu că al doilea else se referă la primuil if, iar al treilea else se referă la al treilea if.

Pentru încuibări mai complicate este indicat să se folosească acoladele pentru delimitarea blocurilor dorite fără echivoc, pentru a evita erorile de scriere a schemelor decizionale.

2.5.3. Instrucţiunea de selecţie Instrucţiunea de selecţie are forma genarală: switch (expresie_selectoare) {case i1: secventa_i1 [break;] ..... case in: secventa_in [break;] [default: secventa_d] }

unde: expresie_selectoare trebuie să producă un rezultat de tip întreg; etichetele i1,...,in trebuie să fie constante sau expresii cu valoare constantă de tip întreg şi trebuie să aibă valori distincte; secvenţele pot fi secvenţe de instrucţiuni sau pot fi vide; eticheta default: şi secventa_d asociată ei sunt opţionale.

Acţiunea de execuţie selectivă se desfăşoară astfel: 1. Se evaluează expresie_selectoare; 2. Se caută aceea dintre expresiile i1,...,in care are valoarea egală cu rezultatul evaluării lui

expresie_selectoare. Dacă o astfel de expresie este întâlnită, se vor executa toate secvenţele de instrucţiuni din corpul instrucţiunii switch până la eticheta default sau până la primul break întâlnit.

Dacă nici una dintre expresiile i1,...,in nu are valoare egală cu rezultatul dat de expresie_selectoare, este executată secvenţa de instrucţiuni asociată etichetei default, dacă aceasta există.

Întâlnirea unei instrucţiuni break transferă controlul execuţiei la prima instrucţiune care urmează instrucţiunii switch.

De exemplu: switch(i) {case 1: case 2:

Page 69: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 57

case 3: y=1; break; case 4: y=2; break; default: y=0; } rezultatul produs fiind y=1 pentru i=1, 2 sau 3, y=2 pentru i=4, şi y=0 pentru oricare altă valoare a lui i. Sau: switch (i) {case 1: y++; case 2: y++; case 3: y++; }

În acest caz rezultatele sunt: pentru i=1 se obţine y=y+3, pentru i=2 se obţine y=y+2, iar pentru i=3 se obţine y=y+1. Pentru oricare altă valoare a lui i, y rămâne neschimbat.

2.5.4. Instrucţiunea de ciclare for Forma generală a instrucţiunii for este: for([iniţializare];[condiţie];[actualizare]) instrucţiune; şi are ca efect următoarele acţiuni: a. se execută instrucţiunea iniţializare; b. se testează expresia condiţie. Dacă aceasta este adevărată, se execută instrucţiune; c. se execută instrucţiunea actualizare. În continuare se reiau numai paşii b şi c atât timp cât condiţie este adevărată. De exemplu:

#include <conio.h> #include <stdio.h> void main() {int i,a; for(a=1,i=1; i<=5; i++) a*=i; printf(“a=%i\n”,a); getch(); } va afişa rezultatul a=120

Dacă bucla for trebuie aplicată, nu asupra unei instrucţiuni ci asupra unui bloc de instrucţiuni, forma generală va fi:

for([iniţializare];[condiţie];[actualizare]) {bloc} În orice punct din interiorul blocului execuţia poate fi întreruptă printr-un break. Astfel,

pentru exemplul de mai sus, se poate scrie varianta: #include <conio.h> #include <stdio.h> void main() {int i,a=1; for(i=1;; i++) {a*=i; if(i>=5) break;} printf(“a=%i\n”,a); getch(); } care va afişa acelaşi rezultat.

2.5.5. Instrucţiunea de ciclare cu test iniţial, while Această instrucţiune are forma generală: while(condiţie) instrucţiune;

Page 70: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 58

respectiv, dacă se aplică asupra unui bloc de instrucţiuni: while(condiţie) {bloc} şi are ca efect executarea instrucţiunii sau a blocului, atât timp cât expresia de test condiţie

este adevărată. De exemplu, secvenţa: sum=0; i=1; while(i<=3) sum+=a; va produce rezultatul sum=3a. Ca şi la instrucţiunea for, şi la instrucţiunea while se poate forţa ieşirea din bloc printr-un

break.

2.5.6. Instrucţiunea de ciclare cu test final, do-while Această instrucţiune are forma generală: do instrucţiune; while(condiţie); respectiv, dacă se aplică asupra unui bloc de instrucţiuni: do {bloc} while(condiţie); şi are acelaşi efect ca şi instrucţiunea while cu test iniţial, dar testul condiţiei are loc abia la

sfârşitul ciclului. Aşadar, pe când ciclul while poate să nu execute de loc instrucţiune sau bloc dacă

condiţie este falsă de la început, ciclul do-while efctuează execuţia cel puţin o dată.

2.5.7. Instrucţiunea continue Această instrucţiune are sintaxa: continue; şi se foloseşte în blocurile instrucţiunilor for, while şi do-while, pentru a produce saltul

forţat la ciclul următor, prin ignorarea instrucţiunilor care apar după poziţia în care este amplasată.

De exemplu:

#include <conio.h> #include <stdio.h> void main() {float x=-2,y=1,z; while(++x<2) {if(x==0) continue; z=y/x; printf(“z=%f\n”,z); } getch(); } are ca efect evitarea executării împărţirii lui y prin x=0. Ca rezultat al rulării programul va afişa: z=-1.000000 z=1.000000 ceea ce arată că, din ciclul while, au fost executate numai operaţiile corespunzătoare valorilor x=-1 şi x=1.

2.5.8. Instrucţiunea de salt, goto Această instrucţiune are sintaxa: goto etichetă; şi are ca efect transferul execuţiei la instrucţiunea precedată de etichetă.

Page 71: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 59

Instrucţiunea goto şi eticheta referită pot fi amplasate numai în interiorul aceleiaşi funcţii.

Menţinerea acestei instrucţiuni are valoare istorică. Utilizarea ei este contrară regulilor de programare structurată şi este contraindicată.

Totuşi, ea poate fi folosită ca ieşire de urgenţă, definitivă, la detectarea unor cazuri de imposibilitate de continuare a algoritmului.

§2.6. Tablouri Tablourile sunt masive de date de acelaşi tip, memorate ca variabile indexate. Ca orice variabile, şi variabilele tablou sunt referite prin nume, iar o variabilă anume din

tablou este identificată prin indicele ei, baza de indexare pornind de la indicele zero considerat ca identificând primul element al tabloului.

Astfel, declaraţia: tip nume[număr_total] defineşte o variabilă tablou denumită nume, având număr_total de elemente de acelaşi tip

şi care ocupă un număr de locaţii de memorie egal cu număr_total*sizeof(tip). Referirea unui element al tabloului se face sub forma: nume[indice] De exemplu:

int a[5]; defineşte un vector (tablou cu o dimensiune) conţinând 5 elemente de tip int, iar prin

a[2]este referit al treilea element al vectorului. Abstracţie făcând de faptul că toate elementele tabloului sunt de acelaşi tip, tipul în sine

poate fi oricare (afară de tipul void), inclusiv structuri. Tablourile pot fi multidimensionale, în acest caz sintaxa de definire fiind: tip nume[număr_1][număr_2]... De exemplu:

float b[3][4]; este un tablou de elemente de tip float, cu două dimensiuni având 3 rânduri şi 4 coloane. Iniţializarea unui tablou se poate face în două moduri: a. implicit, prin scrierea valorii zero de către compilator în toate elementele tabloului. Astfel, definiţia:

float c[3]; produce umplerea cu valoarea 0 a tuturor elementelor tabloului c; b. explicit, prin definirea între acolade a valorilor tabloului, sub forma: tip nume[n]={valoare_1, valoare_2,...,valoare_n}; De exemplu:

float c[3]={1.0, 1.5, 2.0}; atribuie fiecărui element al tabloului c valorile dintre acolade, în ordine, de la stânga la

dreapta, astfel: c[0]=1.0, c[1]=1.5, c[2]=2.0

Puţin altfel stau lucrurile în cazul tablourilor de tip şir de caractere. Astfel, se poate defini: char mesaj[20]=”Apasa orice tasta\n”;

situaţie în care compilatorul completează elementele tabloului cu caracterele menţionate între ghilimele, cu condiţia ca şirul să nu depăşească numărul de elemente prescris, în cazul de faţă 20.

Metoda este destul de greoaie deoarece obligă programatorul la numărarea caracterelor şirului. Mult mai simplu este să se facă uz de iniţializarea cu lungime neprecizată, sub forma:

char mesaj[]=”Apasa orice tasta\n”;

Page 72: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 60

şi, în acest caz, compilatorul face el oficiul de numărare a caracterelor şi alocă tabloului mesaj spaţiul necesar.

Atribuirea unei valori pentru un element individual al unui tablou se poate face: - pentru elemente numerice, de exemplu: b[2]=3.0; - pentru elemente ale unui şir de caractere, de exemplu: mesaj[12]=’p’; Se poate reţine de aici că numai şirurile de caractere se definesc prin încadrare între

ghilimele: “...”,caracterele individuale fiind definite prin încadrare între apostrofuri: ‘X’. Din acest motiv, tablourile de caractere pot fi definite şi în forma din exemplul următor:

char nume[5]={‘G’,’i’,’g’,’i’,’\0’}; mod de definire care este identic cu cel numeric şi care, de fapt, este chiar o definire

numerică deoarece fiecare caracter este reprezentat (substituit) prin codul său numeric întreg în conformitate cu standardul ASCII.

În sfârşit, pentru definirea tablourilor multidimensionale se foloseşte încadrarea între acolade incuibate.

De exemplu: int a[2][3]={{1,2,3},{6,2,5}};

tehnica fiind valabilă şi pentru tablourile şir de caractere.

§2.7. Adrese şi pointeri

Fig.2.7.1.

2.7.1. Definiţia pointerilor În memoria calculatorului, orice entitate are conţinutul

stocat la o anumită adresă de memorie. Situaţia se prezintă ca în figura alăturată.

În limbajul C, pentru a obţine adresa_entitate se prefixează continut_entitate cu operatorul &.

O variabilă prin care se manipulează o adresă a unei entităţi se numeşte variabilă pointer. Denumirea provine de la a puncta către şi, aşa cum o arată şi figura de mai sus, este vorba de o adresă care punctează către o entitate sau, altfel spus, o entitate care este punctată de către o adresă. Deoarece entitatea trebuie să aibă un tip, acesta trebuie declarat conform sintaxei:

tip * adresa_entitate; În lumina celor enunţate mai sus, a scrie:

int continut_entitate; int *adresa_entitate; continut_entitate=175; adresa_entitate=&continut_entitate; *adresa_entitate=175; înseamnă a declara continut_entitate de tip întreg şi adresa_entitate ca o adresă care punctează către o variabilă de tip întreg. Urmează apoi atribuirea directă a valorii 175 variabilei continut_entitate. Ultimele două instrucţiuni realizează indirect ceea ce realiza instrucţiunea de atribuire directă şi anume: se atribuie variabilei de tip pointer către entitatea de tip întreg, adresa la la care se găseşte continut_entitate şi apoi se atribuie valoarea 175 entităţii de tip întreg către care punctează adresa_entitate.

Avantajul folosirii pointerilor constă în aceea că, prin acest procedeu, compilatorul cunoaşte şi tipul către care punctează adresa, adică numărul de octeţi în care este stocată entitatea, ceea ce degrevează programatorul de o foarte completă gestiune a spaţiului de memorie şi face programele sursă independente de tipul de calculator sau de tipul de implementare a limbajului C, adică asigură portabilitatea programelor sursă.

Din exemplul anterior trebuie reţinut că adresa_entitate trebuie obligatoriu să puncteze către tipul prin care este declarată continut_entitate. Din acest motiv, secvenţa de mai jos:

Page 73: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 61

float valoare_reala=15.73; int * pointer_catre_intreg; pointer_catre_intreg=&valoare_reala; este ilegală deoarece se încearcă atribuirea unei adrese de tip float unui pointer către o valoare întreagă.

2.7.2. Utilizarea variabilelor pointer Printr-o variabilă pointer se pot prelua şi transmite date. De exemplu:

adresa_entitate=&valoare_1; va conţine adresa variabilei valoare_1, apoi prin: temporar= *adresa_entitate; variabilei temporar i se transmite valoarea variabilei valoare_1. În continuare, prin: *adresa_entitate=valoare_2; variabila valoare_1, a cărei adresă este conţinută de adresa_entitate, capătă valoarea variabilei valoare_2.

În fine, prin: valoare_2= temporar; variabila valoare_2 capătă conţinutul variabilei temporar, adică conţinutul iniţial al variabilei valoare_1.

În acest mod, valoare_1 şi valoare_2 au schimbat reciproc valorile lor iniţiale.

2.7.3. Iniţializarea variabilelor pointer La o declaraţie de tipul: tip * adresa_entitate; variabila pointer adresa_entitate nu conţine o adresă către o entitate anume, ci doar este

făcută o înştiinţare a compilatorului asupra tipului de entitate către care se poate puncta. O iniţializare cu o adresă a unei entităţi anume se poate face prin secvenţa: tip entitate; tip * adresa_entitate=&entitate; De exemplu:

#include <conio.h> #include <stdio.h> void main() {char j=’W’,k; char *pj=&j; k=*pj; printf(“k=%c\n”,k); getch(); }

Prin acest program a fost făcută o atribuire indirectă a valorii de tip caracter de la variabila j la variabila k prin mecanismul de iniţializare a pointerului pj cu adresa lui j şi apoi de atribuire a acesteia lui k.

2.7.4. Relaţia dintre pointeri şi tablouri Numele unui tablou este o constantă a cărei valoare reprezintă adresa primului element al

tabloului. Din acest motiv, notaţiile tablou şi &tablou[0] sunt echivalente. Atunci, conform celor spuse la definirea pointerilor, accesul la primul element al tabloului se poate face fie prin *tablou fie prin tablou[0].

De la această regulă fac excepţie pointerii către tipul void şi pointerii către funcţii.

Page 74: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 62

Ca exemplu, fie secvenţa: int a[10], *ap;

Instrucţiunea următoare atribuie adresa primului element al tabloului a variabilei pointer ap: ap=a; ceea ce este echivalent cu instrucţiunea: ap=&a[0];

În schimb, atribuirile inverse: a=ap;

şi &a[0]=ap; sunt ilegale deoarece o adresă este o constantă nemodificabilă, căreia nu i se poate atribui o altă valoare.

2.7.5. Pointeri către pointeri Limbajul C poate defini variabile pointer care punctează către alte variabile pointer. În

acest caz prefixarea se face cu două asteriscuri: **. Generalizând, numărul de asteriscuri determină “nivelul de indirectare” al variabilei pointer.

De exemplu, declaraţiile şi atribuirile: int data_intreaga=3; int *pint_1, **pint_2; pint_1=&data_intreaga; pint_2=&pint_1; reflectă situaţia din figura 2.7.2:

Fig.2.7.2.

Desigur, adresele 1293 şi 3174 din figură sunt fictive, ele depinzând de acţiunea compilatorului, şi sunt date pentru a urmări corespondenţa dintre adresa şi conţinutul variabilei pointer.

2.7.6. Aritmetica pointerilor Limbajul C permite efectuarea numai a două operaţii asupra adreselor reflectate de

pointeri, şi anume adunarea şi scăderea, conform regulilor următoare: a. adunarea unui pointer cu un întreg i echivalează cu a aduna valoarea adresei stocate

de pointer cu valoarea i*sizeof(tip_pointer), unde tip_pointer este tipul către care punctează pointerul. De exemplu, secvenţa:

float tabel[3]={1.1,2.2,3.3}; float *p_tabel=tabel /* adresa primului element din tabel */ float valoare; valoare=*(p_tabel+1); va avea ca urmare preluarea de către variabila valoare a celui de al doilea element al

tabloului, adică 2.2; b. scăderea unui întreg i dintr-un pointer se interpretează la fel cu adunarea deoarece, în

acest caz, pointer-i este echivalent cu pointer+(-i). De exemplu, scriind: p_tabel=&tabel[2]; /* adresa ultimului element din tabel */ valoare=*(p_tabel-2); se va atribui variabilei valoare conţinutul primului element din tabel. Adică valoarea 1.1.

Page 75: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 63

Operaţiile de incrementare ++ şi decrementare – pot fi, de asemenea, aplicate pointerilor. Cele expuse pentru tablouri sunt valabile şi pentru şiruri deoarece acestea sunt de fapt

tablouri de caractere. De exemplu, secvenţa: char sir[]=”Cititor”, caracter; char *adresa_caracter=&sir[0] /* sau, echivalent, =sir */ for(i=1;i<6;i++) adresa_caracter++; caracter=*adresa_caracter; va transfera în variabila caracter valoarea celui de al 6-lea element al şirului "Cititor", deci caracterul “o”.

§2.8. Funcţii Spre deosebire de alte limbaje, limbajul C recunoaşte ca module componente ale unui

program numai funcţiile şi ele nu pot fi definite în interiorul altei funcţii.

2.8.1. Prototipul unei funcţii Prototipul unei funcţii este o simplă declaraţie, plasată în zona de început a programului,

declaraţie care are rolul de a înţtiinţa compilatorul asupra numărului şi tipurilor de argumente primite de funcţie, precum şi asupra tipului de rezultat returnat de către funcţie.

Forma generală a prototipului unei funcţii este următoarea: [clasa_de_memorare] tip_rezultat nume_functie([lista_tipuri_argumente]); unde: clasa_de_memorare poate fi de tipul static sau extern. Atributul static face ca funcţia

respectivă să nu fie vizibilă pentru programe definite în alte fişiere. Atributul extern este opţional şi implicit şi face funcţia respectivă vizibilă şi dintr-un alt fişier sursă;

tip_rezultat specifică tipul rezultatului returnat de funcţie. Din acest punct de vedere trebuie să existe concordanţa cu tipul de rezultat referit de instrucţiunea return. Dacă funcţia nu returnează nici un rezultat, atunci tip_rezultat este tipul void;

nume_functie este numele funcţiei. El trebuie să fie unic şi să nu coincidă cu vreunul dintre numele de funcţii standard ale limbajului C;

lista_tipuri_argumente are forma: tip_arg_1,...,tip_arg_n unde tip_arg_j este tipul argumentului j, j=1,2,...,n. Dacă funcţia nu primeşte nici un argument, atunci lista_tipuri_argumente va conţine

numai menţiunea void.

2.8.2. Definirea unei funcţii Definirea unei funcţii are forma: antet {corp_functie} unde antet are aproape aceeaşi formă cu prototipul funcţiei, şi anume: tip_rezultat nume_functie([lista_tipuri_argumente]); cu deosebirea că lista_tipuri_argumente are acum forma: tip_arg_1 nume_arg_1,..., tip_arg_n nume_arg_n unde nume_arg_j este numele intern (din funcţie) al argumentului j, j=1,2,...,n; {corp_functie} este un bloc de program conţinând declaraţii de variabile, constante şi

instrucţiuni.

2.8.3. Apelul unei funcţii O funcţie se apelează sub forma:

Page 76: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 64

nume_functie(nume_arg_1,...,nume_arg_n); unde: nume_arg_j, j=1,2,...,n, trebuie să desemneze un argument de tipul acceptat de

funcţie. Dacă funcţia nu primeşte nici un argument, atunci lista de argumente este vidă, de forma ().

2.8.4. Instrucţiunea return Într-o funcţie pot exista mai multe instrucţiuni return sau nici una. Atingerea unei

instrucţiuni return în cursul execuţiei produce întoarcerea în programul principal. Forma instrucţiunii return este:

return rezultat; unde: rezultat trebuie să fie de tipul tip_rezultat definit de prototipul funcţiei. Dacă funcţia nu produce nici un rezultat, instrucţiunea return are forma: return; Dacă acest lucru se produce la sfârşitul corpului funcţiei, instrucţiunea return poate lipsi.

2.8.5. Funcţia main Funcţia main reprezintă, de fapt, programul principal în limbajul C. Ea nu are nevoie de

prototip ci numai de definiţie, care apare în forma: [void] main([parametri]) {corp_functie} În versiunile timpurii de C, definiţia funcţiei main era precedată de tipul void, dar la

versiunile recente menţionarea lui nu mai este decât opţională, fiind menţinută pentru compatibilitatea cu programele sursă scrise pentru versiunile anterioare.

De obicei funcţia main nu are parametri. Acesta este cazul programelor lansate numai prin nume, fără parametri în linia de comandă. În aceste caz, lista de parametri este vidă:

main() {corp_functie} În sistemul de operare DOS un program poate fi lansat cu parametri în linia de comandă, în

forma generală: nume_program param_1, param_2,...,param_n Parametrii param_1, param_2,...,param_n trebuie preluaţi de program şi prelucraţi în

corpul său. În acest caz, funcţia main trebuie să apară cu o listă formată din doi parametri: main(int numar_par_com, char ** tabl_par){corp_functie} unde: numar_par_com este numărul de parametri din linia de comandă;

**tabl_par este un pointer către un tablou de şiruri de caractere care conţine cuvintele liniei de comandă, astfel:

tabl_par[0] este numele programului, adică nume_program; tabl_par[1] este primul pametru al liniei de comandă, adică param_1; ..... tabl_par[n] este ultimul pametru al liniei de comandă, adică param_n;

2.8.6. Exemplu de folosire a funcţiilor într-un program C Cu toate că nu a fost făcută încă o prezentare a structurii unui program C (pentru că mai

este necesară parcurgerea încă a unor noţiuni), pentru înţelegerea modului de folosire a funcţiilor, în continuare este prezentat un exemplu de program C simplu: #include <conio.h> #include <stdio.h> float a=1.0, b=2.5, c; /*declarare si initializare variabile globale */ float aduna(float, float); /* declarare prototipuri functii */

Page 77: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 65

main() /* definire functie main */ {c=aduna(a,b); /* apelul functiei si atribuirea rezultatului */ printf("c=a+b=%f+%f=%f\n",a,b,c); /*afisare */ getch(); /* asteptarea apasarii unei taste */ } float aduna(float u, float v) /* definirea functiei aduna*/ {float w; /* declarare variabila locala */ w=u+v; /* operatia de adunare si atribuire */ return w; /* returnarea rezultatului */ }

Când compilatorul ajunge la funcţia main, el întâlneşte apelul funcţiei aduna. Pentru a rezolva corect legăturile pe care le are de făcut el trebuie să cunoască, dacă nu chiar funcţia aduna, măcar prototipul ei. De aceea acest prototip trebuie să preceadă apelul, aşadar trebuie să se găsească în partea de început a programului.

Dacă, însă, este mutată definiţia funcţiei aduna înaintea definiţiei funcţiei main în care se găseşte apelul funcţiei aduna, prototipul funcţiei aduna nu mai este necesar, deoarece datele necesare efectuării legăturilor necesare sunt luate chiar din definiţia funcţiei aduna.

Ca urmare a rulării programului de mai sus, se va obţine afişarea: c=a+b=1.000000+2.500000=3.500000 adică funcţia aduna returnează suma numerelor argumente, acest rezultat fiind atribuit variabilei c.

2.8.7. Transferul argumentelor funcţiilor Reamintind cele prezentate anterior, definirea unei funcţii se prezintă sub forma: tip_rezultat nume_functie(tip_1 arg_formal_1,..., tip_n arg_formal_n) {... ... } unde: tip_j, j=1,2,...,n este tipul argumentului;

arg_formal_j, j=1,2,...,n este argumentul formal (denumirea din interiorul funcţiei);

iar apelul funcţiei are forma: nume_functie(arg_efectiv_1,...,arg_efectiv_n); unde: arg_efectiv_j, j=1,2,...,n este argumentul efectiv (denumirea din blocul de unde se

apelează funcţia). Între arg_formal_j şi arg_efectiv_j trebuie să existe concordanţă de tip,

arg_efectiv_j putând să fie o constantă, o variabilă, o expresie sau o funcţie cu rezultatul de tipul tip_j.

Mecanismul de acţiune al apelului este următorul: - se atribuie lui arg_formal_j valoarea lui arg_efectiv_j; - se execută operaţiile din corpul funcţiei; - se returnează rezultatul (dacă există o returnare de rezultat). Ca urmare, dacă argumentele nu sunt de tipul adresă, indiferent ce s-ar întâmpla în corpul

funcţiei, valorile argumentelor arg_efectiv_j nu sunt afectate. În exemplul următor:

#include <conio.h> #include <stdio.h> typedef struct {float x,y;} punct2D;

Page 78: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 66

punct2D punct_mediu(punct2D p1, punct2D p2) {punct2D pm, ptemp; pm.x=0.5*(p1.x+p2.x); pm.y=0.5*(p1.y+p2.y); ptemp=p1; p1=p2; p2=ptemp; return pm; }

main() {punct2D a={0,0}, b={6,6}, c; c=punct_mediu(a,b); printf("a(%f,%f)\n",a.x,a.y); printf("b(%f,%f)\n",b.x,b.y); printf("c(%f,%f)\n",c.x,c.y); getch(); } se obţine ca efect atribuirea listei de coordonate medii ale coordonatelor punctelor a şi b punctului c după care se afişează: a(0.000000,0.000000) b(6.000000,6.000000) c(3.000000,3.000000)

Deşi în corpul funcţiei punctele p1 şi p2 şi-au schimbat între ele coordonatele, ele fiind numai copii ale punctelor a şi b, această inversare nu are efect în exteriorul funcţiei punct_mediu. Dacă, însă, se modifică programul ca mai jos:

#include <conio.h> #include <stdio.h> typedef struct {float x,y;} punct2D; punct2D punct_mediu(punct2D *p1, punct2D *p2) {punct2D pm, ptemp; pm.x=0.5*(p1->x+p2->x); pm.y=0.5*(p1->y+p2->y); ptemp=*p1; *p1=*p2; *p2=ptemp; return pm; } main() {punct2D a={0,0}, b={6,6}, c; c=punct_mediu(&a,&b); printf("a(%f,%f)\n",a.x,a.y); printf("b(%f,%f)\n",b.x,b.y); printf("c(%f,%f)\n",c.x,c.y); getch(); } se va obţine ca rezultat afişarea a(6.000000,6.000000) b(0.000000,0.000000) c(3.000000,3.000000) ceea ce denotă acelaşi efect direct al returnării rezultatului atribuit punctului c, dar, deoarece ca parametri ai funcţiei punct_mediu se transmit adresele punctelor a şi b, prelucrările din interiorul funcţiei vor avea loc asupra originalelor şi, ca urmare, la ieşirea din funcţie punctele originale a şi b vor avea coordonatele schimbate reciproc.

Acesta este un exemplu de efect lateral al unei funcţii şi, dacă nu este intenţionat, poate fi o sursă de erori.

Page 79: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 67

Exemplele de mai sus au avut ca mod de lucru: a. transferul parametrilor d eintrare prin argumente efective; b. transferul rezultatului (ieşirea) prin rezultatul returnat de funcţie; Este posibilă asigurarea exclusiv prin argumentele funcţiei, atât a transmiterii parametrilor

de intrare cât şi a obţinerii rezultatului. În acest caz, adaptând cele două programe de mai sus şi eliminând efectul lateral nedorit, poate fi scris programul: #include <conio.h> #include <stdio.h> typedef struct {float x,y;} punct2D; void punct_mediu(punct2D p1, punct2D p2, punct2D *pm) {pm->x=0.5*(p1.x+p2.x); pm->y=0.5*(p1.y+p2.y); } main() {punct2D a={0,0}, b={6,6}, c; punct_mediu(a,b,&c); printf("a(%f,%f)\n",a.x,a.y); printf("b(%f,%f)\n",b.x,b.y); printf("c(%f,%f)\n",c.x,c.y); getch(); }

Acum, în funcţia main, funcţia punct_mediu primeşte ca argumente efective valorile punctelor a şi b şi apoi adresa punctului c. La terminarea execuţiei, la adresa punctului c se va găsi stocat rezultatul obţinut în corpul funcţiei punct_mediu.

Se observă deja unele mecanisme de transfer foarte avantajoase: deoarece o funcţie poate returna un singur rezultat, când este necesar ca ea să aibă ca rezultat un efect asupra unui set de date, se pot folosi următoarele modalităţi de lucru:

- returnarea unei structuri care conţine un set de date; - folosirea de variabile globale pentru variabilele din set care vor reflecta starea după

ieşirea din funcţie; - folosirea de adrese ca argumente ale funcţiei, la ieşirea din funcţie variabilele adresate

având starea căpătată în corpul funcţiei. Modalitatea recomandabilă este prima. Ultimele două modalităţi încalcă principiul

încapsulării datelor şi, deşi pot fi foarte utile, trebuie folosite cu foarte multă atenţie. Transmiterea argumentelor de tip tablou ale unei funcţii are la bază mecanismul de

transmitere a adreselor descris mai sus. Numele unui tablou are semnificaţia unui pointer la primul element al tabloului deci, transmiterea prin indicarea numelui tabloului nu se face prin copierea tabloului ci prin referinţă la adresa lui.

Ca urmare, în programul: #include <stdio.h> float suma(float tablou[], int nmax) {float s=0; int i; for(i=0;i<nmax;i++) s+=tablou[i]; return s; } main() {float tabl[]={1,2,3}; printf("suma=%f\n",suma(tabl,3)); getch(); }

Page 80: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 68

funcţia suma va returna suma elementelor tabloului, fără să altereze valoarea acestora deoarece nu se operează asupra lor. Efectul rulării acestui program este afişarea: suma=6.000000

În schimb, în programul:

#include <conio.h> #include <stdio.h> void rotire_stanga(float tablou[], int nmax) {float temp=tablou[0]; int i; for(i=0;i<nmax-1;i++) tablou[i]=tablou[i-1]; tablou[nmax-1]=temp; } main() {float tabl[]={1,2,3}; int i; rotire_stanga(tabl,3); for(i=0;i<3;i++) printf("tabl[%i]=%f\n",i,tabl[i]); getch(); } funcţia rotire_stanga nu returnează nici o valoare dar are ca efect, după ieşirea din ea, rotirea elementelor tabloului cu o poziţie către stânga. Efectul rulării programului va fi afişarea: tabl[0]=2.000000 tabl[1]=3.000000 tabl[2]=1.000000

Tablourile pot fi tratate la transmitere şi ca pointeri, ca în exemplul următor, în care numai definirea funcţiei este modificată, restul programului rămânând neschimbat: void rotire_stanga(float *tablou, int nmax) {float temp=*tablou; int i; for(i=0;i<nmax-1;i++) *(tablou+i)=*(tablou+i+1); *(tablou+nmax-1)=temp; }

În cazul tablourilor multidimensionale, lucrurile sunt puţin diferite. Fie cazul unui tablou cu două dimensiuni, pentru care se cere incrementarea tuturor

elementelor. Se poate proceda în mai multe moduri, conform exemplelor următoare: a.

#include <conio.h> #include <stdio.h> #define dim1 2 #define dim2 2 void increment(float tablou[dim1][dim2]) {int i,j; for(i=0;i<dim1;i++) for(j=0;j<dim2;j++) tablou[i][j]++; } main() {int i,j; float tabl[dim1][dim2]={{11,12},{21,22}}; increment(tabl); for(i=0;i<dim1;i++) for(j=0;j<dim2;j++) printf("tabl[%i][%i]=%f\n",i,j,tabl[i][j]); getch(); }

Page 81: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 69

b. la fel ca în cazul a, cu unica diferenţă că definirea funcţiei este de forma: void increment(float tablou[][dim2]) .....

c. se modifică funcţiile increment şi main, astfel: void increment(float **ptablou, int k1, int k2) {int i,j; for(i=0;i<k1;i++) for(j=0;j<k2;j++) (*((*ptablou)+i*k2+j))++; } main() {int i,j; float tabl[dim1][dim2]={{11,12},{21,22}}; float *ptab; ptab=*tabl; increment(&ptab,dim1,dim2); for(i=0;i<dim1;i++) for(j=0;j<dim2;j++) printf("tabl[%i][%i]=%f\n",i,j,tabl[i][j]); getch(); }

În cazurile a şi b s-a efectuat apelul cu numele tabloului iar funcţia trebuia să “vadă” măcar ultima dimensiune a tabloului şi faptul că are două dimensiuni. În cazul c s-a făcut uz de mecanismele de transfer a pointerilor şi de dereferenţiere a acestora.

§2.9. Directive preprocesor Directivele preprocesor sunt directive care au efect numai pe perioada acţiunii

compilatorului şi se adresează acestuia în vederea pregătirii procesului de compilare. 2.9.1. Directiva include Directiva include se prezintă în două forme: #include <fisier_antet>

şi #include “fisier_antet”

şi are ca efect includerea conţinutului unui fisier_antet în fişierul curent. Un fişier antet este un fişier care conţine declaraţii şi definiţii necesare compilatorului

pentru a realiza corect legăturile necesare cu bibliotecile limbajului. De exemplu, a putut fi observată foarte des în exemplele anterioare, directiva:

#include <stdio.h> Prima variantă a directivei include (cea cu paranteze unghiulare) ordonă compilatorului să

caute fişierul antet în directoarele indicate prin setarea opţiunii de includere din cadrul proiectului de program.

A doua variantă (cea între ghilimele) descrie explicit calea de căutare. Dacă nu se face nici o altă specificare, fisier_antet este căutat în directorul curent. Dacă este necesar, se indică drumul de căutare aşa cum se obişnuieşte, în forma “disc:\directoare\fisier_antet”.

Destul de frecvent, programatorii folosesc directiva include pentru a include în fişierul sursă curent un alt fişier sursă conţinând blocuri de program C.

Directiva include poate fi plasată oriunde în program, dar trebuie ţinut cont că fişierul cerut pentru a fi inclus este inserat în poziţia în care apare directiva include.

Page 82: Programarea Calculatoarelor si Limbaje de Programare

Cap.2. Limbajul C 70

2.9.2. Directiva define Directiva define are forma: #define identificator text şi are rolul de a substitui orice apariţie în textul sursă a lui identificator prin text. De exemplu:

#define ZECE 10 va înlocui peste tot textul ZECE prin textul 10, care la compilare va fi interpretat numeric.

Dacă, după aceasta, se scrie: #define INCRZECE ZECE+1

se va înlocui INCRZECE cu ZECE+1, astfel încât instrucţiunea: val=INCRZECE*2;

devine la compilare: val=(10+1)*2;

Tot astfel: #define MESAJ “EROARE\n” poate servi la utilizarea cuvântului MESAJ ca argument al unei funcţii de ieşire pentru scrierea pe ecran a mesajului EROARE urmat de un salt la o linie nouă.

Directiva define are şi o formă parametrizată, denumită macrodefiniţie: #define identificator (lista_de_parametri) care poate servi la crearea de definiţii scurte pentru funcţii simple. Un exemplu clasic este

următorul: #define max(a,b) ((a)>(b) ? (a) : (b))

Această definiţie are ca efect, de exemplu, transformarea la compilare a instrucţiunii: if(max(u,v+1)>x) u=x; în instrucţiunea: if(((u)>(v+1) ? (u):(v+1))>x) u=x;

2.9.3. Directiva undef Directiva undef are forma: #undef identificator şi ordonă compilatorului ca de la linia în care a apărut această directivă, să înceteze efectul

unei directive anterioare define referitoare la acel identificator. Folosind perechi define - undef se pot crea diferite interpretări ale unui identificator în

diferite blocuri de program delimitate de asemenea perechi.

2.9.4. Directive de compilare condiţionată Sintaxa generală a unui bloc de compilare condiţionată este: #if conditie [text] [#elif conditie text] [#elif conditie text] ..... [#elif conditie text] [else text] #endif

Page 83: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 71

unde conditie este o expresie constantă întreagă, evaluabilă în momentul compilării. Directivele if şi endif sunt obligatorii pentru a marca începutul şi sfârşitul blocului. Între if şi endif (în lipsa lui else) pot exista între zero şi mai multe directive elif, dar

directiva else este admisă o singură dată înaintea directivei endif. În funcţie de adevărul condiţiilor, preprocesorul selectează pentru compilare una dintre

alternative, iar dacă nici o condiţie nu este adevărată, selectează alternativa else. Ca urmare, textul corespunzător va fi procesat fie în sensul preprocesor (substituire de asociaţii identificator - text prin directiva define) fie prin compilare, dacă text este constituit din instrucţiuni şi apeluri de funcţii.

De exemplu, programul:

#include <conio.h> #include <stdio.h> #define CAZ 3 #if CAZ==1 #define LATURA 10 #elif CAZ==2 #define LATURA 15 #else #define LATURA 20 #endif main() {int l=LATURA; printf("Latura=%i\n",l); getch(); } va avea ca efect afişarea: Latura=20

Blocurile if - endif pot fi încuibate (evident cu condiţia ca fiecărui if să-i corespundă un endif).

Condiţiile nu pot conţine expresii sizeof, conversii de tipuri sau constante enumerative. Se poate folosi expresia constantă specială: defined (identificator) care are valoare adevărată (diferită de zero) dacă identificator a fost definit anterior. De exemplu, înlocuind în exemplul anterior blocul de compilare condiţionată prin:

#define CAZ 1 #if defined (CAZ) #define LATURA 10 #else #define LATURA 20 #endif se va obţine afişarea Latura=10

Pentru simplificarea scrierii programelor pot fi folosite directivele: ifdef echivalentă cu if defined

şi ifndef echivalentă cu opusul lui ifdef

menţinându-se obligativitatea încheierii blocului prin endif.

Page 84: Programarea Calculatoarelor si Limbaje de Programare

Cap.3. Elemente de limbaj C++ 72

Cap.3. Elemente de limbaj C++

Limbajul C++ este un superset al limbajului C standard. Fără a face o prezentare cuprinzătoare a diferenţelor dintre C şi C++ (aceasta poate fi găsită în orice manual care se ocupă exclusiv de prezentarea limbajului C), vor fi prezentate succint acele caracteristici ale limbajului C++ considerate a fi strict necesare pentru construirea aplicaţiilor inginereşti.

Pentru început trebuie reţinut că orice program scris în C++ trebuie să aibă terminaţia de nume .CPP.

§3.1. Operaţii de intrare/ieşire cu consola Fără a intra în amănunte, pentru a putea înţelege cele ce vor urma, vor fi prezentate cele

două dispozitive de intrare/ieşire standard predefinite în C++ şi anume cin şi cout. cin (Console Input) este dispozitivul de intrare de la consolă (tastatură), care corespunde

dispozitivului stdin din limbajul C; cout (Console OUTput) este dispozitivul de ieşire la consolă (monitor), care corespunde

dispozitivului stdout din limbajul C; >> este operatorul asociat cu cin, însemnând " receptează de la "; << este operatorul asociat cu cout, însemnând "transmite la"; Formele de utilizare sunt: cin >> var1 >> var2 >> ... >> varN; pentru a primi de la tastatură o serie de valori atribuite

variabilelor var1 ... varN; cout << var1 << var2 << ... << varN; pentru a scrie pe ecran valorile variabilelor var1 ...

varN. Se observă lipsa specificatorilor de format, acesta fiind ales automat în funcţie de tipul

variabilelor, la forma potrivită. Totuşi, există şi în acest caz modalităţi de specificare a unor formate preferate de afişare. Ele pot fi aflate prin consultarea help-ului mediului de programare.

§3.2. Supraîncărcarea funcţiilor Compilatorul de C++ este capabil să distingă o funcţie după "semnătura" sa, adică după

lista de parametri (numărul de parametru şi tipul lor). Aceasta permite definirea mai multor funcţii care pot avea acelaşi nume dar, obligatoriu, trebuie să aibă liste de parametri diferite. Compilatorul va şti să aleagă singur, dintre mai multe funcţii cu acelaşi nume, pe aceea care corespunde semnăturii indicate de lista de parametri definită la apelul funcţiei. Această caracteristică a limbajului C++ conferă mai multă naturaleţe scrierii programelor. În acelaşi timp este necesară o mai mare atenţie, deoarece C++ permite ignorarea tipului rezultatului returnat de funcţie. Prin urmare, nu trebuie construite funcţii care diferă numai prin tipul rezultatului returnat deoarece, în acest caz, compilatorul nu mai poate face distincţie între ele.

De exemplu, programul:

#include <iostream.h> #include <conio.h> struct vect2D{float x,y;}; struct vect3D{float x,y,z;}; vect2D suma_vect(vect2D a, vect2D b) {vect2D c; c.x=a.x+b.x; c.y=a.y+b.y; return c;} vect3D suma_vect(vect3D a, vect3D b) {vect3D c; c.x=a.x+b.x; c.y=a.y+b.y; c.z=a.z+b.z; return c;} main() {vect2D a,b,c; vect3D u,v,w;

Page 85: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 73

a.x=-2; a.y=0; b.x=0; b.y=3; c=suma_vect(a,b); u.x=3; u.y=4; u.z=0; v.x=0; v.y=0; v.z=5; w=suma_vect(u,v); cout << "c=(" << c.x << ")i+(" << c.y << ")j+(0)k\n"; cout << "w=(" << w.x << ")i+(" << w.y << ")j+(" << w.z << ")k\n"; getch(); } uşurează mult scrierea programului principal, deoarece programatorul nu trebuie să mai trateze distinct apelul funcţiilor destinate adunării vectorilor plani de cle pentru adunarea vectorilor spaţiali. Singura dificultate rămasă este aceea a folosirii instrucţiunii de scriere, care se scrie diferenţiat pentru cele două tipuri de vectori.

§3.3. Utilizarea argumentelor prestabilite La definirea unor funcţii se pot indica valori prestabilite pentru unele argumente. Dacă la

apelul funcţiei argumentul este omis, va fi folosită automat valoarea prestabilită. Totuşi, există următoarele restricţii:

- dacă se atribuie unui argument o valoare prestabilită, se vor atribui valori prestabilite tuturor argumantelor care îi urmează în lista de parametri;

- dacă un argument este omis, se vor omite toate argumentele care îi urmează; - nu pot fi omise argumentele care nu au valori prestabilite. De exemplu, se poate restructura aplicaţia anterioară, astfel:

#include <iostream.h> #include <conio.h> struct vect{float x,y,z;}; vect constr_vect(float x, float y, float z=0) {vect a; a.x=x; a.y=y; a.z=z; return a;} vect suma_vect(vect a, vect b) {vect c; c.x=a.x+b.x; c.y=a.y+b.y; c.z=a.z+b.z; return c;} main() {vect c,w; c=suma_vect(constr_vect(-2,0), constr_vect(0,3)); cout << "c=(" << c.x << ")i+(" << c.y << ")j+(" << c.z << ")k\n"; w=suma_vect(constr_vect(3,4), constr_vect(0,0,5)); cout << "w=(" << w.x << ")i+(" << w.y << ")j+(" << w.z << ")k\n"; getch(); }

Faţă de aplicaţia anterioară noul program este chiar mai scurt şi nu produce nici o complicaţie de scriere.

§3.4. Alocarea dinamică a memoriei Toate funcţiile de alocare dinamică a memoriei folosite în C sunt recunoscute şi în C++. În

plus, limbajul C++ introduce operatorii new şi delete. Alocarea dinamică prin operatorul new poate avea una dintre formele sintactice: tip_var_pointer=new tip_variabilă; unde: tip_var_pointer este o variabilă pointer către un tip;

tip_variabilă este tipul variabilei dinamice tip_var_pointer=new tip_variabilă(valoare); unde: valoare este valoarea iniţială care se atribuie variabilei dinamice.

Page 86: Programarea Calculatoarelor si Limbaje de Programare

Cap.3. Elemente de limbaj C++ 74

tip_var_pointer=new tip_variabilă[dimensiune]; unde: dimensiune este dimensiunea variabilei dinamice de tip tablou. Tabloul poate

fi multidimensional, în acest caz fiind necesară specificarea tuturor dimensiunilor. Tablourile nu pot fi iniţializate valoric.

În toate cazurile, dacă alocarea dinamică a reuşit, este returnat un pointer de tipul tip_variabilă. Dacă alocarea a eşuat, este returnat un pointer de valoare NULL. Este recomandabilă testarea valorii returnate, înainte de a efectua exploatarea spaţiului de memorie alocat dinamic.

Eliberarea memoriei alocate dinamic se face folosind operatorul delete, cu sintaxa: delete tip_var_pointer unde: tip_var_pointer este valoarea pointer returnată la alocarea anterioară cu new. De exemplu:

#include <iostream.h> #include <ctype.h> main() {int endprog=0, ls, i; char cont, *sir; while(endprog==0) {cout << "Lungime sir="; cin >> ls; sir=new char[ls+1]; for(i=0;i<ls;i++) sir[i]='*'; sir[ls]='\0'; cout << sir << "\nContinuare(D/N)?"; cin >> cont; if(toupper(cont)!='D') endprog=1; delete sir; } }

Programul cere lungimea unui şir de caractere, alocă spaţiul necesar plus o locaţie pentru caracterul terminator de şir \0, completează zona de memorie alocată cu caractere * şi o încheie cu caracterul terminator de şir. După aceea cere confirmarea continuării. La fiecare sfârşit de ciclu eliberează memoria alocată.

§3.5. Conceptul de clasă Clasa reprezintă un concept nou introdus de limbajul C++ ca o contribuţie majoră la

dezvoltarea tehnicilor de programare. Ea reprezintă o extindere a conceptului de structură ca grupare de date, la o treaptă superioară care, pe lângă date, conţine şi metodele de tratare asociate datelor prin funcţii care, impreună cu datele, sunt membri ai clasei. Pe baza conceptului de clasă este dezvoltată tehnica de programare orientată pe obiecte.

3.5.1. Structura în C++ Spre deosebire de limbajul C, în C++ structura este mai puternică, putând să conţină ca membri,

pe lăngă date, şi funcţii şi, din acest motiv, este privită ca o prefigurare a conceptului de clasă. Fie următorul exemplu de program:

#include <iostream.h> #include <conio.h> struct vect{float x,y,z;}; struct calc_vect {vect a,b,rezv; float rezs; void set_vect(vect,vect); void suma_vect(void); } svect;

Page 87: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 75

void calc_vect::set_vect(vect v1,vect v2){a=v1; b=v2;} void calc_vect::suma_vect(void) {rezv.x=a.x+b.x; rezv.y=a.y+b.y; rezv.z=a.z+b.z;} main() {vect v1={-2,0,0}, v2={0,3,0}; svect.set_vect(v1,v2); svect.suma_vect(); cout << "c=(" << svect.rezv.x << ")i+(" << svect.rezv.y << ")j+(" << svect.rezv.z << ")k\n"; getch(); }

Se observă că funcţiile conţinute ca membri ai structurii svect acţionează asupra membrilor date ale structurii. Din acest motiv, deoarece datele pot fi extrase prin referinţă la membrii structurii, nu a fost necesar ca funcţiile membre să returneze valori.

Asocierea dintre funcţia membru şi structură se face prin operatorul :: folosit la definirea funcţiei cu sintaxa de definire:

tip_rezultat nume_structură :: funcţie_membru(parametri) {corp_funcţie_membru} La apel funcţia este referită ca şi datele membru ale structurii, prin operatorul punct (.). Funcţiile membru pot returna şi valori, ca în exemplul restructurat următor:

#include <iostream.h> #include <conio.h> struct vect{float x,y,z;}; struct calc_vect {vect a,b; float rezs; void set_vect(vect,vect); float prod_scal(void); } svect; void calc_vect::set_vect(vect v1,vect v2){a=v1; b=v2;} float calc_vect::prod_scal(void) {rezs=a.x*b.x+a.y*b.y+a.z*b.z; return rezs;} main() {vect v1={2,1,0}, v2={3,4,0}; float pscal; svect.set_vect(v1,v2); pscal=svect.prod_scal(); cout << "Produsul scalar=" << pscal << ", sau\n"; cout << "Produsul scalar=" << svect.rezs << "\n"; getch(); }

Analizând modul de comportare al funcţiilor membre ale structurii se observă că: - funcţia set_vect transferă valorile de tip vect, transmise ei ca parametri de apel, datelor

membri de tip vect a şi b ale structurii svect; - celelalte funcţii membre, suma_vect în primul exemplu şi prod_scal în al doilea,

lucrează cu valorile datelor membre şi, eventual le modifică (funcţia suma_vect stabileşte valoarea datei membru rezv, iar prod_scal stabileşte valoarea datei membru rezs);

- Datele membre ale structurii pot fi accesate pe calea obişnuită cu operatorul punct. În cazul primului exemplu, rezultatul sumei vectoriale, adică efectul obţinut prin apelul funcţiei suma_vect, a fost extras prin acces la datele membre x, y şi z ale structurii rezv, membră la rândul ei în structura svect. În al doilea exemplu, data rezs membră a structurii svect a fost stabilită prin efectul apelului funcţiei membre prod_scal. La rândul ei funcţia prod_scal returnează valoare, astfel încât se putea renunţa la includerea în structura svect a datei membru rezs.

Cu aceste înbunătăţiri oferite de structură în C++, ea devine o formă elementară de clasă.

Page 88: Programarea Calculatoarelor si Limbaje de Programare

Cap.3. Elemente de limbaj C++ 76

3.5.2. Clasa în C++ Membrii unei structuri sunt în mod implicit publici. Aceasta înseamnă că pot fi referiţi din

program prin intermediul operatorului punct. Înlocuind cuvântul cheie struct cu cuvântul cheie class se obţine clasa, ai cărei membri

sunt în mod implicit privaţi, vizibilitatea lor fiind limitată la interiorul clasei. Ultimul exemplu se poate converti la utilizarea claselor prin definiţia:

class calc_vect {vect a,b; public: float rezs; void set_vect(vect,vect); float prod_scal(void); } cvect; restul programului rămânând neschimbat cu excepţia înlocuirii numelui svect cu numele cvect.

Dacă, însă, se va încerca accesarea membrilor a şi b din program, rezultatul la compilare va fi un mesaj de eroare avertizând că aceşti membri sunt inaccesibili. Aceeaşi reacţie se va obţine dacă, omiţând cuvântul cheie public în definiţia clasei, se va încerca referirea din program a vreuneia dintre funcţiile membre ale clasei. În acest caz funcţiile devin inaccesibile din exterior, dar sunt accesibile din interiorul altor funcţii membre ale clasei.

Pentru a înlătura confuziile din partea unui programator care citeşte programul, este indicat să se folosească declaraţiile explicite complete. Astfel, definiţia: class calc_vect {private: vect a,b; public: float rezs; void set_vect(vect,vect); float prod_scal(void); } cvect; este perfect echivalentă cu cea anterioară şi este mai explicită.

Ca şi în cazul funcţiilor obişnuite, şi funcţiile membre pot fi supraîncărcate, compilatorul fiind capabil să discearnă între mai multe funcţii omonime, prin analiza semnăturilor lor.

3.5.3. Funcţii speciale ale clasei. Constructori şi destructori Constructorii sunt funcţii care se execută automat la crearea unui obiect de tipul clasei.

Un constructor are acelaşi nume ca şi clasa. Ca orice funcţie, şi constructorul poate fi supraîncărcat şi, din acest motiv, se deosebesc trei tipuri de constructori:

- constructorul prestabilit; - constructorul de copiere; - constructorul oarecare. Dintre aceşti constructori, la crearea unui obiect (instanţă) al clasei respective, va fi

executat automat acel constructor care corespunde semnăturii de la apelul creării instanţei. Vor fi analizate pe rând cele trei cazuri. - Constructorul prestabilit. În general, rolul acestuia este de a iniţializa datele membre

ale clasei. El poate să aibă fie nici un argument, fie argumente prestabilite. Pentru a înţelege modul cum se lucrează cu acest constructor, trebuie analizat exemplul următor: #include <iostream.h> #include <conio.h> struct vect{float x,y,z;}; vect v0={0,0,0};

Page 89: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 77

class calc_vect {private: vect a,b; int jinst; static int nrinst; /* membru static */ public: calc_vect(vect=v0,vect=v0); /* constructor de initializare cu parametri prestabiliti */ calc_vect(calc_vect& cv); /* constructor de copiere a unei instante */ ~calc_vect(); /* destructor - numai pentru evidentiere */ calc_vect& copie_vect(calc_vect& cv) {a=cv.a; b=cv.b; return *this;}; /* copiere cu autoreferire */ void set_vect(vect,vect); vect suma_vect(void); void print_vect(vect); static int nrInstante(void){return nrinst;} /* functia statica */ }; calc_vect::calc_vect(vect v1, vect v2) {a=v1; b=v2; jinst=++nrinst; cout << "A fost creata instanta nr=" << jinst << "\n"; } calc_vect::calc_vect(calc_vect& cv) {a=cv.a; b=cv.b; jinst=++nrinst; cout << "A fost creata instanta nr=" << jinst << " prin copiere\n"; } calc_vect::~calc_vect() {cout << "Distrugerea instantei " << jinst << ". Apasa o tasta\n"; getch(); } void calc_vect::set_vect(vect v1,vect v2){a=v1; b=v2;} vect calc_vect::suma_vect(void) {vect c; c.x=a.x+b.x; c.y=a.y+b.y; c.z=a.z+b.z; return c;} void calc_vect::print_vect(vect c) {cout << "c=(" << c.x << ")i+(" << c.y << ")j+(" << c.z << ")k\n";} int calc_vect::nrinst=0; main() {vect u={-2,0,0}, v={0,3,0}, w; cout << "Inceput de calcul\n"; calc_vect cvect1; /*parametrii constructorului sunt omisi */ w=cvect1.suma_vect(); cvect1.print_vect(w); cout << "Instanta cvect1 este initializata cu vectori nuli\n"; calc_vect cvect2(u,v); /* se dau parametrii u si v

constructorului */ cvect2.print_vect(cvect2.suma_vect()); cout << "Instanta cvect2 este initializata cu vectori u si v\n"; cvect1.set_vect(u,u); w=cvect1.suma_vect(); cvect1.print_vect(w); cout << "Instanta cvect1 este modificata cu vectorii u si u\n"; calc_vect cvect3(cvect1); /* se creaza copia instantei cvect1 in cvect3 */ w=cvect3.suma_vect(); cvect3.print_vect(w);

Page 90: Programarea Calculatoarelor si Limbaje de Programare

Cap.3. Elemente de limbaj C++ 78

cout << "Instanta cvect1 este copiata in instanta cvect3\n"; cvect3.copie_vect(cvect2); /* se copiaza instanta cvect2 in

cvect3 */ w=cvect3.suma_vect(); cvect3.print_vect(w); cout << "Instanta cvect2 este copiata in instanta cvect3\n"; cout << "In acest moment sunt create " << calc_vect::nrInstante() << " instante\n"; getch(); }

Trebuie observată şi notată regula: constructorul nu returnează nici o valoare (nici măcar void) şi de aceea definiţia funcţiei constructor nu este precedată de nici un nume de tip.

În exemplul dat, la crearea obiectului cvect1, el este iniţializat automat cu valorile vectori a şi b ale clasei egale cu vectorul nul. La crearea obiectului cvect2, deoarece sunt menţionaţi parametrii u şi v de valori definite în funcţia main, vectorii a şi b primesc aceste valori. Aceasta se poate vedea din efectul funcţiilor de scriere pe ecran, print_vect ale obiectelor create. Ulterior, prin funcţia set_vect, sunt schimbate valorile vectorilor a şi b ai obiectului cvect1 la valorile vectorilor u şi respectiv v. Pe ecran va apare afişarea: Inceput de calcul A fost creata instanta nr=1 c=(0)i+(0)j+(0)k Instanta cvect1 este initializata cu vectori nuli A fost creata instanta nr=2 c=(-2)i+(3)j+(0)k Instanta cvect2 este initializata cu vectorii u si v c=(-4)i+(0)j+(0)k Instanta cvect1 este modificata cu vectorii u si u A fost creata instanta nr=3 prin copiere c=(-4)i+(0)j+(0)k Instanta cvect1 este copiata in instanta cvect3 c=(-2)i+(3)j+(0)k Instanta cvect2 este copiata in instanta cvect3 In acest moment sunt create 3 instante Distrugerea instantei 3. Apasa o tasta Distrugerea instantei 2. Apasa o tasta Distrugerea instantei 1. Apasa o tasta

Evident că afişările făcute de constructori şi destructori au fost prevăzute numai pentru a urmări fenomenul pas cu pas. În mod obişnuit aceasta nu se face.

- constructorul de copiere a unei instanţe. Acest constructor serveşte la copierea unei instanţe existente într-o alta care se crează. După cum se observă din exemplul dat, instanţa cvect3 a fost creată copiind valorile a şi b ale instanţei cvect1. Folosirea constructorilor de copiere este recomandabilă în special dacă se doreşte copierea datelor alocate dinamic. Compilatorul crează el însuşi un constructor de copiere dacă nici un astfel de constructor nu a fost declarat explicit de către programator, dar acest constructor creat de compilator face doar o copiere superficială, numai a datelor membre iar nu şi a celor dinamice.

- alţi constructori pot fi declaraţi de către programator în diverse scopuri. Destructorul, ca şi constructorul, are acelaşi nume cu clasa dar este precedat de caracterul ~

şi este unic. Ca şi constructorul, destructorul nu este precedat de nume de tip şi nu are niciodată parametri. Rolul lui este numai acela de a dezafecta clasa atunci când ea nu mai este utilă. Dacă programatorul nu defineşte explicit un destructor, compilatorul va crea el însuşi unul.

Page 91: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 79

Fie exemplul următor: #include <iostream.h> #include <conio.h> char ast='*'; class sir_car {private: char *sircar; int lung; char car; public: sir_car(int, char); /* constructor cu parametri prestabiliti */ sir_car(sir_car& s); /* constructor de copiere */ ~sir_car(); /* destructor pentru eliberarea memoriei */ void scrie_sir(void); }; sir_car::sir_car(int i=1, char c=ast) {lung=i; car=c; sircar=new char(lung+1); for(i=0;i<lung;i++)sircar[i]=car; sircar[lung]='\0'; } sir_car::sir_car(sir_car& s) /* copierea datelor instantei */ {car=s.car; lung=s.lung; sircar=s.sircar;} sir_car::~sir_car() {delete sircar; /* se elibereaza memoria alocata in instanta */ cout << "Distrugere. Apasa o tasta!\n"; getch(); } void sir_car::scrie_sir(void){cout << sircar << "\n";} main() {sir_car sir1; /* creaza o instanta cu ambii parametri

prestabiliti */ sir1.scrie_sir(); sir_car sir2(10); /* creaza o instanta cu 10 caractere

prestabilite */ sir2.scrie_sir(); sir_car sir3(15,'$'); /* creaza instanta sir3 cu 15 caractere $ */ sir3.scrie_sir(); sir_car sir4(sir2); /* copiaza instanta sir2 in noua instanta sir4 */ sir4.scrie_sir(); getch(); }

Programul va afişa: * ********** $$$$$$$$$$$$$$$ ********** Distrugere. Apasa o tasta! Distrugere. Apasa o tasta! Distrugere. Apasa o tasta! Distrugere. Apasa o tasta!

În acest caz destructorul definit explicit prin program, eliberează prin instrucţiunea delete memoria alocată în cadrul instanţelor cu instrucţiunea new. Altfel, prin acţiunea unui destructor creat de compilator, ar fi fost distruse numai instanţele înseşi, nu însă şi memoria alocată în cadrul lor. Aceasta ar fi rămas în evidenţa sistemului de operare ca fiind ocupată,

Page 92: Programarea Calculatoarelor si Limbaje de Programare

Cap.3. Elemente de limbaj C++ 80

deşi nefolosită. Dacă programul ar fi fost folosit în mod repetat, s-ar fi putut ajunge la un moment dat la situaţia ca întreaga memorie să fie ocupată şi nefolosibilă, lucru care nu se poate remedia decât prin restartarea calculatorului.

3.5.4. Autoreferinţa unui obiect al clasei. Cuvântul cheie this Analizând exemplul anterior se observă că se poate crea o instanţă copie a alteia prin

intermediul constructorului de copiere, la apelul de creare a instanţei. Ce este însă de făcut dacă se doreşte copierea unei instanţe într-o alta care a fost deja creată?

În exemplul dat la constructori, a fost definită funcţia membru copie_vect care primeşte ca parametru o instanţă existentă şi returnează prin intermediul cuvântului cheie this o referinţă la instanţa apelată. Ea modifică datele membre ale instanţei curente (cea apelată) copiindu-le pe acelea ale instanţei date ca parametru.

Prin această metodă se spune că obiectul (instanţa) se autoreferă. Există o restricţie, şi anume aceea ca expresia *this să fie folosită numai în funcţiile

membre ale clasei. 3.5.5. Membrii statici ai clasei Un membru static este un membru care aparţine întregii clase, deci este comun tuturor

obiectelor (instanţelor) clasei respective. Membrii statici, date sau funcţii, sunt precedaţi de cuvântul cheie static.

În exemplul dat la clasa calc_vect se observă existenţa variabilei statice nrinst care este iniţializată în afara clasei, deoarece un membru static există separat de instanţele clasei şi poate fi accesat înainte de crearea instanţelor. Variabila serveşte la contorizarea numărului de instanţe existente şi, datorită introducerii membrului jinst nestatic (deci propriu fiecărei instanţe) se poate face numerotarea instanţelor.

Funcţiile membre statice, cum este nrInstante, datorită independenţei de existenţa clasei, nu poate accesa decât membri statici, în cazul de faţă numai pe nrinst. De asemenea, din acelaşi motiv, funcţiile membre statice nu pot returna expresia *this.

3.5.6. Funcţii prietene O funcţie prietenă a unei clase este o funcţie externă clasei respective (ea poate fi membră

a unei alte clase) şi căreia îi este permis accesul la membrii clasei cu care este prietenă. Declararea calităţii de funcţie prietenă a clasei se face în cadrul clasei prin prefixarea

declaraţiei funcţiei cu cuvântul cheie friend. Iată următorul exemplu, reluare a exemplului anterior pentru calcul vectorial: #include <iostream.h> #include <conio.h> struct vect{float x,y,z;}; vect v0={0,0,0}; class calc_vect {private: vect v; public: calc_vect(vect a=v0){v=a;} calc_vect(calc_vect& cv){v=cv.v;} friend calc_vect se_substituie_cu(calc_vect& cv); void suma_vect(calc_vect& a, calc_vect& b); void print_vect(); }; void calc_vect::suma_vect(calc_vect& a, calc_vect& b)

Page 93: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 81

{v.x=a.v.x+b.v.x; v.y=a.v.y+b.v.y; v.z=a.v.z+b.v.z;} void calc_vect::print_vect(void) {cout << "(" << v.x << ")i+(" << v.y << ")j+(" << v.z << ")k\n";} calc_vect se_substituie_cu(calc_vect& cv) {calc_vect rez; rez.v=cv.v; return rez;} main() {vect a={-1,2,3}, b={2,1,3}; cout << "*****************\n"; calc_vect c1; cout << "c1="; c1.print_vect(); calc_vect c2(a); cout << "c2="; c2.print_vect(); calc_vect c3(b); cout << "c3="; c3.print_vect(); c1.suma_vect(c2,c3); cout << "c1=c2+c3="; c1.print_vect(); c1=se_substituie_cu(c2); cout << "c1 se substituie cu c2="; c1.print_vect(); getch(); }

În exemplul dat, a fost definită funcţia prietenă se_substituie_cu care permite substituirea vectorului dintr-o instanţă a clasei calc_vect cu un altul.

Singura diferenţă dintre o funcţie membru şi una prietenă este aceea că, funcţia prietenă fiind externă, nu poate returna expresia *this ca referinţă la o instanţă,

3.5.7. Supradefinirea operatorilor În limbajul C++ operatorii pot fi supradefiniţi în cadrul claselor, fiind trataţi ca funcţii

membre sau prietene. Supradefinirea operatorilor este valabilă numai în contextul clasei în care este făcută.

Dintre operatorii care se pot supradefini, se pot menţiona următorii: + - * / % = += -= /= %= == != < > <= >= | & || && [] () ' Sintaxa supradefinirii unui operator este: tip operator oper(lista_de_parametri); unde oper este simbolul operatorului de supradefinit. De exemplu:

#include <iostream.h> #include <conio.h> struct vect{float x,y,z;}; vect v0={0,0,0}; class calc_vect {private: vect v; public: calc_vect(vect a=v0){v=a;} calc_vect(calc_vect& cv){v=cv.v;} calc_vect& operator=(calc_vect& cv) /* operator membru */ {v.x=cv.v.x; v.y=cv.v.y; v.z=cv.v.z; return *this;} calc_vect& operator+=(calc_vect& cv) /* operator membru */ {v.x+=cv.v.x; v.y+=cv.v.y; v.z+=cv.v.z; return *this;} friend calc_vect operator+(calc_vect& cv1,calc_vect& cv2); void print_vect(); };

Page 94: Programarea Calculatoarelor si Limbaje de Programare

Cap.3. Elemente de limbaj C++ 82

calc_vect operator+(calc_vect& cv1, calc_vect& cv2) /* operator prieten */

{calc_vect rez; rez.v.x=cv1.v.x+cv2.v.x; rez.v.y=cv1.v.y+cv2.v.y; rez.v.z=cv1.v.z+cv2.v.z; return rez; } void calc_vect::print_vect(void) {cout << "(" << v.x << ")i+(" << v.y << ")j+(" << v.z << ")k\n";} main() {vect a={-1,2,3}, b={2,1,3}; cout << "*****************\n"; calc_vect c1; cout << "c1="; c1.print_vect(); calc_vect c2(a); cout << "c2="; c2.print_vect(); calc_vect c3(b); cout << "c3="; c3.print_vect(); c1=c2; cout << "c1=c2="; c1.print_vect(); c1=c2+c3; cout << "c1=c2+c3="; c1.print_vect(); c2+=c2; cout << "c2+=c2="; c2.print_vect(); getch(); }

Au fost supradefiniţi operatorii = şi += ca operatori membri ai clasei calc_vect, iar operatorul + a fost supradefinit ca operator prieten al clasei.

Se observă repede că, prin supradefinirea operatorilor, scrierea operaţiilor vectoriale din program se simplifică mult faţă de metodele din aplicaţiile anterioare.

Page 95: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 83

Cap.4. Programarea în limbajul C sub sistemul DOS

§.4.1. Structura unui program C Un program scris în limbajul C are, în general, structura reflectată de următorul exemplu:

#include <conio.h> /* directive preprocesor */ #include <stdio.h> #define UNU 1

typedef int intreg; /* definiţii de tipuri */

void mesaj(intreg numar) /* definiri de functii */ {printf("Acesta este programul nr.=%i\n",numar);} main() /* functia main = programul principal */ {intreg primul=UNU; mesaj(primul); getch(); }

Primele două linii din program cer compilatorului să caute în fişierele antet conio.h şi stdio.h prototipurile şi definiţiile funcţiilor nedefinite dar apelate în program.

A treia linie defineşte constanta UNU care va fi substituită peste tot în program prin textul 1 interpretat numeric de către compilator.

A patra linie defineşte tipul intreg (ca denumire substitut pentru tipul int). Dacă în program se folosesc variabile globale (vizibile din interiorul oricărei funcţii

definită în fişierul sursă) ar trebui să urmeze definiţii privind tipul şi identificatorii acestor variabile, ceea ce nu a fost cazul în acest program.

Urnează apoi definiţiile de funcţii apelate în program, aici funcţia mesaj, şi apoi definiţia funcţiei main care constituie programul principal. Trebuie reamintit faptul că orice funcţie apelată dintr-o alta trebuie să fie precedată, dacă nu de definiţia ei, măcar de definiţia prototipului ei.

Variabila de tip întreg primul este locală, fiind vizibilă numai din funcţia main, unde este declarată şi iniţializată. Tot astfel, variabila de tip întreg numar, definită în lista de parametri ai funcţiei mesaj, este vizibilă numai în interiorul acestei funcţii.

Efectul execuţiei acestui program este afişarea: Acesta este programul nr.=1 urmat de saltul cursorului la începutul liniei următoare şi aşteptarea apăsării unei taste.

§.4.2. Fişiere antet Fişierele antet sunt fişiere care conţin macrodefiniţii şi prototipuri de funcţii pentru

funcţiile de bibliotecă standard ale limbajului C. De asemenea, fişiere antet pot fi create de utilizator pentru a conţine macrodefiniţii, prototipuri şi funcţii proprii.

Un nume de fişier antet are forma: nume.h Încluderea conţinutului unui fişier antet într-un fişier program sursă se face cu ajutorul

directivei preprocesor include expusă mai înainte.

§.4.3. Funcţii de bibliotecă standard În continuare, se face o trecere în revistă a unora dintre funcţiile de bibliotecă C standard.

Ele sunt valabile începând de la mediul Borland C++ 4.0. Sunt menţionate numai funcţiile portabile pe sistemul DOS şi Windows pe 32 de biţi.

Page 96: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 84

O funcţie este prezentată prin prototipul său pentru a preciza tipul parametrilor de intrare şi tipul rezultatului returnat.

Este menţionat fişierul antet care trebuie inclus pentru ca funcţia să poată fi folosită şi, unde este necesar este făcută o scurtă prezentare.

Mai multe detalii pot fi obţinute consultând Help-ul mediului pe care se lucrează. 4.3.1. Funcţii de conversie a datelor double atof(const char *şir); math.h Converteşte un şir de caractere numerice scris în formatul: [spaţii] [semn] [parte întreagă] [.[parte zecimală]] [e/E[semn]exponent] într-un număr de tip virgulă mobilă pe care îl returnează ca rezultat. int atoi(const char *şir); math.h long atol(const char *şir); math.h Funcţiile convertesc un şir de caractere numerice scris în formatul [spaţii] [semn] [cifre] într-un număr de tip întreg pe care îl returnează ca rezultat. char *itoa(int valoare, char *şir, int bază) stdlib.h char *ltoa(long valoare, char *şir, int bază) stdlib.h Funcţiile convertesc un număr de tip întreg într-n şir de caractere pe care îl returnează ca

rezultat sub forma unui pointer către şir. Baza de numeraţie este indicată de valoarea bază. Rezultatul conversiei este utilizabil şi prin pointerii *şir.

4.3.2. Funcţii matematice int abs(int valoare) math.h long labs(long valoare) math.h Funcţiile returnează o valoare întreagă absolută a argumentului de tip întreg valoare. double acos(double valoare) math.h long double acosl(long double valoare) math.h Funcţiile returnează o valoare de tip real între 0 şi π reprezentând arcul cosinusului de

argument real dat (valoare) care trebuie să fie cuprins între -1 şi +1 pentru a nu se obţine o eroare.

double asin(double valoare) math.h long double asinl(long double valoare) math.h Funcţiile returnează o valoare de tip real între 0 şi π reprezentând arcul sinusului de

argument real dat (valoare) care trebuie să fie cuprins între -1 şi +1 pentru a nu se obţine o eroare.

double atan(double valoare) math.h long double atanl(long double valoare) math.h Funcţiile returnează o valoare de tip real între -π/2 şi π-2 reprezentând arcul tangentei de

argument real dat (valoare). double atan2(double a, double b) math.h long double atan2l(long double a, long double b) math.h Funcţiile returnează o valoare de tip real între -π/2 şi π-2 reprezentând arcul tangentei de

argumente reale a/b date.

Page 97: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 85

double ceil(double x) math.h long double ceil(long double x) math.h Funcţiile returnează rezultatul de tip real al rotunjirii argumentului real x în sensul creşterii

pozitive (de exemplu, -1.0250 este rotunjit la -1.0000). double cos(double unghi) math.h long double cosl(long double unghi) math.h Funcţiile returnează valorea de tip real situată în intervalul -1...1 a cosinusului unghiului

dat ca valoare de tip real în radiani. double cosh(double x) math.h long double coshl(long double x) math.h Funcţiile returnează o valoare reală reprezentând cosinusul hiperbolic de argument x real. div_t div(int numarator, int numitor) stdlib.h ldivt_t ldiv(long int numarator, long int numitor) stdlib.h Funcţiile primesc ca argumente valorile de tip întreg numarator şi numitor şi returnează ca

rezultat o structură de tipul div_t sau ldiv_t definite ca: typedef struct{int quot; int rem} div_t; typedef struct{long int quot; long int rem} ldiv_t; unde quot şi rem sunt câtul şi restul înpărţirii celor două numere întregi. double exp(double x) math.h long double expl(long double x) math.h Funcţiile returnează rezultatul de tip real al funcţiei exponenţiale ex de argument real x.

double fabs(double x); math.h long double fabsl(long double x); math.h Funcţiile returnează valoarea absolută de tip double sau long double a argumentului x. double floor(double x); math.h long double floorl(long double x); math.h Funcţiile returnează o valoare de tip double sau long double a numărului x rotunjit la valoarea

întreagă către sensul negativ al axei numerelor. De exemplu, -3,02 devine -4, iar 5.33 devine 5.

double fmod(double numărător, double numitor); math.h long double fmodl(long double numărător, long double numitor); math.h Funcţiile returnează valoarea de tip double sau long double a mărimii numărător modulo

numitor, adică restul înpărţirii numărătorului la numitor, conform relaţiei numărător=cât*numitor+rest, unde cât este întreg, iar 0<rest<numitor. Când numitorul este egal cu zero, funcţiile returnează zero. Semnul restului este acelaşi cu semnul numărătorului.

double hypot(double cat1, double cat2); math.h long double hypot(long double cat1, long double cat2); math.h Funcţiile returnează ca rezultat, de tipul double sau long double, lungimea ipotenuzei unui

triunghi dreptunghic de catete cat1 şi cat2. double ldexp(double x, int exp) math.h long double ldexpl(long double x, int exp) math.h

Page 98: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 86

Funcţiile returnează ca rezultat, de tipul double sau long double, valoarea x*2exp.

double log(double x) math.h long double logl(long double x) math.h Funcţiile returnează ca rezultat, de tip double sau long double, logaritmul natural din

argumentul x, cu condiţia ca acesta să fie mai mare decât zero.

double log10(double x) math.h long double log10l(long double x) math.h Funcţiile returnează ca rezultat, de tip double sau long double, logaritmul zecimal din

argumentul x, cu condiţia ca acesta să fie mai mare decât zero. double poly(double x, int grad, double coef[ ]); math.h long double polyl(long double x, int grad, long double coef[ ]); math.h Funcţiile returnează ca rezultat, de tip double sau long double, valoarea unui polinom de

gradul grad, care are coeficienţii coef[0], coef[1],...,coef[grad], polinomul având forma: coef[grad]*xgrad+coef[grad-1]*xgrad-1+...+coef[0]*x0 double pow(double baza, double exp); math.h long double powl(long double baza, long double exp); math.h Funcţiile returnează ca rezultat, de tip double sau long double, valoarea bazaexp. double pow10(double exp); math.h long double pow10l(long double exp); math.h Funcţiile returnează ca rezultat, de tip double sau long double, valoarea 10exp. double sinh(double x); math.h long double sinhl(long double x); math.h Funcţiile returnează ca rezultat, de tip double sau long double, valoarea (ex-e-x)/2. double sqrt(double x); math.h long double sqrtl(long double x); math.h Funcţiile returnează ca rezultat, de tip double sau long double, rădăcina pătrată a

argumentului x, cu condiţia ca x să fie pozitiv. double tan(double arc); math.h long double tanl(long double arc); math.h Funcţiile returnează ca rezultat, de tip double sau long double, tangenta arcului arc

exprimat în radiani. double tanh(double x); math.h long double tanhl(long double x); math.h Funcţiile returnează ca rezultat, de tip double sau long double, tangenta hiperbolică a argumentului x. 4.3.3. Funcţii de intrare/ieşire ale consolei Din mulţimea de funcţii de intrare/ieşire ale consolei (tastatură şi ecran), au fost selectate

câteva mai frecvent folosite, referite de fişierul antet conio.h. 4.3.3.1. Funcţii de intrare de la tastatură char *cgets(char *sir); conio.h Funcţia citeşte un şir de caractere de la consolă. Înainte de a apela funcţia, sir[0] trebuie

Page 99: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 87

făcut să conţină numărul maxim de caractere citibile, inclusiv caracterul terminator de şir \0. După apelarea funcţiei, introducerea şirului de la tastatură şi apăsarea tastei ENTER, sir[1] conţine numărul de caractere citite, iar de la sir[2] începe şirul de caractere introdus de la tastatură. Lungimea totală a tabloului sir este sir[0]+2. Rezultatul returnat de funcţie este un pointer către sir[2].

int getch(void); conio.h Funcţia preia un caracter de la tastatură şi îl returnează ca rezultat de tip întreg. int getche(void); conio.h Funcţia preia un caracter de la tastatură şi îl returnează ca rezultat de tip întreg. În acelaşi

timp, ca ecou, afişează caracterul preluat. 4.3.3.2. Funcţii de acces la ecranul text void clrscr(void); conio.h Funcţia şterge ecranul şi plasează cursorul în poziţia iniţială (1,1) a ecranului aflat în

modul de afişare text. void delline(void); conio.h Funcţia şterge toată linia pe care se află cursorul şi mută toate liniile inferioare în sus cu o poziţie. void gotoxy(int x, int y) conio.h Funcţia poziţionează cursorul text pe linia y în coloana x. Parametrii x şi z sunt întregi

reprezentând coordonate în fereastra text curentă şi sunt diferite de zero. void insline(void); conio.h Funcţia inserează o linie vidă în linia pe care se află cursorul. Toate liniile preexistente,

începănd de la linia cursorului sunt înpinse în jos cu o poziţie. Dacă ultima linie de jos se afla chiar la baza ecranului, ea este eliminată.

int gettext(int colstg, int randsus, int coldr, int randjos, void *stocdest); conio.h int puttext(int colstg, int randsus, int coldr, int randjos, void *stocsurs); conio.h Funcţiile gettext şi puttext preiau/aduc de pe/pe ecran toate caracterele aflate în

dreptunghiul de coordonate colstg-coloană stânga, randsus-rând de sus, coldr-coloană dreapta, randjos-rândul de jos. Caracterele sunt duse la/aduse din o zonă tampon de memorie stocdest/stocsurs a cărui lungime se calculează cu formula:

lungime=2*(coldr-colstg+1)*(randjos-randsus+1) Valorile returnate sunt diferite de zero dacă operaţiile au decurs cu succes şi zero în caz

contrar. void textbackground(int culfond); conio.h void textcolor(int cultext); conio.h Funcţiile selectează culoarea pentru fondul textului şi culoarea textului propriu-zis cu care

se vor face afişările ulterioare. Culorile se selectează din tabela următoare:

Constanta simbolică

Valoare textbackground textcolor

BLACK 0 Da Da BLUE 1 Da Da

Page 100: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 88

Constanta simbolică

Valoare textbackground textcolor

GREEN 2 Da Da CYAN 3 Da Da RED 4 Da Da

MAGENTA 5 Da Da BROWN 6 Da Da

LIGHTGRAY 7 Da Da DARKGRAY 8 Nu Da LIGHTBLUE 9 Nu Da

LIGHTGREEN 10 Nu Da LIGHTCYAN 11 Nu Da LIGHTRED 12 Nu Da

LIGHTMAGENTA 13 Nu Da YELLOW 14 Nu Da WHITE 15 Nu Da BLINK 128 Nu Da

Valoarea BLINK face textul să clipească dacă este adunată la valoarea culorii pentru text.

De exemplu textcolor(BLINK+BLUE) face ca afişările ulterioare de text să fie făcute cu albastru şi să clipească.

int wherex(void) conio.h int wherey(void) conio.h Funcţiile returnează o valoare întreagă reprezentând poziţia unde se află cursorul text pe

direcţia x (numărul coloanei) sau pe direcţia y (numărul rândului), în momentul apelului funcţiei.

void window(int colstg, int randsus, int coldr, int randjos) conio.h Funcţia defineşte fereastra text curentă, în coordonate ecran, unde colstg este indicele

coloanei din stânga, coldr este indicele coloanei din dreapta, iar randsus şi randjos sunt indicii rândurilor de sus şi de jos care definesc noua fereastră text. Dacă coordonatele sunt greşite, funcţia nu are efect. Mărimea implicită este ecranul întreg cu coordonatele 1,1,C,R, unde C şi R sunt numărul de coloane şi de rânduri ale modului text curent. După declararea noii ferestre, toate funcţiile care lucrează cu coordonate de fereastră text se raportează la colţul din stânga sus al noii ferestre, considerat a fi de coordonate (1,1).

4.3.4. Funcţii de intrare/ieşire standard În acest subcapitol sunt descrise sumar câteva dintre cele mai folosite funcţii din fişierul

stdio.h care deservesc intrările/ieşirile standard predefinite stdin - dispozitivul de intrare standard şi stdout - dispozitivul de ieşire standard, precum şi lucrul cu fişiere.

4.3.4.1. Intrări/ieşiri standard int getchar(void) stdio.h Funcţia aşteaptă introducerea unui şir de caractere de la tastatură, până la apăsarea tastei

ENTER. Rezultatul returnat de funcţie este numai primul caracter din şirul introdus.

Page 101: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 89

char *gets(char *sir); stdio.h Parametrul funcţiei este numele unui şir. El nu trebuie prefixat cu * deoarece se ştie că

numele de şir este de fapt un pointer către un tablou de caractere. Funcţia receptează un şir de caractere de la tastatură şi terminat prin caracterul new-line (obţinut prin apăsarea tastei ENTER) pe care îl substituie cu caracterul terminator de şir \0. Valoarea returnată de funcţie este un pointer către tipul char reprezentând şirul receptat.

Exemplu de folosire: #include <stdio.h> #include <conio.h> main() {char sir[80]; printf("Scrieti un sir:"); gets(sir); printf("Ati scris sirul:%s\n",sir); getch(); }

int puts(char *sir); stdio.h Ca şi la funcţia gets, parametrul funcţiei este numele unui şir de caractere predefinit, fără

prefixare cu *, din acelaşi motiv. Funcţia afişează pe ecran şirul de caractere completat cu caracterul new-line. Rezultatul returnat este un întreg nenegativ dacă ieşirea a avut loc cu succes, altfel este returnată valoarea EOF (end of file).

Exemplu: main() {char sir[]="Acesta este un sir de caractere"; puts(sir); getch(); }

int putchar(int car); stdio.h Funcţia trimite la stdout caracterul car. Valoarea returnată este caracterul car sau EOF în

caz de eroare. int printf(char * format[, argument,...]); stdio.h Funcţia formatează şi trimite la stdout (ecran) o serie de caractere şi valori. Parametrul format conţine caractere normale, secvenţe ESC şi, dacă este urmat de

argumente, conţine specificatori de format care se aplică acestora. În consecinţă, numărul de specificatori de format trebuie să fie egal cu numărul de argumente, în caz contrar rezultatul poate să fie impredictibil sau dezastruos. Dacă sunt mai multe argumente decât specificatori de format, argumentele în plus sunt ignorate.

Valoarea returnată de funcţie este un număr întreg reprezentând numărul de caractere trimise la stdout, iar în caz de eroare, valoarea EOF.

Şirul format trebuie să existe ca argument obligatoriu în orice funcţie printf. El conţine două tipuri de caractere:

- câmpuri de caractere recunoscute de stdout şi care sunt trimise la ieşire ca atare; - specificatori de format care guvernează modul de conversie al argumentelor în şiruri de

caractere. Aceste şiruri de caractere obţinute prin conversie substituie specificatorii de format, rezultatul fiind un şir concatenat trimis la ieşire.

Specificatorii de format au forma generală: %[indicatori][lăţime][.precizie][h | l | L]tip Orice specificator de format începe cu caracterul %. Semnificaţiile câmpurilor de după % sunt: - indicatori:

Page 102: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 90

aliniere la stânga, alinierea la dreapta fiind implicită; + ataşează semnul + valorilor pozitive şi - celor negative; spaţiu ataşează numai semnul - valorilor negative, cele pozitive având ataşat caracterul

spaţiu; # are următoarele efecte în combinaţie cu:

c s d i u - nici un efect; o x X - prefixează orice valoare nonzero cu 0, 0x sau 0X; e E f - punctul zecimal apare şi în lipsa părţii fracţionare; g G - acelaşi efect cu e şi E şi în plus inhibă eliminarea zerourilor nesemnificative;

- lăţime specifică numărul de caractere de afişat. Dacă numărul de caractere de rezultat este mai mic, are loc umplurea cu zero sau cu spaţii. Prefixarea cu 0 a numărului de caractere produce complatarea la stânga cu zerouri. De exemplu: ..... int i=231; ..... printf("i=%i+06i\n",i); .....

produce afişarea: i= +0231 Dacă în locul numărului de caractere se scrie caracterul * atunci lăţime trebuie să apară ca

argument precedând argumentul la care se referă. De exemplu, acelaşi efect al exemplului anterior se poate obţine cu:

printf("i=%i+*i\n",6,i); - precizie. Indicarea preciziei începe întotdeauna cu caracterul punct, după care

urmează numărul de caractere de afişat, în conformitate cu tipul, astfel: d i o u x - precizie determină numărul maxim de caractere de afişat. Dacă

precizie este mai mare decât numărul de cifre de afişat, se vor se vor adăuga zerouri la stânga. Dacă precizie se omite, este zero sau este sub forma "." neurmat de un număr, atunci precizie este egal cu 1;

e E - precizie determină numărul maxim de zecimale. Ultima zecimală se rotunjeşte. Dacă precizie este zero sau punct neurmat de număr, punctul zecimal nu este afişat;

f - precizie determină numărul de zecimale. Dacă precizie lipseşte ea este considerată implicit zero. Dacă este 0, punctul zecimal nu apare;

g G - precizie determină numărul maxim de cifre semnificative de afişat. Dacă precizie lipseşte, sunt afişate cifrele semnificative;

c - precizie nu are efect; s - precizie determină numărul maxim de caractere de afişat. Dacă precizie

lipseşte, şirul se afişează până la întâlnirea terminatorului de şir. - [h | l | L] sunt modificatori care determină lungimea argumentului, astfel:

h - prefixează tipurile d i o u x X şi specifică un argument de tip short; l - prefixează tipurile d i o u x X şi specifică un argument de tip long; L - prefixează tipurile e E f g G şi specifică un argument de tip long double;

- tip. Descrierea tipului este obligatorie şi se face cu ajutorul caracterelor: d - întreg zecimal cu semn; i - întreg zecimal cu semn; o - întreg octal cu semn; u - întreg zecimal fără semn;

x - întreg hexazecimal fără semn, caracterele litarale folosite fiind a, b, c, d, e, f;

Page 103: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 91

X - întreg hexazecimal fără semn, caracterele literale folosite fiind A, B, C, D, E, F;

f - valoare cu semn de forma [-]dddd.dddd, unde dddd sunt caractere zecimale;

e - valoare cu semn de forma [-]d.dddde[semn]ddd; E - valoare cu semn de forma [-]d.ddddE[semn]ddd; g - valoare zecimală de forma e sau f cu selectare automată a variantei

cea mai compactă conform valorii şi preciziei date. Zerourile finale sunt eliminate iar punctul zecimal apare numai dacă există parte zecimală;

G - la fel ca g dar folosind E în loc de e; c - un singur caracter; s - şir (de fapt pointer către şir). Afişează toate caracterele până la

terminatorul de şir \0.

4.3.4.2. Intrări/ieşiri în flux (de la/spre fişiere) FILE *fopen(char *cale, char *tip); stdio.h Funcţia produce deschiderea unui fişier. Argumentele funcţiei sunt: cale - reprezintă calea către fişier inclusiv numele fişierului, sub forma unui şir de caractere; tip - este un şir delimitat de ghilimele, conţinând una dintre valorile:

f - deschidere pentru citire; w - crearea unui fişier nou pentru scriere sau suprascrierea peste fişierul existent; a - adăugarea la sfârşitul unui fişier existent sau crearea unui fişier nou pentru

scriere; r+ - deschiderea unui fişier existent pentru actualizare (citire şi scriere); w+ - crearea unui fişier nou pentru actualizare (citire şi scriere) sau suprascrierea

unui fişier existent; a+ - deschiderea pentru adăugare într-un fişier existent sau crearea unui fişier nou

pentru scriere. Caracterele t şi b adăugate caracterelor r w sau a specifică modul de transmitere text sau

binar. În modul text (t) caracterul CR-LF este transformat în LF la intrare iar caracterul LF este transformat în CR-LF la ieşire. Caracterul CTRL+Z este interpretat la intrare ca sfârşit de fişier. În modul binar (b) transformările de mai sus nu au loc.

Valoarea returnată de funcţie este un pointer către un fişier deschis. Acesta este folosit ca argument în funcţiile de citire/scriere ca fread şi fwrite, sau pentru închidere de fişier, ca fclose.

int fclose(FILE *fisier); stdio.h Funcţia închide fişierul desemnat prin pointerul către fişier *fişier, deschis anterior cu

funcţia fopen. Valoarea returnată este 0 în caz de succes şi EOF altfel. int fcloseall(void); stdio.h Funcţia are ca efect închiderea tuturor fişierelor deschise. Valoarea returnată este numărul

de fişiere închise, sau EOF în caz de eroare. int fgetc(FILE *fisier); stdio.h Argumentul funcţiei este un pointer către fişier, returnat de funcţia fopen care deschide

fişierul pentru citire. Funcţia citeşte din fişier caracterul corespunzător indicatorului de poziţie curentă în fişier şi apoi incrementează indicatorul de poziţie cu o unitate. Valoarea returnată de funcţie ca întreg fără semn este este caracterul citit. În caz de eroare sau la atingerea sfârşitului de fişier, funcţia returnează EOF.

Page 104: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 92

Ca exemplu pentru funcţiile descrise mai înainte, iată programul următor:

#include <stdio.h> #include <string.h> #include <conio.h> main() {FILE *fwr,*frd; char tampon[]="0123456789ABCDEF"; int i=0; char car; fwr=fopen("HEXAZEC.FIS","w"); fwrite(&tampon, strlen(tampon),1,fwr); fclose(fwr); frd=fopen("HEXAZEC.FIS","r"); while((car=fgetc(frd))!=EOF){fputc(car,stdout); i++;} printf("\nAu fost citite %i caractere din fisier.\n",i); fclose(frd); getch(); }

Acest program deschide, pentru scriere, un fişier nou cu numele HEXAZEC.FIS în directorul de lucru curent şi scrie în el şirul de caractere "0123456789ABCDEF", după care închide fişierul. În continuare, fişierul este deschis din nou, de data aceasta pentru citire. Cât timp caracterul citit din fişier nu este caracterul EOF (sfârşit de fişier), caracterul citit cu funcţia fgetc este transmis la ieşirea standard, adică la ecran, şi contorizează numărul i de caratere citite. După întâlnirea sfârşitului de fişier, este afişat mesajul cu privire la numărul de caractere citite şi apoi este închis fişierul.

int fputc(int car, FILE *fisier); stdio.h Funcţia are ca prim parametru caracterul car care trebuie scris în fişierul determinat de cel

de al doilea parametru. Acesta poate fi un pointer către un fişier deschis pentru scriere sau numele stdout pentru ieşirea pe ecran. O variantă asemănătoare este funcţia putc. Valoarea returnată de funcţie este caracterul car, iar în caz de eroare, EOF.

int fgets(char *sir, int ncar, FILE *fisier); stdio.h Primul parametru al funcţiei este un pointer către un tampon pentru şirul de caractere

(numele şirului). Al doilea parametru este lungimea tamponului (ncar) adică numărul de caractere de citit plus o locaţie pentru terminatorul de şir (caracterul \0). Al treilea parametru este un pointer către fişierul deschis cu funcţia fopen. Funcţia citeşte din fişier ncar-1 caractere sau câte caractere întâlneşte până la primul caracter new-line (\n), dacă acesta este găsit înainte de citirea numărului de caractere prescris, şi apoi adaugă terminatorul de şir. Valoarea returnată este pointerul către şir sau NULL în caz de eroare sau sfârşit de fişier.

int fputs(char *sir, FILE *fisier); stdio.h Primul parametru al funcţiei este numele şirului de scris, iar al doilea este pointerul către

fişierul în care se face scrierea, pointer returnat de funcţia fopen, sau numele stdout pentru scrierea pe ecran. Şirul este scris la ieşirea indicată cu adăugarea terminatorului de şir \0, fără a fi adăugat caracterul new-line. Valoarea returnată este este un număr nenegativ sau EOF în caz de eroare.

int fread(void *ptr, size_t lung, size_t nart, FILE *fisier); stdio.h Primul argument al funcţiei este un pointer către un bloc de memorie în care se face

memorarea octeţilor citiţi. Al doilea argument este lungimea în octeţi a fiecăruia dintre cele nart articole citite. Al treilea argument este numărul de articole de citit. Al patrulea argument

Page 105: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 93

este pointerul către fişierul deschis pentru citire cu funcţia fopen. Blocul de memorie de stocare trebuie să aibă lungimea de minimum lung*nart octeţi. Valoarea returnată de funcţie este numărul efectiv de articole citite. În caz de eroare sau de întâlnire a sfârşitului de fişier, este returnat zero.

int fwrite(void *ptr, size_t lung, size_t nart, FILE *fisier); stdio.h Semnificaţia parametrilor formali şi a valorii returnate este aceeaşi ca la funcţia fread cu

deosebirea că, de această dată, este vorba de o operaţie de scriere.

int feof(FILE *fisier); stdio.h Funcţia are ca parametru pointerul către fişierul deschis pentru citire cu funcţia fopen.

Funcţia testează dacă operaţia anterioară de citire din fişier a atins sfârşitul acestuia şi, în acest caz, returnează o valoare non zero, sau zero în caz contrar. Returnarea valorii non zero are loc până când fişierul este redeschis (cu rewind) sau închis.

int fseek(FILE *fisier, long depl, int reper); stdio.h Primul parametru este un pointer către fişierul deschis cu funcţia fopen. Parametrul depl reprezintă

un deplasament în raport cu parametrul reper care poate avea valorile din tabelul următor: Constanta simbolică Valoarea numerică Locaţia în fişier

SEEK_SET 0 Începutul fişierului SEEK_CUR 1 Poziţia curentă în fişier SEEK_END 2 Sfârşitul fişierului

Funcţia returnează zero dacă repoziţionarea afost posibilă, şi nonzero în caz de eşec. În caz de eşec, variabila globală errno poate avea una dintre valorile: EBADF - pointer de fişier greşit, EINVAL - argument incorect.

De exemplu, programul:

#include <stdio.h> #include <conio.h> main() {FILE *frd; int i=11; char car; frd=fopen("HEXAZEC.FIS","r"); fseek(frd,i,SEEK_SET); car=fgetc(frd); printf("Al %i-lea caracter din fisier este: %c\n",i,car); fclose(frd); getch(); } deschide fişierul creat cu exemplul de la funcţia fgetc, şi afişează: Al 11-lea caracter din fisier este: B

int fprintf(FILE *fisier, char * format[, argument,...]); stdio.h Funcţia lucrează asemănător cu funcţia printf, cu deosebirea că scrierea se face nu pe ecran

ci la ieşirea indicată de primul argument, care pote fi un pointer către fişierul deschis cu funcţia fopen, sau numele standard predefinit (de exemplu stdout).

int fscanf(FILE *fisier, char * format[, adresa,...]); stdio.h Funcţia citeşte câmpurile de date începând de la poziţia curentă a indicatorului de poziţie în

fişier şi le stochează la adresele indicate. Citirea se face conform formatului: %[lăţime][h | l | L]tip

Page 106: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 94

unde: lăţime este numărul de caractere de citit, iar h, l şi L sunt modificatori de tip cu semnificaţiile: h - short int; l - long int dacă tip specifică conversia la întreg; l - double dacă tip specifică conversia la virgulă mobilă; L - long double, valabil numai pentru conversia la virgulă mobilă; tip este specificatorul de tip la care se face conversia caracterelor citite.

Observaţie: funcţia încheie citirea înainte de a citi numărul de caractere egal cu lăţime, dacă întâlneşte un spaţiu sau un caracter neconvertibil.

Valoarea returnată de funcţie este numărul de câmpuri citite, convertite şi stocate, eventual 0, şi EOF la atingerea sfârşitului de fişier.

De exemplu, programul:

#include <stdio.h> #include <conio.h> #include <math.h> main() {FILE *fwr,*frd; float valcit; char numfis[]="VALPI.DAT"; char sirscr[]="pi=", sircit[10]; fwr=fopen(numfis,"w"); fprintf(fwr,"%s %7.4f",sirscr,M_PI); fclose(fwr); frd=fopen(numfis,"r"); fscanf(frd,"%s%f",&sircit,&valcit); printf("S-au citit: %s si %f\n",sircit,valcit); fclose(frd); getch(); }

crează fişierul VALPI.DAT în care scrie şirul pi= 3.1416 şi îl închide. Fişierul este deschis din nou, de data aceasta pentru citire, este citit şirul de caractere şi valoarea şi, înainte de a închide fişierul din nou, este făcută afişarea: S-au citit: pi= si 3.141600

void rewind(FILE *fisier); stdio.h Funcţia repoziţionează indicatorul de poziţie curentă în fişier la începutul fişierului. int remove(char *numefis); stdio.h Singurul parametru al acestei funcţii este numele fişierului (numefis), eventual incluzând

calea de acces către el. Funcţia şterge fişierul indicat. Dacă fişierul era anterior deschis, pentru a se încerca ştergerea lui el trebuie mai întâi închis. Valoarea returnată este 0 dacă ştergerea a putut fi efectuată cu succes, sau -1 în caz de eroare, când variabila globală errno va fi setată pe una dintre valorile: EACCES - acces interzis (încercare de ştergere a unui fişier cu atributul read only), ENOENT - nume de fişier sau cale greşite.

int rename(char *numevechi, char *numenou); stdio.h Funcţia redenumeşte fişierul numevechi în numenou, ca în secvenţa de program:

..... char nv[]="VALPI.DAT", nn[]="PIVAL.DAT"; ..... rename(nv,nn); .....

Valoarea returnată este 0 în caz desucces sau -1 în caz de eşec, când variabila globală errno va fi setată pe una dintre valorile: EACCES şi ENOENT descrise la funcţia remove, sau ENOTSAM - inexistenţa dispozitivului indicat.

Page 107: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 95

4.3.5. Funcţii de lucru cu şiruri de caractere Funcţiile descrise în acest paragraf sunt referite prin intermediul fişierului antet string.h. void *memcpy(void *dest, void *sursa, size_t n); string.h Funcţia copiază un bloc de n octeţi din sursa în dest. Dacă sursa şi dest se suprapun,

comportamentul memoriei este nedefinit. Valoarea returnată este un pointer către dest.

void *memmove(void *dest, void *sursa, size_t n); string.h Funcţia lucrează la fel ca şi memcpy, dar se comportă bine şi dacă sursa şi dest se suprapun.

void *memset(void *sir, int car, size_t n); string.h Funcţia setează primii n octeţi din blocul de memorie sir cu caracterul car. Valoarea

returnată este un pointer către şirul sir. void setmem(void *dest, unsigned lungime, char valoare); string.h Funcţia atribuie valoarea de tip caracter valoare unui domeniu de memorie de lungime

dată, punctat de pointerul dest. Nu este returnată nici o valoare.

char *strcpy(char *dest, char *sursa); string.h Funcţia copiază un şir din sursa în dest, oprindu-se după ce caracterul terminator de şir \0

al şirului sursa a fost copiat. Valoarea returnată este un pointer către dest.

char strcat(char *dest, char *sursa); string.h Funcţia adaugă o copie a şirului sursa la sfârşitul şirului dest. Ambele şiruri trebuie să se

termine prin caracterul terminator de şir \0. Lungimea şirului rezultat este strlen(sursa)+strlen(dest). Valoarea returnată este un pointer către şirul concatenat dest.

size_t strlen(char *sir); string.h Funcţia calculează lungimea şirului sir. Valoarea returnată constă din numărul caracterelor

şirului sir, mai puţin caracterul terminator de şir \0. char *strrev(char *sir); string.h Funcţia inversează ordinea caracterelor şirului sir, mai puţin caracterul terminator de şir \0.

Valoarea returnată este un pointer către şirul inversat.

char *strset(char *sir, int car); string.h Funcţia completează în întregime şirul sir cu caracterul car. Valoarea returnată este un

pointer către sir. char *strlwr(char *sir); string.h Funcţia converteşte toate caracterele unui şir în litere mici. Valoarea returnată este un

pointer către sir. char *strupr(char *sir); string.h Funcţia converteşte toate caracterele unui şir în litere mari. Valoarea returnată este un

pointer către sir. 4.3.6. Funcţii de clasificare şi conversie a caracterelor Funcţiile descrise în acest paragraf sunt referite prin intermediul fişierului antet ctype.h. int isalnum(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este alfanumeric, şi zero în

caz contrar.

Page 108: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 96

int isalpha(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este alfabetic, şi zero în caz contrar. int isascii(int c); ctype.h Funcţia testează dacă caracterul c este un caracter ASCII şi returnează o valoare diferită de

zero, sau zero în caz contrar. Valoarea diferită de zero este returnată dacă octetul mai puţin semnificativ al caracterului c este cuprins între 0 şi 127.

int iscntrl(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este de control, şi zero în caz contrar. int isdigit(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este zecimal, şi zero în caz contrar. int isgraph(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este caracter tipăribil

(exceptând caracterul spaţiu), şi zero în caz contrar. int islower(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este o literă mică, şi zero în

caz contrar. int isprint(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este tipăribil (inclusiv

caracterul spaţiu), şi zero în caz contrar.

int ispunct(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este de punctuaţie, şi zero în

caz contrar. int isspace(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este caracter tipăribil de

spaţiere (spaţiu, TAB, carriage return, new-line, tab vertical, avans la pagină nouă, etc), şi zero în caz contrar.

int isupper(int c); ctype.h Funcţia returnează o valoare diferită de zero când caracterul c este o literă majusculă, şi

zero în caz contrar. int tolower(int c); ctype.h Funcţia transformă caracterul c în literă mică. Valoarea returnată este valoarea caracterului

c convertit în literă mică, dacă acesta a fost iniţial o majusculă, altfel o lasă neschimbată. int toupper(int c); ctype.h Funcţia transformă caracterul c în literă majusculă. Valoarea returnată este valoarea

caracterului c convertit în majusculă, dacă acesta a fost iniţial o literă mică, altfel o lasă neschimbată.

4.3.7. Funcţii de acces la directoare şi dispozitive Funcţiile descrise în acest paragraf sunt referite prin intermediul fişierului antet dir.h.

Page 109: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 97

int chdir(char *cale); dir.h Funcţia face ca directorul specificat prin şirul cale să devină directorul curent de lucru.

Şirul cale trebuie să specifice un director existent. Dacă operaţia a avut loc cu succes, este returnată valoarea 0. Altfel, este returnată valoarea -1 iar variabila globală errno este stabilită la valoarea ENOENT (calea sau numele fişierului nu pot fi găsite).

int getcurdir(int dispozitiv, char *director); dir.h Funcţia returnează directorul curent din dispozitivul specificat. Argumentul dispozitiv este

un număr atribuit dispozitivului (0 pentru dispozitivul implicit, 1 pentru A, 2 pentru B, etc). Argumentul director punctează către o zonă de memorie cu lungimea MAXDIR unde este plasat un nume de director terminat cu caracterul NULL (\0). Numele nu conţine specificaţia dispozitivului şi nu începe cu caracterul \.

MAXDIR este o valoare predefinită în fişierul dir.h, egală cu 66 pentru aplicaţii pe 16 biţi, şi cu 260 pentru 32 biţi, şi reprezintă lungimea maximă a şirului care descrie directorul, incluzând caracterele backslash (\).

Valoarea returnată este 0 în caz de succes sau -1 în caz de eroare. De exemplu, programul:

#include <stdio.h> #include <conio.h> #include <dir.h> main() {char dir_vechi[MAXDIR]; char dir_nou[MAXDIR]; getcurdir(0,dir_vechi); printf("Directorul curent initial este: \\%s\n",dir_vechi); chdir("\\"); getcurdir(0, dir_nou); printf("Acum directorul curent este: \\%s\n",dir_nou); printf("Revenire la directorul initial: \\%s\n",dir_vechi); chdir(dir_vechi); getch(); } va produce afişarea: Directorul curent initial este: \TCLITE\BIN Acum directorul curent este: \ Revenire la directorul initial: \TCLITE\BIN

int getdisk(void); dir.h Funcţia returnează un număr întreg reprezentând dispozitivul curent: 0 pentru A, 1 pentru

B, 2 pentru C, etc. int setdisk(int dispozitiv); dir.h Funcţia stabileşte ca dispozitiv curent unul asociat cu valorile: 0 pentru A, 1 pentru B, 2

pentru C, etc, şi returnează numărul total al dispozitivelor disponibile. 4.3.8. Funcţii de alocare a memoriei Funcţiile descrise în acest paragraf sunt referite prin intermediul fişierelor antet alloc.h sau

malloc.h. void *calloc(size_t nrart, size_t mărime); alloc.h sau malloc.h Funcţia alocă un spaţiu (bloc) de nrart*mărime octeţi în memoria de bază. Blocul nu

poate depăşi 64K. Parametrul nrart reprezintă numărul de articole iar mărime este lungimea în octeţi a unui articol.

Page 110: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 98

Valoarea returnată este un pointer către blocul de memorie alocat, sau NULL dacă nu a fost găsit suficient spaţiu pentru alocarea blocului, sau dacă unul dintre parametrii nrart sau mărime este egal cu 0.

void *malloc(size_t mărime); alloc.h sau malloc.h Funcţia este similară cu calloc dar are un singur parametru reprezentând mărimea totală a

blocului de memorie de alocat. Valoarea returnată este un pointer către blocul de memorie alocat, sau NULL dacă nu a fost găsit suficient spaţiu pentru alocarea blocului, sau dacă parametrul mărime este egal cu 0.

void *realloc(void *bloc, size_t mărime); alloc.h sau malloc.h Funcţia realocă memoria de bază, restrângând sau extinzând blocul reprezentat prin

argumentul bloc care punctează către o zonă de memorie alocată anterior cu calloc, malloc sau realloc, la o nouă mărime. Dacă mărime este zero, blocul de memorie este eliberat şi se returnează NULL. Dacă bloc este un pointer NULL, funcţia realloc lucrează exact la fel ca malloc. Mărimea blocului de realocat este ajustată la noua mărime prin copierea conţinutului la o nouă adresă, dacă este necesar.

Valoarea returnată este adresa blocului realocat care poate fi diferită de adresa iniţială a blocului. Dacă blocul nu poate fi realocat, se returnează NULL.

void free(void *bloc); alloc.h sau malloc.h Funcţia eliberează spaţiul de memorie alocat anterior pentru bloc cu o funcţie calloc,

malloc sau realloc. void far *farcalloc(unsigned long nrart, unsigned long mărime); alloc.h sau malloc.h Funcţia se aseamănă cu calloc dar lucrează cu memoria îndepărtată. Ea poate folosi toată

memoria RAM disponibilă şi poate aloca blocuri mai mari de 64K. Pentru a accesa zona de memorie alocată este necesar să se folosească pointeri far sau, dacă blocurile alocate sunt mai mari de 64K, pointeri huge.

Valoarea returnată este un pointer de tip far către blocul de memorie alocată sau NULL dacă nu există spaţiu suficient.

void far *farmalloc(unsigned long mărime); alloc.h sau malloc.h Funcţia este asemănătoare cu farcalloc dar are un un singur parametru reprezentând mărimea

totală a blocului de memorie de alocat. Valoarea returnată este un pointer de tip far către blocul de memorie alocat, sau NULL dacă nu a fost găsit suficient spaţiu pentru alocarea blocului.

void farfree(void far *bloc); alloc.h sau malloc.h Funcţia eliberează spaţiul de memorie alocat anterior pentru bloc cu o funcţie farcalloc

sau farmalloc. 4.3.9. Funcţii grafice DOS Funcţiile descrise în acest paragraf sunt referite prin intermediul fişierului graphics.h şi,

fiind utilizabile numai sub DOS, nu sunt portabile pe WINDOWS

void far arc(int xc, int yc, int ung_init, int ung_final, int raza); graphics.h Funcţia desenează un arc de cerc centrat în punctul (xc,yc), cu raza dată şi care începe de

la unghiul ung_init şi se termină la ung_final, unghiurile fiind măsurate în concordanţă cu convenţia trigonometrică. Culoarea de desenare este cea curentă. Stilul de linie nu afectează trasarea arcului, ci numai grosimea.

Page 111: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 99

void far bar(int stânga, int sus, int dreapta, int jos); graphics.h Funcţia desenează o bandă plină rectangulară bidimensională. Umplerea benzii se face cu

culoarea şi modelul de umplere curente. Conturul benzii nu este evidenţiat. Pentru evidenţierea conturului benzii se foloseşte funcţia bar3d cu grosimea egală cu zero. Parametrii stânga şi sus reprezintă coordonatele x,y ale colţului din stânga-sus, iar dreapta şi jos reprezintă coordonatele x,y ale colţului din dreapta-jos ale benzii.

void far bar3d(int stânga, int sus, int dreapta, int jos, int gros, int plafon); graphics.h Funcţia desenează o bară plină rectangulară tridimensională. Umplerea barei se face cu

culoarea şi modelul de umplere curente. Conturul barei nu este desenat cu stilul de linie şi culoarea curente. Parametrii stânga şi sus reprezintă coordonatele x,y ale colţului din stânga-sus, iar dreapta şi jos reprezintă coordonatele x,y ale colţului din dreapta-jos ale barei. Profunzimea barei este dată de parametrul gros. Parametrul plafon stabileşte dacă plafonul barei este desenat (valoare nonzero) sau nu (valoare zero), permiţând desenarea de bare supraetajate.

void far circle(int xc, int yc, int raza); graphics.h Funcţia desenează un cerc centrat în punctul (xc,yc), cu raza dată. Culoarea de desenare

este cea curentă. Stilul de linie nu afectează trasarea cercului, ci numai grosimea. void far cleardevice(void); graphics.h Funcţia şterge (adică umple cu culoarea fondului) întregul ecran şi mută poziţia curentă în

punctul (0,0). void far clearviewport(void); graphics.h Funcţia şterge un port de vedere şi mută poziţia curentă în punctul (0,0) relativ la portul de

vedere curent. void far drawpoly(int nrnoduri, int far *defnod); graphics.h Funcţia desenează un poligon cu numărul de noduri dat de parametrul nrnoduri, folosind

culoarea şi stilul de linie curente. Parametrul *defnod punctează către o secvenţă de întregi în număr de 2*nrnoduri, ordonată pe perechi de coordonate x,y întregi, exprimate în pixeli, reprezentând coordonatele nodurilor poligonului. Pentru a desena o figură închisă cu n noduri trebuie ca nrnoduri=n+1, astfel încât ultima pereche de coordonate să fie identică cu prima.

void far ellipse(int xc, int yc, int ung_init, int ung_final, int a, int b); graphics.h Funcţia desenează o elipsă cu culoarea curentă de desenare, având centrul în punctul xc,yc,

iar semiaxele orizontală şi verticală de mărime a şi b. Elipsa este desenată de la unghiul de început ung_init până la unghiul de sfârşit ung_final. Dacă ung_init este 0 iar ung_final este 360, elipsa este completă. Stilul de linie nu afectează trasarea cercului, ci numai grosimea.

void far fillellipse(int xc, int yc, int a, int b); graphics.h Funcţia desenează o elipsă cu centrul în xc,yc, cu semiaxele orizontală şi verticală a şi b, şi

o umple cu culoarea şi modelul curente.

void far fillpoly(int nrnoduri, int far *defnod); graphics.h Funcţia lucrează la fel ca drawpoly dar poligonul generat este umplut cu culoarea şi

modelul curente. void getarccoords(struct arccoordstype far *coordarc); graphics.h Funcţia completează structura arccoordstype punctată de pointerul coordarc, cu

Page 112: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 100

informaţia obţinută la ultimul apel al funcţiei arc. Structura arccoordstype este definită în fişierul graphics.h astfel:

struct arccoordstype{int x,y; int xstart, ystart, xend, yend;}; Membrii acestei structuri specifică centrul arcului (x şi y), punctul de început (xstart şi

ystart) şi punctul de sfârşit (xend şi yend).

void getaspectratio(int far *aspx, int far *aspy); graphics.h Funcţia extrage valorile aspx şi aspy care reprezintă factorii de aspect ai pixelilor. La

standardul VGA, unde pixelii sunt pătraţi, aspx=aspy=10000, însă, în general, relaţia dintre cele două valori este aspy=10000, aspx<=10000.

int far getbkcolor(void); graphics.h Funcţia returnează culoarea curentă a fondului (pentru detalii a se vedea setbkcolor). int far getcolor(void); graphics.h Funcţia returnează culoarea curentă de desenare a entităţilor grafice lineare.

void far getfillpattern(char far *model); graphics.h Funcţia copiază modelul de umplere definit de utilizator, setat cu setfillpattern, într-o zonă

de memorie de 8 octeţi punctată de parametrul model. Când unui bit din model îi corespunde valoarea 1 el va fi desenat.

void far getfillsettings(struct fillsettingstype far *infoumpl); graphics.h Funcţia completează structura fillsettingstype, punctată de parametrul infoumpl, cu

informaţia despre modelul şi culoarea de umplere curente. Structura fillsettingstype este definită în fişierul graphics.h, astfel:

struct fillsettingstype{int pattern; int color;}; Funcţiile bar, bar3d, fillpoly, floodfill şi pieslice, umplu aria corespunzătoare cu modelul şi

culoarea curente. Există următoarele modele predefinite, conform tabelului de mai jos. Dacă valoarea modelului este 12 (USER_FILL), atunci va fi utilizat un model definit de utilizator.

Nume Valoare Model de umplere EMPTY_FILL 0 culoarea fondului SOLID_FILL 1 umplere solidă LINE_FILL 2 haşurare orizontală LTSLASH_FILL 3 haşurare subţire la 45° dreapta SLASH_FILL 4 haşurare groasă la 45° dreapta BKSLASH_FILL 5 haşurare subţire la 45° stânga LTBKSLASH_FILL 6 haşurare groasă la 45° stânga HATCH_FILL 7 haşurare rară XHATCH_FILL 8 haşurare încrucişată deasă INTERLEAVE_FILL 9 linii întreţesute WIDE_DOT_FILL 10 puncte rare CLOSE_DOT_FILL 11 puncte dese USER_FILL 12 model definit de utilizator

void far getimage(int stânga, int sus, int dreapta, int jos, void far *bitmap); graphics.h Funcţia copiază o imagine de pe ecran în memorie. Parametrii stânga, sus, dreapta şi jos

definesc zona dreptunghiulară de pe ecran care va fi copiată. Parametrul bitmap punctează

Page 113: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 101

către o zonă de memorie unde imaginea este memorată. Primii doi octeţi ai acestei zone sunt folosiţi pentru lungimea şi lăţimea ferestrei, iar ceilalţi pentru stocarea imaginii.

void far getlinesettings(struct linesettingstype far *infolin); graphics.h Funcţia completează structura linesettingstype, punctată de parametrul infolin, cu

informaţia despre stilul liniei curente, modelul curent şi grosimea curentă. Structura linesettingstype este definită în fişierul graphics.h, astfel:

struct linesettingstype{int linestyle; unsigned upattern; int thickness;}; Membrul linestyle specifică tipul de linie cu care se vor desena liniile în continuare. Stilurile de linie sunt următoarele:

Nume Valoare Model de umplere SOLID_LINE 0 linie continuă DOTTED_LINE 1 linie punctată CENTER_LINE 2 linie-punct DASHED_LINE 3 linie întreruptă USERBIT_LINE 4 linie definită de utilizator

Membrul thickness specifică grosimea liniei, astfel:

Nume Valoare Lăţimea în pxeli NORM_WIDTH 1 1 pixel THICK_WIDTH 3 3 pixeli

Membrul upattern este un model pe 16 biţi care este aplicat numai dacă stilul de linie (linestyle) este USERBIT_LINE. În acest caz, când un bit al modelului este 1, pixelul corespunzător din linie este desenat cu culoarea curentă. Dacă linestyle nu este USERBIT_LINE, deşi parametrul upattern este ignorat, el trebuie totuşi să fie furnizat.

int far getmaxx(void); graphics.h int far getmaxy(void); graphics.h Cele două funcţii returnează valorile maxime ale coordonatelor x şi y alr ecranului curent

pentru dispozitivul grafic şi modul grafic curente. Valorile sunt returnate în coordonate ecran. unsigned far getpixel(int xpix, int ypix); graphics.h Parametrii xpix şi ypix sunt coordonatele unui pixel. Funcţia returnează o valoare întreagă

fără semn reprezentând culoarea pixelului.

void far gettextsettings(struct textsettingstype far *infotiptext); graphics.h Funcţia completează structura textsettingstype, punctată de parametrul infotiptext, cu

informaţia despre fontul curent al caracterelor, direcţia, mărimea şi alinierea lor. Structura textsettingstype este definită în fişierul graphics.h astfel:

struct textsettingstype{int font; int direction; int charsize; int horiz; int vert;}; A se vedea funcţia settextstyle pentru descrierea unora dintre membrii structurii.

void far getviewsettings(struct viewporttype far *portvedere); graphics.h Funcţia completează structura viewporttype, punctată de parametrul portvedere, cu

informaţia despre portul de vedere curent. Structura viewporttype este definită în fişierul graphics.h astfel:

Page 114: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 102

struct viewporttype {int left; int top; int right; int bottom; int clip;}; Membrii left, top, right şi bottom sunt limitele stânga, sus, dreapta şi jos ale portului de

vedere, iar clip, dacă este nonzero, semnifică decuparea tuturor desenelor la limitele portului de vedere.

int far getx(void); graphics.h int far gety(void); graphics.h Funcţiile returnează coordonatele x şi y ale poziţiei curente, în valori relative la portul de

vedere curent. unsigned far imagesize(int stanga, int sus, int dreapta, int jos); graphics; Funcţia determină şi returnează mărimea zonei de memorie necesară pentru stocarea unei

imagini cuprinsă într-un dreptunghi având limitele stânga, sus, dreapta şi jos. Dacă mărimea zonei de memorie necesară stocării imaginii este mai mare sau egală cu 64K-1, funcţia returnează valoarea 0xFFFF (-1).

void initgraph(int far *dispgraf, int far *modgraf, char far *cale); graphics.h Funcţia iniţializează sistemul grafic prin încărcarea de pe disc a unui dispozitiv grafic logic

specificat prin dispgraf şi trecând sistemul în modul grafic specificat prin modgraf. Funcţia poate folosi un dispozitiv grafic şi un mod grafic anume, specificate, sau poate executa acţiunea prin autodetecţie. De asemenea, initgraph resetează toate setările grafice la valorile lor implicite (poziţie curentă, paletă de culori, porturi de vedere, etc) şi resetează funcţia graphresult la zero. În mod normal, initgraph încarcă dispozitivul grafic alocând memorie pentru el, apoi încarcă fişierul corespunzător cu extensia .BGI de pe disc. Parametrul cale specifică calea spre directorul unde initgraph caută dispozitivele. Iniţial initgraph caută pe calea specificată de cale apoi, dacă nu găseşte acolo, caută în directorul curent. Când cale este nulă fişierul dispozitiv (*.BGI) trebuie să se afle în directorul curent.

Parametrul dispgraf poate avea diferite valori. Multe dintre ele reprezintă diferite versiuni de dispozitive grafice depăşite de evoluţia tehnologică. Ele pot fi aflate consultând help-ul mediului de programare C în care se lucrează. Cel mai frecvent este folosită valoarea DETECT (0) care produce autodetecţia. Dacă este folosită valoarea DETECT pentru dispgraf, valoarea modgraf nu mai are importanţă, modul grafic fiind stabilit prin autodetecţie.

Funcţia nu returnează valoare dar, prin efect lateral, setează codul intern de eroare (care poate fi determinat cu funcţia graphresult) la una din valorile:

grOK 0 Iniţializare desfăşurată cu succes grNotDetected -2 Nu se poate detecta placa grafică grFileNotFound -3 Nu poate fi găsit fişierul dispozitivului grafic logic grInvalidDriver -4 Dispozitiv grafic logic invalid grNoLoadMem -5 Memorie insuficientă pentru încărcarea dispozitivului

int far graphresult(void); graphics.h Funcţia returnează codul de eroare pentru ultima ultima operaţie grafică eşuată şi

restabileşte nivelul de eroare la valoarea grOK. Codurile de eroare returnate sunt definite în graphics.h şi pot fi consultate prin help-ul mediului de programare C.

char far *grapherrormsg(int coderoare); graphics.h Funcţia primeşte argumentul coderoare obţinut anterior cu graphresult, şi returnează un

pointer către un şir de caractere mesaj de eroare.

Page 115: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 103

void far *closegraph(void); graphics.h Funcţia eliberează toată memoria alocată sistemului grafic, apoi restabileşte ecranul în

modul anterior apelului funcţiei initgraph. void far line(int xi, int yi, int xf, int yf); graphics.h Funcţia desenează o linie cu culoarea, stilul şi grosimea de linie curente, între punctele

(xi,yi) şi (xf, yf), fără actualizarea poziţiei curente. void far linerel(int deplx, int deply); graphics.h Funcţia desenează o linie cu culoarea, stilul şi grosimea de linie curente, începând de la

punctul poziţiei curente (xc, yc) considerat ca punct iniţial, până la punctul final (xc+deplx, yc+deply). Poziţia curentă avansează la punctul final.

void far lineto(int xf, int yf); graphics.h Funcţia desenează o linie cu culoarea, stilul şi grosimea de linie curente, începând de la

punctul poziţiei curente (xc, yc) considerat ca punct iniţial, până la punctul final (xf,yf). void far moverel(int deplx, int deply); graphics.h Funcţia deplasează poziţia curentă cu deplx pixeli pe axa x şi cu deply pixeli pe axa y. void far moveto(int noux, int nouy); graphics.h Funcţia mută poziţia curentă în poziţia nouă (noux, nouy).. void far outtext(char far *şirtext); graphics.h Funcţia afişează în modul grafic şirul şirtext, în portul de vedere folosind fontul, direcţia şi

mărimea de text curente. Afişarea textului are loc începând de la poziţia curentă. Dacă alinierea textului pe orizontală este LEFT_TEXT şi direcţia textului este HORIZ_DIR, coordonata x a poziţiei curente este avansată cu textwidth(şirtext). Altfel, poziţia curentă rămâne neschimbată. Pentru a menţine controlul dimensiunilor rezultate când se folosesc diferite stiluri de caractere, trebuie folosite funcţiile textwidth şi textheight pentru a determina dimensiunea şirului. Dacă şirul este tipărit cu stilul de caractere implicit folosind funcţia outtext, orice parte a şirului care depăşeşte marginea portului de vedere curent este trunchiată. Funcţia outtext poate fi folosită numai în modul grafic. Ea nu lucrează în modul text.

void far outtextxy(int x, int y, char far *şirtext); graphics.h Funcţia este asemănătoare cu outtext, dar afişează textul începând nu de la poziţia curentă,

ci de la poziţia specificată de punctul (x, y). void far pieslice(int xc, int yc, int ungin, int ungfin, int raza); graphics.h Funcţia desenează şi umple un sector de disc cu raza dată, cu centrul în (xc, yc), începând

de la unghiul ungin şi sfârşind la unghiul ungfin. Sectorul este conturat cu culoarea curentă şi este umplut cu modelul şi culoarea de umplere curente. Unghiurile sunt specificate în grade.

void far putimage(int stânga, int sus, void far *bitmap, int oper); graphics.h Funcţia afişează o imagine salvată anterior cu funcţia getimage. Colţul din stânga-sus al

imaginii este plasat în punctul de coordonate (stânga, sus). Parametrul bitmap punctează către o zonă de memorie unde este stocată imaginea sursă. Parametrul oper specifică un operator de combinare care controlează modul cum este calculată culoarea fiecărui pixel care este pus pe ecran, bazându-se pe pixelul deja existent pe ecran şi pe cel din memorie.

Page 116: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 104

Operatorii oper pot avea valorile definite în fişierul graphics.h, astfel:

Nume simbolic Valoare Descriere COPY_PUT 0 Copiere XOR_PUT 1 SAU exclusiv OR_PUT 2 SAU inclusiv AND_PUT 3 ŞI NOT_PUT 4 Copierea inversului sursei

void far putpixel(int xp, int yp, int culoare); graphics.h Funcţia atribuie pixelului de coordonate (xp, yp) relative la portul de vedere curent,

valoarea specificată de parametrul culoare. void far rectangle(int stânga, int sus, int dreapta, int jos); graphics.h Funcţia desenează un dreptunghi având colţurile diagunal opuse în punctele de coordonate

(stânga, sus) şi (dreapta, jos). Desenarea se face cu tipul, grosimea şi culoarea de linie curente.

void far sector(int xc, int yc, int ungin, int ungfin, int a, int b); graphics.h Funcţia desenează un sector de elipsă cu centrul în punctul (xc, yc), începând de la unghiul

ungin şi sfârşind la ungfin, exprimate în grade. Semiaxele orizontală şi verticală ale elipsei sunt a şi b. Sectorul este conturat cu culoarea curentă şi este umplut cu modelul şi culoarea definite de setfillstyle sau setfillpattern. Dacă apare o eroare la umplerea sectorului, funcţia graphresult returnează valoarea grNoScanMem= -6.

void setaspectratio(int xasp, int yasp); graphics.h Funcţia schimbă raportul de aspect implicit al sistemului grafic. A se vedea funcţia

getaspectratio. void far setbkcolor(int culoare); graphics.h Funcţia stabileşte culoarea fondului la valoarea culoare, conform tabelului următor:

Val. Nume simb. Val. Nume simb. Val. Nume simb. Val. Nume simb. 0 BLACK 4 RED 8 DARKGRAY 12 LIGHTRED 1 BLUE 5 MAGENTA 9 LIGHTBLUE 13 LIGHTMAGENTA2 GREEN 6 BROWN 10 LIGHTGREEN 14 YELLOW 3 CYAN 7 LIGHTGRAY 11 LIGHTCYAN 15 WHITE

void far setcolor(int culoare); graphics.h Funcţia stabileşte culoarea de desenare curentă la valoarea culoare, conform aceluiaşi tabel

de la funcţia setbkcolor. void far setfillstyle(int model, int culoare); graphics.h Funcţia stabileşte modelul şi culoarea curentă de umplere la valorile model şi culoare

indicate. Dacă un parametru al funcţiei este incorect, ea nu va avea nici un efect iar apelul funcţiei graphresult va returna valoarea grError= -11.

void far setfillpattern(char far modelutil, int culoare); graphics.h Funcţia este asemănătoare cu setfillstyle, cu deosebirea că este folosită pentru a stabili un

model de umplere definit de utilizator (modelutil), ca matrice de 8X8 biţi, în loc de un model

Page 117: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 105

predefinit. Parametrul modelutil punctează către o secvenţă de 8 octeţi, în care fiecărui octet îi corespund 8 pixeli din model. Pentru fiecare bit din modelutil egal cu 1, este desenat un pixel corespunzător de pe ecran.

void setlinestyle(int stillinie, unsigned modelutil, int grosime); graphics.h Funcţia stabileşte stilul tuturor liniilor desenate cu funcţiile line, lineto, rectangle,

drawpoly, etc. Parametrii stillinie şi grosime necesare pentru a defini stilul şi grosimea de linie cu care se

lucrează, sunt cele definite la funcţia getlinesettings. Modelul de desenare modelutil trebuie să fie furnizat, deşi el este luat în considerare numai dacă stillinie are valoarea USERBIT_LINE. Dacă se introduce un parametru invalid, funcţia nu are efect, iar funcţia graphresult va returna codul de eroare grError= -11.

void far settextjustify(int alinoriz, int alinvert); graphics.h Funcţia stabileşte modul de aliniere al textului. Parametrul alinoriz determină alinierea pe

orizontală iar alinvert stabileşte alinierea pe verticală, în raport cu un centru de aliniere considerat în poziţia grafică curentă. În mod implicit, iniţial alinierea orizontală este LEFT_TEXT iar cea verticală este TOP_TEXT. Valorile predefinite în fişierul graphics.h ale parametrilor alinoriz şi alinvert sunt cele din tabelul de mai jos:

Parametru Nume simbolic Valoare Acţiune LEFT_TEXT 0 text aliniat la stânga

alinoriz CENTER_TEXT 1 text centrat pe orizontală RIGHT_TEXT 2 text aliniat la dreapta BOTTOM_TEXT 0 text aliniat la bază

alinvert CENTER_TEXT 1 text centrat pe verticală TOP_TEXT 2 text aliniat la vârf

Dacă alinoriz este LEFT_TEXT şi direcţia textului este HORIZ_DIR, componenta x a poziţiei curente este avansată, după ce se apelează funcţia outtext(şir), cu o valoare egală cu lungimea şirului. Funcţia settextjustify afectează numai textul scris cu outtext, şi nu poate fi folosită în modul text.

Dacă unul dintre parametri este invalid, nu se obţine nici un efect, iar funcţia graphresult va returna codul de eroare grError= -11.

void far settextstyle(int font, int direcţie, int mărime); graphics.h Funcţia stabileşte fontul, direcţia şi mărimea caracterelor cu care va fi afişat textul.

Apelarea funcţiei settextstyle afectează textele afişate de funcţiile outtext şi outtextxy. Parametrii font şi direcţie sunt descrişi în tabelele următoare:

Constanta simbolică pentru font

Valoare Constanta simbolică pentru font

Valoare

DEFAULT_FONT 0 SIMPLEX_FONT 6 TRIPLEX_FONT 1 TRIPLEX_SCR_FONT 7 SMALL_FONT 2 COMPLEX_FONT 8 SANS_SERIF_FONT 3 EUROPEAN_FONT 9 GOTHIC_FONT 4 BOLD_FONT 10 SCRIPT_FONT 5 - -

Page 118: Programarea Calculatoarelor si Limbaje de Programare

Cap.4. Programarea în limbajul C sub sistemul DOS 106

Constanta simbolică pentru direcţie Valoare Descriere HORIZ_DIR 0 Scriere de la stânga la dreapta VERT_DIR 1 Scriere de jos în sus

Parametrul mărime este factorul de amplificare a dimensiunii fiecărui caracter, într-un dreptunghi de 8X8 pixeli. Dacă mărime este egal cu 1, funcţiile outtext şi outtextxy afişează fonturile de 8X8 într-un dreptunghi de 8X8 pixeli. Dacă mărime este egal cu 2, afişarea se va face într-un dreptunghi de 16X16 pixeli, etc.

void far setviewport(int stanga, int sus, int dreapta, int jos, int decupare); graphics; Funcţia stabileşte o nouă fereastră grafică având colţurile exprimate în coordonate absolute

ale ecranului, în punctele (stânga, sus) şi (dreapta, jos). Poziţia curentă este mutată în punctul (0,0) al noii ferestre. Parametrul decupare este 1 dacă desenele se întrerup la marginile ferestrei definite, sau 0 altfel. Dacă unul dintre parametri este invalid, nu se obţine nici un efect, iar funcţia graphresult va returna codul de eroare

grError= -11.

int far textheight(char far *şirtext); graphics.h Funcţia returnează înălţimea în pixeli a şirului de text şirtext pe baza dimensiunii fontului

curent şi a factorului de multiplicare a dimensiunii. int far textwidth(char far *şirtext); graphics.h Funcţia returnează lăţimea în pixeli a şirului de text şirtext pe baza dimensiunii fontului

curent şi a factorului de multiplicare a dimensiunii.

Page 119: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 107

Cap.5. Elemente de operabilitate sub Windows

Sistemul de operare Windows face parte dintr-o categorie mai largă de sisteme numită Interfeţe grafice cu utilizatorul (GUI sau Graphic User Interface). Programarea aplicaţiilor care rulează sub acest sistem trebuie să ţină cont de o serie de concepte pe care le vom prezenta în continuare.

UC RAM HDD

Sistem de operare Resursecomune

Aplicaţie executabilă Resurse specifice(proprii)

Memorie virtuală

Mărime variabilă

Schimb de comenzi

Schimb de date

Figura 5.1.1. Relaţia calculator – mediu de execuţie

§5.1. Relaţia calculator – mediu de execuţie Definiţie: Prin calculator se înţelege maşină fizică constituită din blocurile electronice

necesare prelucrării semnalelor electrice care reprezintă comenzi şi date, adică informaţia. Definiţie: Prin mediu de execuţie se înţelege configuraţia informaţiei din calculator

partajată între diferitele module de program care rulează la un moment dat. În timpul lucrului între componentele principale ale calculatorului şi mediul de execuţie se

stabiliesc relaţiile prezentate în figura 5.1.1. Aplicaţia executabilă, compusă dintr-unul sau mai multe module de program, comunică

cu sistemul de operare care îi satisface cerinţele de acces la memoria RAM sau la harddisc (HDD). Datele aflate iniţial pe harddisc sunt transferate la:

- UC – unitatea centrală care realizează execuţia propriu-zisă a acţiunilor programelor; - RAM (Random Access Memory – memorie cu acces aleatoriu) care stochează temporar

datele manevrate de program; - Memoria virtuală – zonă de pe hard disc tratată de sistemul de operare la fel ca memoria

RAM. În această zonă sunt stocate datele care nu sunt de uz imediat, dar trebuie reţinute fiind necesare mai târziu.

Resursele folosite de mediul de execuţie sunt acele blocuri de informaţie (date, module de program) care sunt folosite mai frecvent şi care, având caracter de repetabilitate şi reutilizabilitate, sunt, într-o anumită măsură standardizate. Ele constituie blocuri de informaţie distincte, apelabile la cerere. Se deosebesc două tipuri de resurse:

- Resurse specifice sau resurse proprii ale aplicaţiei. Acestea sunt module de program

Page 120: Programarea Calculatoarelor si Limbaje de Programare

Cap.5. Elemente de operabilitate sub Windows 108

incluse în setul de module ale aplicaţiei şi care execută funcţii specifice, proprii numai aplicaţiai respective. Tot în această categorie intră o serie de fişiere de date sau care descriu obiecte grafice de interacţiune cum sunt cutiile de dialog, meniurile, cursoarele, etc.

- Resurse comune. Acestea sunt module de program executabile existente în sistemul de operare şi lansate în lucru de către sistemul de operare la cererea aplicaţiei sau ca urmare a unei decizii a sistemului de operare în urma apariţiei unui eveniment tratabil de către sistem. De exemplu, o serie de fişiere cu extensia .dll (dynamic link library – bibliotecă cu legare dinamică) pot fi module de program ale sistemului Windows, dar şi resurse proprii ale aplicaţiei. Tot în această categorie intră o serie de cutii de dialog standard cum sunt cele de tip Open sau Save, folosite la deschiderea sau la salvarea fişierelor.

Tendinţa recomandată este de a se folosi pe cât posibil resurse comune, gestionate de către sistemul de operare. Aceasta asigură pe de o parte robusteţea funcţionării sistemului în ansamblu, împreună cu aplicaţiile, dar şi economicitatea muncii de programare a aplicaţiilor – efort mai mic şi fişiere executabile de dimensiuni mai mici.

§5.2. Sarcini şi tehnici de realizare a sarcinilor 5.2.1. Interdependenţa sarcinilor Aplicaţiile pentru a căror deservire sunt proiectate modulele de program pot avea un grad de

complexitate foarte ridicat. Ele se compun dintr-un număr de sarcini pe care, în continuare le vom nota cu litera S, care trebuie îndeplinite şi care participă la realizarea scopului final al aplicaţiei.

În raport cu relaţiile care pot exista între sarcini acestea pot fi privite ca fiind secvenţiale sau concurente.

Fig.5.2.1.

Fig.5.2.2. Fig.5.2.3. Acţiunea sarcinilor secvenţiale se poate descrie ca un şir de sarcini S1, S2, …, Sn, figura

5.2.1, care trebuie îndeplinite în ordine pentru a realiza sarcina globală Sg. În această situaţie

Page 121: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 109

ieşirile unei sarcini servesc ca intrări pentru următoarea sarcină. De exemplu, pentru a transforma o entitate grafică 2D se pot face operaţiile de mutare,

scalare şi rotire. Ordinea lor însă nu este indiferentă, ea influenţând rezultatul obţinut, aşa cum se vede din

figurile 5.2.2 şi 5.2.3.

Fig.5.2.4. Fig.5.2.5.

Acţiunea sarcinilor concurente. Conform figurii 5.2.4 sarcinile S1, S2, …, Sn pot fi

îndeplinite în orice ordine pentru a realiza sarcina globală Sg, înainte de a se trece la realizarea sarcinii ulterioare Sn+1.

De exemplu, pentru un segment de linie deja desenat, al cărui aspect trebuie modificat şi care trebuie apoi să fie copiat, este indiferentă ordinea de aplicare a operaţiilor indicate în figura 5.2.5 pentru modificarea aspectului.

Privite deci sub aspectul interdependenţei acţiunilor de efectuat, în programarea aplicaţiilor în general şi a aplicaţiilor grafice în particular, se desprind evolutiv două tehnici de programare şi de utilizare şi anume:

- Tehnica unitasking; - Tehnica multitasking. 5.2.2. Tehnica unitasking Tehnica unitasking semnifică în principal efectuarea unei lucrări care are în vedere o

sarcină unică din punctul de vedere al finalităţii lucrării respective. Procesul de lucru cu calculatorul având un aspect dual, pe de o parte din punctul de vedere al programatorului şi, pe de altă parte din punctul de vedere al utilizatorului, problemele care caracterizează unitaskingul pot fi privite de pe cele două poziţii.

Din punctul de vedere al programatorului, scrierea unui program de tip unitasking este caracteristică programelor sistemului vechi de operare DOS, dar şi unor module de program din WINDOWS, şi presupune acapararea totală a resurselor maşinii şi controlul total al acesteia de către programul sau modulul de program în curs de execuţie. Pentru a se trece la un alt program sau modul de program, sistemul trebuie să aştepte recăpătarea controlului, deci terminarea completă a execuţiei sarcinii curente.

Din punctul de vedere al utilizatorului, unitaskingul este caracteristic efectuării unei sarcini care condiţionează total trecerea la execuţia sarcinii următoare.

Din ambele puncte de vedere, toate aplicaţiile complexe compuse dintr-un număr mare de sarcini de acest fel necesită secvenţializarea execuţiei.

În consecinţă, pot fi evidenţiate următoarele sisteme de module de acţiune (de program sau de a operaţii efectuate de utilizator), fiecare modul rezolvând o anumită sarcină:

a. Structura liniară: În figura 5.2.6 semnificaţia notaţiilor este următoarea: Mi, i=1,2,…,n sunt module de

Page 122: Programarea Calculatoarelor si Limbaje de Programare

Cap.5. Elemente de operabilitate sub Windows 110

program sau de acţiune, Fj, j=1,2,…,n-1 sunt fişiere de date. Aşa cum se observă, un fişier de date Fk este rezultatul acţiunii unui modul Mk, conţinând datele rezultate din acesta şi necesare unui modul ulterior, căruia îi servesc ca date de intrare sau necesare în timpul lucrului.

Fig.5.2.6.

Fig.5.2.7.

Ca exemplu, o lucrare de tehnoredactare efectuată cu un procesor de text şi grafică complex, aşa cum este programul WORD, poate necesita în cadrul documentului tehnoredactat o serie de imagini care trebuie pregătite de alte programe. În figura 5.2.7 este ilustrată o astfel de situaţie.

Generarea imaginii se poate face cu ajutorul unui program de sinteză de imagine, cel mai cunoscut exemplu fiind acela al programului 3D Studio, sau pot fi obţinute din scanarea unor fotografii sau preluate de la o cameră video digitală.

Prelucrarea imaginii în Corel Photo Paint poate fi necesară pentru a introduce o serie de efecte grafice speciale.

Tehnoredactarea în Word plasează imaginea în cadrul textului documentului, eventual o scalează pentru a permite o bună încadrare a ei şi o corelează cu explicaţiile din text.

Fig.5.2.8.

b. Structura inelară: Dacă rezultatul final al ultimului modul de acţiune (sau de program) necesită ajustări care

impun reluarea de la început sau dintr-o anumită fază anterioară a lanţului de acţiuni, modulul decizional Reluare, figura 5.2.8 poate decide reluarea ciclului.

Ca exemplu, dacă în urma parcurgerii lanţului de operaţii necesare tehnoredactării documentului din exemplul anterior se constată nevoia unor retuşuri sau modificări ale imaginii care necesită reluarea procesului de lucru cu Corel Photo Paint, schema de acţiune ar putea fi cea din figura 5.2.9.

Page 123: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 111

Fig.5.2.9. c. Structura subordonată inelar (supervizată): Acest tip de structură apare în cadrul unor lucrări mai complexe la care sarcinile de lucru

sunt de naturi diferite şi efectuarea uneia sau a alteia dintre ele este decisă pe baza unui complex de condiţii diverse.

În general, acest tip de structură poate fi sintetizat prin schema din figura 5.2.10.

Fig.5.2.10.

În cadrul acestei scheme există un modul supervizor S al cărui rol este realizarea direcţionării execuţiei către unul dintre modulele supervizate si, i=1,2,…,n.

Direcţionarea controlului se poate face: - în cazul controlului programat, pe baza unor criterii de validare a calităţii rezolvării

(obţinerea unui anumit efect sau precizie de rezolvare); - în cazul controlului acţiunilor utilizatorului, la cererea acestuia prin autoevaluarea

rezultatelor obţinute. De exemplu, la realizarea unei cărţi, album, sau pliant publicitar, redactorul în calitate de factor supervizor, coordonează tipurile de lucrări care concurează la elaborarea cărţii, conform schemei din figura 5.2.11.

Fig.5.2.11.

Page 124: Programarea Calculatoarelor si Limbaje de Programare

Cap.5. Elemente de operabilitate sub Windows 112

d. Structuri combinate. În funcţie de situaţiile practice concrete se poate concepe orice combinaţie sau încuibare pe

un anumit număr de nivele a structurilor de la punctele a, b, sau c, prezentate anterior.

5.2.3. Tehnica multitasking Multitaskingul înseamnă posibilitatea unui sistem de a efectua mai multe sarcini care îşi

împart între ele resursele sistemului. În funcţie de resursele pe care le posedă sistemul multitaskingul poate fi organizat diferit.

Resursa critică a sistemului este microprocesorul. Dacă sistemul are un singur microprocesor nu se poate folosi decât multitaskingul

secvenţial. În această manieră de lucru, diferitele sarcini îşi împart între ele memoria disponibilă în sistem dar capătă pe rând accesul la microprocesorul unic. Aceasta înseamnă că, la un moment dat, numai o singură sarcină (aplicaţie) este activă, celelalte fiind suspendate (înregistrate în memoria disponibilă) în starea în care se găseau când a survenit ordinul de suspendare.

Dacă sistemul are mai multe procesoare, se pot desfăşura concomitent un număr de sarcini cel mult egal cu numărul de procesoare, rezultând un multitasking simultan sau paralel.

Cu rare excepţii, pentru nevoile utilizatorului obişnuit, multitaskingul secvenţial este suficient, în ultimul timp el fiind îmbunătăţit cu unele perfecţionări legate de lucrul în subteran (background) care desfăşoară automat unele activităţi de transfer de date la periferice de ieşire (imprimantă sau plotter), activităţi care nu necesită intervenţie şi care pot folosi pauzele de acţiune ale utilizatorului. Astfel, deşi secvenţial, multitaskingul poate părea – la nivelul de precepţie temporală al utilizatorului – că ar fi paralel.

§5.3. Mediul obiectual 5.3.1. Tehnica de programare orientată pe obiect La începutul anilor 1970 în proiectarea aplicaţiilor pe calculator a intervenit o criză majoră.

Ea s-a datorat creşterii spectaculoase a mărimii şi complexităţii programelor şi, în consecinţă, a volumului de muncă necesar care nu mai putea fi acoperit de o singură persoană şi ridica probleme foarte mari de organizare a muncii în echipă.

O primă rezolvare a acestei crize a fost efectuată prin crearea disciplinei de inginerie a programării şi prin introducerea conceptului de programare structurată.

În programarea structurată se afirmă şi se demonstrează că orice aplicaţie poate fi programată folosind numai trei structuri de control fundamentale, şi anume:

- Structura secvenţială (blocul de instrucţiuni), figura 5.3.1; - Structura alternativă cu două ramuri (blocul if), figura 5.3.2; - Structura repetitivă condiţionată anterior (blocul while), figura 5.3.3.

Fig.5.3.1.

Un program scris numai cu acest gen de instrucţiuni se numeşte program D-structurat, litera D provenind de la Dijkstra, cel care a introdus conceptul de programare structurată.

Deşi aceasta a însemnat o revoluţie în programare, şi a rezolvat problema organizării eficiente a lucrului în înteriorul echipei de programatori, ea nu a rezolvat problema comunicaţiei dintre analist şi programatori.

Page 125: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 113

În tehnica de programare structurată analistul preia cererile clientului şi identifică funcţiile îndeplinite de modulele de program, iar programatorii implementează modulele funcţionale astfel identificate folosind un limbaj de programare adecvat. Dezavantajul acestei maniere de lucru este acela că, dacă este exprimată o cerere de modificare a unor funcţii îndeplinite de modulele de program, efortul de modificare a programelor poate fi apreciabil.

Fig.5.3.2. Fig.5.3.3.

Această tehnică de scriere a programelor a fost proprie sistemului de operare DOS şi este încă utilizată la dezvoltarea unor porţiuni de programe în WINDOWS.

Tehnica de programare orientată pe obiecte introduce un concept nou şi anume obiectul.

Un obiect este un modul de program care simulează un obiect din lumea reală.

Obiectul, figura 5.3.4, are un set de atribute care îl caracterizează şi care sunt stocate într-un stoc de "date" proprii.

date

metode

mesaje

Fig.5.3.4.

De asemenea, obiectul are un mod propriu de prelucrare a datelor, mod bazat pe o bază de "metode" proprii constând din procedurile program incluse în structura lui.

În plus, obiectul comunică cu sistemul de operare prin "mesaje" pe care le primeşte de la sistem sau pe care le emite către sistem. Prin aceasta obiectul ia cunoştinţă de evenimentele survenite în sistem sau înştiinţează sistemul cu privire la evenimentele survenite în interiorul său, aşa cum se vede în figura 5.3.5.

Starea la un moment dat a datelor obiectului constituie proprietăţile lui iar modul cum obiectul tratează datele pe care le conţine constituie metodele obiectului.

Prin această tehnică de lucru analistul, după ce ia cunoştinţă de cerinţele clientului, adică defineşte "universul problemei", identifică "obiectele" din acest univers, "proprietăţile" obiectelor şi stabileşte un comportament adecvat al obiectelor, adică "evenimentele" din exteriorul şi interiorul obiectelor, "mesajele" prin care obiectele comunică şi "metodele" de care obiectele trebuie să facă uz pentru tratarea proprietăţilor lor ca răspuns la mesaje externe.

Mai departe, programatorii preiau această descriere şi o implementează folosind tehnicile de programare structurată numei în interiorul obiectelor, pentru exteriorul lor respectând conceptul şi tehnicile de programare orientată spre obiecte.

În acest fel, modificarea unei funcţii, cerută de client, nu mai afectează decât obiectul care posedă funcţia respectivă şi nu întregul univers al problemei.

Din punctul de vedere al utilizatorului simplu, problema nu apare prea complicată, deoarece el nu trebuie decât să manevreze corect obiectele grafice existente în câmpul său de lucru.

Page 126: Programarea Calculatoarelor si Limbaje de Programare

Cap.5. Elemente de operabilitate sub Windows 114

Fig. 5.3.5.

Pentru utilizatorul avansat care doreşte să scrie programe care fac uz de entităţi grafice care reprezintă obiecte din universul problemei, nu este necesară cunoaşterea mecanismelor interne de lucru ale obiectului ci numai denumirile proprietăţilor şi metodelor obiectului. Acestea, sunt de regulă accesibile prin intermediul unor limbaje de programare orientate spre obiecte, implementate în mediile de dezvoltare de aplicaţii incluse în programele aplicative moderne. Astfel, MicroSoft pune la dispoziţia utilizatorilor de produse din pachetul Office un dialect de Visual BASIC comun tuturor aplicaţiilor din acest pachet, fiecare program din pachet având diferite numai obiectele specifice aplicaţiei.

Apelul proprietăţilor şi metodelor obiectelor grafice se face folosind apelative a căror denumire apare de forma obiect.proprietate şi, respectiv, obiect.metodă.

Obiectele la rândul lor se pot clasifica în obiecte recipient şi obiecte conţinute, un obiect conţinut putând să fie, la rândul său, obiect recipient pentru alte obiecte.

Evenimente şi mesaje Un eveniment este o schimbare a stării sistemului. De exemplu: - mutarea pe ecran a unei ferestre; - închiderea unei ferestre; - acţionarea unui meniu; - apăsarea unei taste; - mişcarea mouse-ului; - apăsarea unui buton al mouse-ului; - etc. Când are loc un eveniment, este emis un mesaj. Mesajul este un tip de dată special care

este generată de către obiectul asociat cu evenimentul produs. Mesajul este receptat mai întâi de către sistem care îl plasează într-o structură de date

denumită "coadă de mesaje". Plasarea în coada de mesaje poate fi normală sau prioritară (mesajul sare peste rând).

Page 127: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 115

Sistemul preia mesajele din coadă în ordinea plasării lor, le analizează şi le transmite mai departe obiectelor cărora le sunt destinate. Acestea le tratează conform semnificaţiei lor, generând efecte sau alte evenimente.

Interacţiunea obiectelor O dată cu lansarea platformelor WINDOWS, s-a generalizat tehnica utilizării obiectelor. Deoarece sistemul de operare WINDOWS este un sistem de interfaţare grafică cu

utilizatorul (GUI – Graphic User Interface), toate elementele unei aplicaţii au un corespondent grafic în fereastra de lucru. Aceste entităţi grafice sunt obiecte care interacţionează aparent cu utilizatorul prezent în mediul de lucru şi cu sistemul de operare care supraveghează desfăşurarea întregului proces de interacţiune, ca în figura 17, proces dependent de caracterul universului problemei şi de configuraţia mediului de lucru.

Mediul de lucru este complexul constituit din dispozitivele periferice prin care utilizatorul interacţionează cu universul problemei, modulele de program care deservesc aceste periferice şi programul aplicativ care solicită accesul la resursele sistemului.

În acest complex de componente, mediul de lucru generează evenimente pe care un anumit obiect care este subiectul unui astfel de eveniment le transformă în mesaje pe care le transmite sistemului de operare. La nivelul sistemului de operare, mesajele se dispun într-o coadă de mesaje, în ordinea sosirii lor. Un analizor de mesaje asigură gestiunea cozii de mesaje transmiţându-le sistemului în ordinea lor normală. Unele dintre evenimente sunt prioritare (de exemplu un clic pe fereastra altei aplicaţii în vederea transferului controlului la aceasta este un eveniment care, în funcţie de tipul aplicaţiilor concurente, poate genera un mesaj prioritar). Astfel de mesaje sar peste rând fiind trimise de către analizorul de mesaje imediat către blocul de tratare a mesajelor. De aici, mesajele sunt interpretate de către sistem şi, dacă ele conţin cereri de natură să fie rezolvate de către sistem, sunt îndeplinite de către acesta. Dacă mesajele se adresează altor obiecte, sunt direcţionate către obiectele destinaţie.

O dată ajunse la obiectul destinaţie, mesajele generează acţiuni care acţionează asupra mediului de lucru, producând din partea acestuia reacţii care constituie alte evenimente.

Astfel, în mod indirect, sub controlul sistemului de operare, obiectele comunică între ele şi colaborează la îndeplinirea unor sarcini complexe.

§5.4. Mediu de programare După cum s-a văzut din capitolele anterioare, pentru a se realiza un program trebuie

parcurse anumite etape în funcţie de procedeul de realizare folosit, compilator sau interpretor. Acestor etape le corespund programe utilitare sau module de program utilitare, specializate. Corespunzător celor două procedee de realizare a programelor, programele utilitare

necesare sunt următoarele: A. Pentru procedeul compilator, figura 5.4.1: - Editorul de text, este necesar pentru scrierea şi, eventual, modificarea programului sursă; - Compilatorul, este necesar pentru traducerea programului sursă în coduri binare

reprezentând instrucţiuni în limbaj maşină; - Editorul de legături, necesar pentru efectuarea legăturilor între modulele care vor

compune programul complet; - Depanatorul, necesar pentru analiza erorilor de diferite tipuri. B. Pentru procedeul interpretor, figura 5.4.2: - Editorul de text, necesar pentru scrierea şi modificarea programelor sursă; - Interpretorul, care efectuează funcţiile de compilare, legare, depanare şi execuţie la

nivelul unei singure instrucţiuni.

Page 128: Programarea Calculatoarelor si Limbaje de Programare

Cap.5. Elemente de operabilitate sub Windows 116

Editor de text

Compilator

Editor de legături

Execuţie sub sistemul deoperare

Depanator

Editor de text

Interpretor

Execuţie sub interpretor

Fig.5.4.1. Programe necesare Fig.5.4.2. Programe necesare la procedeul compilator la procedeul interpretor

5.4.1. Medii de programare integrate, medii integrate de dezvoltare a aplicaţiilor În fazele timpurii ale evoluţiei tehnicilor de programare, programele utilitare descrise mai

sus apăreau ca programe de sine stătătoare. Încă şi astăzi, anumite etape (cel mai adesea etapa de editare de text) pot fi executate separat.

În prezent, programele utilitare concurente la realizarea unui program sunt integrate într-un produs unic, trecerea de la o etapă la alta, înainte şi înapoi, făcându-se cu uşurinţă maximă, fapt cu influenţe benefice majore asupra productivităţii muncii programatorului.

Acest tip de produs integrat poartă denumirea de mediu de programare integrat. Un caz deosebit, caracteristic în special interpretoarelor, este cazul în care mediul de

programare integrat, este implementat într-o aplicaţie particulară. Acesta este cazul mediilor integrate de dezvoltare a aplicaţiilor.

Un exemplu foarte popular este acela al limbajului Visual BASIC din MicroSoft Office, folosibil atât în WORD cât şi în EXCEL. De asemenea, începând din anul 2000, firma AutoDesk a implementat acest limbaj şi în produsul AutoCAD destinat proiectării asistate de calculator, aliniindu-se la o tendinţă existentă încă din anii anteriori la alte produse program specializate care foloseau implementări similare ale unor versiuni proprii de Visual BASIC (de exemplu firma Bentley cu produsul Micro Station, tot pentru proiectare asistată de calculator).

Prin implementarea unui limbaj într-o aplicaţie se urmăreşte să se pună la dispoziţia utilizatorului un instrument de lărgire practic nelimitată a posibilităţilor existente ale aplicaţiei.

Astfel, se pot crea comenzi noi, meniuri şi cutii de dialog noi conectate la comenzile nou create de către utilizator.

Pe această cale aplicaţia iniţială capătă posibilităţi noi şi, într-o anumită măsură chiar un nou aspect, servind mai bine necesităţile utilizatorului. Este chiar posibilă crearea de aplicaţii noi, de sine stătătoare, rulabile de sub aplicaţia mamă astfel îmbogăţită.

Page 129: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 117

În sinteză, un mediu integrat de dezvoltare a aplicaţiilor este compus din: - O aplicaţie suport. De exemplu: WORD, EXCEL, COREL DRAW, AutoCAD,

MicroStation: - Un limbaj implementat (de regulă un interpretor). De exemplu: MicroSoft Visual BASIC,

MicroStation BASIC, AutoLISP, AutoCAD Script, COREL Script; - Un editor de text; - Un editor de resurse (cutii de dialog, meniuri); - Facilităţi de depanare. Editoare de text utilizabile pentru mediile de programare Deşi este din ce în ce mai rar cazul când o aplicaţie care are integrat un interpretor de

limbaj de programare, nu are implementat şi un editor de text, pot exista situaţii când, din diferite motive, utilizatorul nu doreşte să lanseze în lucru mediul integrat de dezvoltare a aplicaţiilor (sau nu îl are instalat pe calculatorul pe care lucrează în acel moment), ci doreşte numai să facă o modificare în textul programului sursă, restul prelucrării fiind amânat pentru mai târziu.

Într-o atare situaţie el poate folosi un editor de text de sine stătător (extern), neintegrat. Totuşi, la alegerea editorului potrivit trebuie avută în vedere următoarea condiţie:

Fişierele rezultate trebuie să conţină numai caractere ASCII tipăribile, nu şi alte caractere care nu pot fi înţelese de traducătorul de limbaj (compilator sau interpretor).

Exemple de editoare de text potrivite: EDIT, QEDIT, NOTEPAD. Exemple de editoare de text nepotrivite: WORDPAD, WORD. Obs.: chiar şi aceste din urmă editoare pot fi folosite la editarea programelor sursă, cu

condiţia de a nu se folosi caractere netipăribile (tasta TAB, atribuiri de caracteristici de format ca sublinierea îngroşarea, colorarea, etc) şi de a se alege la salvare ca tip de fişier tipul TXT.

În cazul integrării într-un mediu de dezvoltare de aplicaţii, un editor de text integrat trebuie

să realizeze următoarele funcţii: 1. Generarea fişierului rezultat strict sub forma text (aceeaşi condiţie ca mai sus); 2. Structurarea automată a textului sursă. La această funcţie contribuie setul de reguli

sintactice recunoscute de compilator (sau interpretor). Practic, este efectuată o preanaliză sintactică a textului sursă. În urma acestei preanalize se obşin următoarele efecte:

- cuvintele cheie ale limbajului, denumirile tipurilor de variabile standard sau definite de utilizator, sunt evidenţiate prin scrierea cu culori diferite de restul textului;

- la trecerea la o nouă linie se efectuează o decalare a începutului de rând în funcţie de apartenenţa la un bloc de structură predefinită (linie interioară unei funcţii sau subrutine, linie interioară unei structuri logice (if) sau repetitive (for, while, until).

5.4.2. Elaborarea unui program în limbaj C într-un mediu de programare integrat Limbajul C este un limbaj pentru lucrul prin procedeul compilator. La ora actuală este un

limbaj foarte răspândit. Existent în diferite versiuni ca mediu de programare de sine stătător, el se află chiar inclus în anumite medii integrate de dezvoltare din unele aplicaţii.

Dată fiind, deci, răspândirea lui, se cuvine să prezentăm câteva elemente privind concepţia lui şi modul său de folosire.

Limbajul C are trei avantaje principale, şi anume: - este un limbaj de programare cu destinaţie generală. Cu ajutorul lui se pot construi orice

fel de programe, de la editoare de text şi programe de calcul matematic, până la jocuri dintre cele mai complexe;

- este un limbaj structurat. Limbajul C posedă capabilităţi de structurare completă ceea ce

Page 130: Programarea Calculatoarelor si Limbaje de Programare

Cap.5. Elemente de operabilitate sub Windows 118

conferă programelor o mare robusteţe şi uşurinţa modificării; - este un limbaj standardizat. Aceasta face ca în cea mai mare parte din cazuri, cu foarte

mici modificări sau fără nici o modificare, un program în C scris pe o anumită maşină să poată fi compilat pe o alta.

Etapele de lucru pentru elaborarea programului sunt: - După lansarea programului compilator, se scrie textul sursă. Editorul de text este inclus în

mediul de programare şi nu necesită accesare separată. Practic, programatorul se găseşte tot timpul în editorul de text;

- Înainte de a se trece la următoarele etape, pentru a nu se pierde programul sursă ca urmare a unei erori de execuţie care ar conduce la blocarea compilatorului (se poate întâmpla oricând din diferite motive, legate mai ales de o concepţie defectuoasă a programului), se salvează fişierul sursă. Se va alege un director de depozitare a fişierului program sursă şi i se va atribui un nume. Numele trebuie urmat de extensia C sau CPP după cum este vorba de folosirea limbajului C standard sau a versiunii sale extinse, şi anume C++.

- Următoarea etapă este cea de compilare. Aceasta produce fişierul cod obiect relocabil. În această fază are loc depistarea erorilor de sintaxă şi de definire. Compilatorul nu va

raporta îndeplinirea sarcinii de compilare dacât atunci când toate erorile vor fi fost eliminate. Dacă apar erori, acestea sunt raportate într-o fereastră de mesaje.

- În cazul unei lucrări mai complexe, pentru crearea unui program din mai multe module, se foloseşte un fişier proiect (nume.PRJ sau nume.IDE) care conţine indicaţiile privind componenţa lucrării.

- Următoarea etapă este cea de legare a modulelor componente ale proiectului sau a modulului curent cu modulele invocate din biblioteci, invocare explicită sau implicită prin referinţele văzute de compilator.

- O etapă folosită adesea de programatorii profesionişti este aceea de depanare folosind un program de depanare integrat în mediu (Debuger).

- Ultima etapă este cea de rulare (Run), etapă care se poate efectua fie din mediu, fie din afara lui dacă programul a fost pus la punct.

- Am putea folosi de la început comanda Run dar nu este indicat, deoarece încă nu am eliminat erorile şi ne expunem pericolului unei căderi a programului compilator din cauza erorilor neeliminate.

O serie de erori greu detectabile sunt cele de execuţie, cauzate de vicii de concepţie. Aceste erori nu sunt de tip sintactic, nici de definire, şi nu sunt detactabile în faza de compilare. Ele nu se manifestă decât la execuţie şi pot cauza efecte nedorite dintre cele mai diverse, de la simple rezultate eronate până la căderi ale sistemului. De aceea, dacă se doresc informaţii suplimentare privitoare la desfăşurarea execuţiei programului, trebuie folosit meniul Debug, de unde se pot impune anumite condiţii de execuţie graduală şi se pot inspecta valorile şi stările variabilelor în cursul execuţiei.

Nu mai insistăm asupra detaliilor de operare cu compilatorul de C deoarece aceasta face obiectul unui curs distinct, de specialitate. În plus, diferite firme producătoare de astfel de compilatoare, oferă produse cu diferite configuraţii şi un studiu amănunţit al unui asemenea produs este util numai unui programator profesionist.

Page 131: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 119

Cap. 6. Mediul Visual BASIC pentru EXCEL §6.1. Generalităţi Mediul Visual BASIC este un sistem operaţional complex destinat dezvoltării aplicaţiilor

cu interfaţare grafică, şi este compus, în principal, din următoarele elemente: - un program supervizor al aplicaţiei, care are rolul de a asigura funcţionarea corectă a

modulelor de aplicaţie şi a resurselor aplicaţiei; - o serie de module de program, concepute ca obiecte care primesc, prelucrează şi transmit

"mesaje" către alte obiecte, mesaje care constituie un mediu de comunicare între obiecte şi supervizorul de aplicaţie în cadrul sarcinilor de prelucrarea a datelor în cuprinsul aplicaţiei;

- un set de resurse comune, constituite din obiecte de interacţiune grafică (cutii de dialog, butoane, meniuri, etc) şi care au rolul de a asigura interfaţarea naturală a dialogului dintre utilizator şi aplicaţie.

Limbajul folosit este un dialect al limbajului BASIC destinat nespecialiştilor în informatică şi adaptat sarcinilor programării aşa zis "vizuale" a aplicaţiilor sub WINDOWS. Termenul de programare vizuală se referă în special la programarea interfaţării grafice când, în loc de a scrie descrieri complicate ale resurselor grafice, ele sunt definite prin operaţii de tipul priveşte-alege-apucă şi pune.

În cele ce urmează vor fi discutate acele probleme care particularizează limbajul Visual BASIC folosit sub EXCEL ca supervizor de aplicaţie, de limbajul BASIC obişnuit, care este mai mult sau mai puţin cunoscut.

§6.2. Obiecte şi colecţii

Fig.6.2.1.

Saltul major realizat de dialectele de Visual BASIC actuale este acela de a fi gândit ca un

limbaj de programare orientată pe obiecte. Aceasta face din el un concurent serios pentru mediile de dezvoltare de aplicaţii care permit dezvoltarea aplicaţiilor fie în Visual Basic, fie în C++. Adeseori, şi în special utilizatorii cu mai puţine, sau de loc, cunoştinţe de programare avansată, ceea ce este cazul majorităţii, preferă limbajul visual BASIC, mai ales dacă aplicaţia nu este critică sub aspectul vitezei de lucru.

Page 132: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 120

În EXCEL, se defineşte ca obiect orice entitate controlabilă prin limbajul Visual BASIC. Orice element constitutiv al mediului EXCEL este un obiect. De asemenea, orice construcţie care foloseşte elemente EXCEL poate deveni un obiect.

Definirea obiectelor se face prin intermediul limbajului Visual BASIC iar manevrarea lor se face prin intermediul procedurilor din Visual BASIC.

Obiectele EXCEL sunt grupate într-o ierarhie, structurată în recipiente şi colecţii. Un recipient este un obiect care conţine alte obiecte. O colecţie este o grupare de obiecte de acelaşi tip. O metacolecţie este o grupare de obiecte de mai mult decât un singur tip, aşa cum sunt

obiectele desenate (DrawingObjects). De exemplu, structura generală a obiectelor din EXCEL este cea din figura 6.2.1. 6.2.1. Utilizarea obiectelor Obiectele se caracterizează prin: - proprietăţi, care descriu aspectul, starea sau comportarea lor. De exemplu, pentru

obiectul Workbook, câteva dintre cele mai semnificative proprietăţi sunt: = Name, indicând numele documentului; = Precision As Displayed, indicând modul de considerare a preciziei calculelor

conform modului de afişare a valorilor numerice în celule; = Read Only, indicând protecţia documentului împotriva modificărilor; = Saved, indicând starea de salvare a documentului, etc.

- metode, care reprezintă acţiunile pe care obiectele le pot efectua. De exemplu, pentru obiectul Worksheet, sunt disponibile o serie de acţiuni printre care se află:

= Activate, reprezentând acţiunea de activare a unei foi de lucru; = Copy, reprezentând acţiunea de a copia o întreagă foaie de lucru; = Move, reprezentând acţiunea de a muta o foaie de lucru în altă poziţie în

succesiunea foilor; = Protect, reprezentând acţiunea de a proteja o foaie de lucru împotriva modificării; = Select, reprezentând acţiunea de a selecta o foaie de lucru în vederea unor operaţii

ulterioare, etc.

6.2.2. Variabile obiect O variabilă obiect este o variabilă asociată unui anumit tip (sau clasă) de obiect şi care adresează un

obiect EXCEL anumit. Pentru a fi folosită, o variabilă obiect trebuie mai întâi să se facă declararea folosind una din instrucţiunile Dim, Public, Private, Static sau ReDim şi precizând obiectul asociat.

Folosind instrucţiunea Dim, un obiect poate fi declarat în trei moduri: Dim nume_obiect declară variabila nume_obiect de tipul Variant, cel mai general tip de

dată din EXCEL, tip care poate fi şi un obiect; Dim nume_obiect As Object declară variabila nume_obiect de tipul Object, adică

obiect general care, ulterior poate particulariza orice obiect real; Dim nume_obiect As obiect_concret declară explicit variabila nume_obiect ca obiect

de un anumit tip. De exemplu: Dim ObiectA As Object, ObiectB As Object declară variabilele ObiectA şi ObiectB ca

fiind de tipul general Object, iar Dim domeniuA As Range declară variabila domeniuA ca având tipul domeniu de celule. O variabilă obiect trebuie să refere un obiect existent. Asocierea variabilei cu obiectul

referit se face prin instrucţiunea Set, cu sintaxa: Set nume_obiect = expresie_obiect sau:

Page 133: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 121

Set nume_obiect = nothing Prima variantă produce asocierea variabilei cu obiectul referit de expresie_obiect.

Expresie _obiect constă din numele unui obiect, o altă variabilă obiect de acelaşi tip, o funcţie (sau metodă) care returnează un obiect de tipul specificat.

A doua variantă produce desfacerea referinţei stabilite anterior.

6.2.3. Proprietăţi care reprezintă obiecte Proprietăţile care reprezintă obiecte nu sunt caracteristici ale unor obiecte, ci sunt referinţe

ale obiectului către alte obiecte care deţin proprietăţi. Iată câteva exemple:

Proprietate Adresează

Application Aplicaţia care a creat obiectul ActiveCell Celula activă ActiveChart Diagrama activă ActiveDialog Foaia de dialog în lucru ActiveSheet Foaia de lucru activă ActiveWindow Fereastra activă ActiveWorkbook Mapa (documentul Excel) activă Next Foaia sau celula următoare Parent Obiectul părinte al obiectului specificat Previous Foaia sau celula anterioară ThisWorkbook Mapa în care se execută procedura curentă De exemplu, procedura:

Sub Nume_foaie() Dim celula As Range Set celula = Worksheets("Sheet1").Range("A1") celula.Value = ActiveSheet.Name End Sub va afişa în celula A1 din foaia de lucru Sheet1 numele foii de lucru active în momentul execuţiei procedurii.

6.2.4. Adresarea obiectelor Pentru adresarea obiectelor, Visual BASIC permite utilizarea a trei sintaxe: identificator![nume_obiect] identificator("nume_obiect") identificator(indice) unde: identificator poate fi numele colecţiei care conţine obiectul, sau numele unui

obiect a cărui colecţie implicită conţine obiectul; nume_obiect este numele obiectului adresat (eventual în forma şir) indice este numărul de ordine al obiectului vizat, în colecţia din care face

parte. Astfel, de exemplu, dacă în procedura de mai sus se înlocuieşte ultima instrucţiune cu celula.Value = Application.Worksheets(2).Name în celula A1 din foaia de lucru Sheet1 va fi afişat numele celei de a doua foi de lucru din

document.

Page 134: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 122

6.2.5. Folosirea sau manipularea proprietăţilor obiectelor Pentru a folosi sau manipula o proprietate a unui obiect se pot efectua următoarele operaţii: - Atribuirea unei valori către o proprietate (operaţie de scriere). Sintaxa atribuirii este: obiect.proprietate=expresie unde: obiect este o referinţă către un obiect, eventual incluzând recipienţii săi;

proprietate este numele proprietăţii obiectului căreia i se atribuie o valoare expresie este un enunţ care generează valoarea de atribuit.

De exemplu, procedura:

Sub Coloreaza() ActiveWorkbook.Worksheets(1).Cells(1, 5).Interior.ColorIndex = 3 End Sub va produce colorarea în roşu a celului E1 (rândul 1 coloana 5) din prima foaie a documentului.

- Preluarea unei valori a unei proprietăţi (operaţie de citire) se realizează cu sintaxa: variabilă=obiect.proprietate unde variabilă este numele variabilei carea preia valoarea proprietăţii obiectului. Exemplul anterior ar putea fi rescris ca:

Sub Coloreaza() culoare=ActiveWorkbook.Worksheets(1).Cells(1, _

5).Interior.ColorIndex ActiveWorkbook.Worksheets(1).Cells(2, _

5).Interior.ColorIndex=culoare End Sub şi, în acest caz, celula E2, ce de sub E1, va primi culoarea preluată de variabila culoare de la proprietatea ColorIndex a obiectului interior de celulă E1.

Observaţie: deşi, în general sunt posibile ambele tipuri de operaţii totuşi, proprietăţile anumitor obiecte sunt de tipul read-only (citibile numai) astfel încât asupra acestor proprietăţi se pot efectua numai acţiuni de citire.

6.2.6. Activarea obiectelor În afară de proprietăţi, obiectele posedă metode. Metodele reprezintă modul în care

informaţia este tratată de obiecte, sau acţiunile pe care aceste ale pot efectua şi în urma cărora proprietăţile obiectelor sunt afectate.

Din punct de vedere formal, spre deosebire de proprietăţi care pot căpăta o singură valoare, metodele pot primi mai multe argumente, deoarece ele sunt de fapt funcţii. Pot fi întâlnite următoarele situaţii, aceleaşi ca şi la apelul unei funcţii oarecare:

a. Metoda nu primeşte nici un argument. În acest caz se foloseşte sintaxa: obiect.metodă De exemplu, instrucţiunea: Application.Worksheets("Sheet1").Range("1:1").Delete va şterge conţinutul întregului rând 1. b. Metoda primeşte o listă de argumente, dar valoarea returnată de metodă nu trebuie

salvată. În acest caz sintaxa este: obiect.metodă lista_de_argumente c. Dacă valoarea returnată de metodă trebuie salvată, transmiterea argumentelor se face cu

sintaxa: obiect.metodă(lista_de_argumente) unde: obiect este numele obiectului a cărei metodă se foloseşte (eventual incluzând

şi numele recipienţilor);

Page 135: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 123

metodă este numele metodei folosite; lista_de_argumente este lista de argumente separate între ele prin caracterul separator de listă

afişat în pagina Module General din cutia de dialog a comenzii Options din meniul Tools. Acesta este de obicei virgula, atunci când ordinea enumerării argumentelor este importantă. De exemplu:

Worksheets("Sheet1").Move(Worksheets("Sheet3")) reprezintă versiunea incompletă a apelării metodei obiect.Move(before, after), unde argumentul

after a fost omis dar, în acest caz, unicul argument furnizat este interpretat ca fiind argumentul before. De aceea, efectul apelului este de a muta foaia Sheet1 în faţa foii Sheet3.

Dacă ordinea argumentelor nu contează, trebuie folosită metoda transmiterii argumentelor denumite. În acest caz, apelul:

Worksheets("Sheet1").Move after:=Worksheets("Sheet3") foloseşte operatorul de asignare := pentru a specifica foaia Sheet3 drept argument after. În

acest caz, foaia Sheet1 va fi mutată după foaia Sheet3.

§6.3. Tipuri de date Tipurile de date recunoscute de Visual BASIC sunt următoarele:

Tip de date Identificator Memorie Domeniu de valori logic Boolean 2 octeţi True sau False întreg Integer 2 octeţi -32768...32767 întreg lung Long 4 octeţi -2147483648... 2147483647 real simplă precizie Single 4 octeţi -3.402823E38...-1.401298E-45 (val. negative) 1.401298E-45... 3.402823E38 (val. pozitive) real dublă precizie Double 8 octeţi -1.79769313486232E308...-

4.94065645841247E-324 (valori negative) 4.94065645841247E-324...

1.79769313486232E308 (valori pozitive) monetar Currency 8 octeţi -922337203685477.5808...

922337203685477.5807 dată calendaristică Date 8 octeţi 1 Ianuarie 100...31 Decembrie 9999 Şir de caractere String 1 octet/caracter 0...~2000000000 În afară de aceste tipuri, mai sunt recunoscute următoarele tipuri speciale: Tip de date Identificator Memorie Domeniu de valori

Obiect Object 4 octeţi Orice referinţă la un obiect Oricare Variant 16 octeţi + 1

octet/caracter Orice valoare numerică sau text

Definit de utilizator

Conform definiţiei

numărul de octeţi cerut de

elemente

Domeniul fiecărui element component

Tablou Conform definiţiei

cât este necesar Fără restricţii asupra numărului de elemente

§6.4. Constante şi variabile 6.4.1.Constante Constantele reprezintă valori care nu se pot modifica în timpul execuţiei şi sunt de două tipuri: - constante native sau predefinite în Visual BASIC. Ele se folosesc în legătură cu

Page 136: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 124

obiectele EXCEL şi pot fi reconoscute prin prefixele xl, vb sau db ataşate numelui lor. De exemplu: vbOK, vbCancel, vbNo,...etc.

- constante definite de utilizator, cu sintaxa: [Public | Private] Const NUME_CONSTANTA [As nume_tip] = expresie unde: Public sau Private determină domeniul de vizibilitate al constantei. În mod

implicit domeniul de vizibilitate al constantelor este Private; Const este cuvântul cheie pentru declararea unei constante; NUME_CONSTANTA este identificatorul constantei. El se formează, ca orice

nume de variabilă, conform convenţiilor Visual BASIC-ului (a se vedea mai jos) dar, prin convenţie, se scrie cu majuscule;

nume_tip este declaratorul de tip şi este opţional; expresie este o expresie aritmetică sau logică a cărei valoare este atribuită

constantei. Ea nu poate conţine variabile, funcţii, sau operatorii Is sau &. Observaţie: constantele definite în proceduri sunt locale, adică au vizibilitate numai în

interiorul procedurilor unde sunt definite. Exemple de declaraţii de constante:

Const ZECE As Integer = 10 Const ENAT As Single = 2.7182 Const NUME As String = "Geta"

6.4.2. Variabile Variabilele sunt acele valori care pot fi modificate în timpul execuţiei. Ele se declară cu

sintaxa: [Public | Private | Static | Dim] nume_variabila [As nume_tip][,...] unde: Public sau Private determină domeniul de vizibilitate al variabilelor; Static se referă la durata de viaţă a variabilelor; Dim se foloseşte pentru definirea variabilei si alocarea spaţiului de stocare.

Dim este în special folosit pentru tablouri; nume_tip este unul din numele de tipuri de date prezentate mai înainte. Dacă

nume_tip este omis, tipul atribuit implicit este Variant; nume_variabila trebuie scris conform următoarelor reguli valabile în Visual

BASIC: - primul caracter trebuie să fie o literă; - numele trebuie să conţină numai litere, cifre şi caracterul de subliniere "_"; - nu se admit caractere de punctuaţie sau spaţii; - nu se face distincţie între majuscule sau litere mici; - lungimea maximă a numelui este de 255 de caractere; - ca nume nu pot fi folosite cuvinte cheie ale limbajului Visual BASIC; - numele trebuie să fie unice.

Exemple de declaraţii de variabile: Dim ValoareA, ValoareB ' ValoareA şi ValoareB sunt declarate ca fiind implicit

' de tipul Variant şi sunt iniţializate cu valoarea Empty Dim Indice As Integer ' Indice este declarat ca întreg Dim NumReal As Single ' NumReal este declarat ca număr de tip real simplă

' precizie În cazul variabilelor de tip şir declaraţia implicită este: Dim SirCar As String ceea ce comunică interpretorului de Visual BASIC să deschidă o zonă de memorie cu

lungime variabilă dinamic, pentru stocarea şirului.

Page 137: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 125

Dacă se doreşte ca spaţiul de memorie alocată să aibă lungime fixă, de exemplu de 30 de caractere, explicitarea lungimii se face cu sintaxa:

Dim SirCar As String * 30 Observaţie: Într-o instrucţiune Public, Private, Static sau Dim se pot declara mai multe

variabile, fiecare dintre ele putând fi de alt tip, declaraţiile succesive fiind separate prin virgule. De exemplu:

Dim NumarPuncte As Integer, NumeCurba As String, Linearitate As Boolean Se pot folosi şi nume de variabile nedeclarate, dar acest lucru poate produce erori greu de controlat. Pentru a interzice folosirea unor nume de variabile nedeclarate se foloseşte instrucţiunea

Option Explicit, plasată în zona pentru declaraţii a modulului de programe. Pentru variabilele tablou declararea se face astfel: [Public | Private | Static | Dim] nume_variabila ([[indice_initial1 To] indice_final1[,... ...[,[indice_ initial j To] indice_ final j]...]) [As nume_tip][,...]

unde: indice_ initialj, j=1...n, este valoarea de început a indicilor elementelor tabloului pentru dimensiunea j;

indice_ finalj, j=1...n, este valoarea de sfârşit a indicilor elementelor tabloului pentru dimensiunea j.

Visual BASIC acceptă tablouri cu maxim 60 de dimensiuni. Valoarea implicită pentru indice_ initial este 0. Ea poate fi modificată la nivel de modul

folosind instrucţiunea Option Base 0 sau Option Base 1. nume_tip este numele tipului atribuit datelor tabloului. Dacă este omis, se atribuie tipul

Variant. Observaţie: Visual BASIC acceptă, pentru elementele unui tablou, şi indici negativi. Exemple de declarare a tablourilor:

Dim TablouA(40) ' TablouA este de tipul Variant cu 41 de elemente indexate de la ' 0 la 40

Dim TablouB(2,5) As Integer' TablouB este de tip întreg, cu două dimensiuni, ' cu indicii iniţiali implicit egali cu 0

Dim TablouC(1 To 10, 6 To 15, 11 To 20) As Double ' TablouC este de tip real dublă precizie cu 3 dimensiuni, cu indici între limite ' explicitate

Dacă dimensiunea tabloului nu poate fi precizată de la început, el poate fi declarat dinamic, cu sintaxa:

Dim Nume_tablou() [As nume_tip] Se observă că nu a fost specificată lungimea tabloului. Un tablou dinamic poate fi redimensionat în timpul execuţiei programului, cu sintaxa: ReDim [Preserve] nume_tablou ([indice_initial1 To] indice_final1 [,...]) [As

nume_tip][,...] De exemplu: ReDim TabDinamic(10) As Object La fiecare folosire a instrucţiunii ReDim, elementele tabloului suferă o reiniţializare cu

valoarea Empty pentru tipul Variant, 0 pentru tipul numeric, şirul nul "" pentru tipul şir de caractere de lungime variabilă, zerouri pentru tipul şir de caractere de lungime fixă, şi Nothing pentru tipul Object.

Acelaşi lucru se întâmplă şi în cazul variabilelor simple declarate cu Public, Private, Static sau Dim.

Dacă se doreşte ca redimensionarea tabloului dinamic să lase nealterate valorile anterioare, trebuie folosit cuvântul cheie Preserve.

Page 138: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 126

De exemplu: Redim Preserve TabDinamic(15) As Object va păstra valorile anterioare ale tabloului, adăugând la ele alte 5 noi elemente iniţializate cu

valoarea Nothing. Variabilele Variant, sunt variabilele cu tipul cel mai general. Dacă, la declarare, unei

variabile nu i se specifică tipul, ea capătă automat tipul Variant. Tipul Variant poate memora orice alt tip de date (cu excepţia tipurilor de date definite de

utilizator). Tipul efectiv al unei variabile variant este tipul ultimei valori atribuite. Variabila de tip Variant poate memora şi tipurile de informaţii speciale, ca: - valoarea Empty - semnificând valoarea unei variabile Variant înainte de prima atribuire; - valoarea Null - adică valoare necunoscută sau valoare lipsă.

6.4.3. Vizibilitatea constantelor şi variabilelor Domeniul de vizibilitate al unei variabile este zona de program în cadrul căreia este

recunoscut numele variabilei, şi este definit prin cuvintele cheie Private şi Public. Domeniul de vizibilitate implicit este Private. Aceasta înseamnă că, în lipsa altei specificări, o

constantă sau variabilă este vizibilă local, în cuprinsul procedurii în care a fost declarată. Dacă se doreşte ca unele variabile sau constante să fie vizibile peste tot, în toate modulele,

acestea se declară în afara oricărei proceduri, în zona de declaraţii a oricărui modul de programe, ca de exemplu:

Public Matrice(5,6) As Double În consecinţă, două sau mai multe variabile pot avea acelaşi nume dacă au domenii de

vizibilitate diferite. 6.4.4. Durata de viaţă variabilelor Durata de viaţă a unei variabile este timpul cât ea este memorată şi, deci, accesibilă. Din

acest punct de vedere se deosebesc trei categorii de variabile: - Variabile permanente care păstrează valoarea memorată pe toată durata execuţiei

Visual BASIC. Acestea sunt variabilele declarate cu declaraţia Public; - Variabile temporare care sunt declarate în cuprinsul procedurilor (deci de tip Private) şi

nu sunt memorate decât pe durata execuţiei unei proceduri. Când procedura este apelată, respectivele variabile sunt iniţializate şi folosite, iar la terminarea execuţiei ele sunt "uitate", adică spaţiul de memorie alocat lor este eliberat;

- Variabilele statice sunt acelea declarate cu declaraţia Static. Aceste variabile îşi păstrează valorile de la o execuţie la alta a procedurilor, atât timp cât modulul este în execuţie.

De exemplu:

Function Functia1(x As Single) Static y As Single ... End Function păstrează valoarea variabilei y de la o execuţie la alta a funcţiei Functia1; pe când: Static Function Functia2(x As Single, y As Single) ... End Function păstrează valorile tuturor variabilelor locale ale funcţiei Functia2, de la o execuţie la alta.

Page 139: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 127

§6.5. Tipuri de date definite de utilizator Ca şi în alte limbaje de programare moderne, şi în Visual BASIC, utilizatorul are

posibilitatea de a crea o combinaţie de tipuri de date standard ale limbajului care, apoi, să fie recunoscută ca un tip nou de dată.

Sintaxa declarării noului tip de date este: [Public | Private] Type nume_tip_nou membru1 As nume_tip1 membru2 As nume_tip2 ... End Type Declaraţia pentru tipuri noi se plasează numai în zona pentru declaraţii a modulului. Se observă că, aşa cum este formulată sintaxa, ea se aseamănă foarte mult cu sintaxa

declarării structurilor din limbajul C. După declararea tipului nou de dată, acesta poate fi folosit la declararea variabilelor la fel

ca şi tipurile de date standard. Folosirea variabilelor de tip nou se poate face: - prin referire la întregul tip, de exemplu: variabila1=variabila2 unde variabila1 şi variabila2 sunt variabile de acelaşi tip definit de utilizator. Prin aceasta,

fiecare membru al variabilei variabila1 preia valoarea membrului corespunzător din variabila2;

- prin referire la un membru individual, de exemplu: variabila1.membruk=expresie atribuie membrului de rang k membruk din variabila variabila1 valoarea evaluării

expresiei expresie, valoare care trebuie să fie de tipul lui membruk, sau: variabilax=variabila2.membruj care atribuie variabilei variabilax valoarea membrului de rang j membruj al variabilei

variabila2, cu aceeaşi condiţie a concordanţei tipurilor.

§6.6. Expresii Expresiile sunt construcţii care produc o valoare în urma unui proces de evaluare (proces

de calcul, manevrare a unui caracter, testare a unor date). O expresie este alcătuită din operanzi şi operatori, şi produce o valoare de un anumit tip. Operanzii sunt elemente asupra cărora acţionează operatorii. La rândul lor, operanzii pot fi

expresii. Operatorii indică modul cum se face combinarea operanzilor, adică operaţiile care pot fi

efectuate. Există următoarele tipuri de operatori:

Operatori aritmetici Operatori relaţionali

+ adunare < mai mic decât - scădere > mai mare decât * înmulţire = egal / înpărţire <= mai mic sau egal ^ ridicare la putere >= mai mare sau egal \ înpărţire întreagă <> diferit

Mod Modulo (restul înpărţirii) Is Echivalenţă

Page 140: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 128

Observaţie: spre deosebire de operatorul =, operatorul Is verifică dacă două variabile se referă la acelaşi obiect.

Operatorii relaţionali produc rezultat True sau False.

Operatori pentru şiruri de caractere & Concatenare (adăugarea unui al doilea şir la sfârşitul primului)

Like Similitudine - verifică dacă al doilea şir se regăseşte în cadrul primului

Observaţie: La operatorul Like, în al doilea şir de caractere se pot folosi şi caractere substitutive (wildcard), conform tabelului următor:

Caractere wildcard ? înlocuirea unui caracter în poziţia corespunzătoare * înlocuirea unui grup de caractere # înlocuirea unei cifre zecimale

[lista_de_caractere] înlocuirea oricărui caracter individual, prezent în listă [!lista_de_caractere] înlocuirea oricărui caracter individual, absent din listă

Operatori logici Operator Semnificaţie Rezultatul evaluării

And Şi True dacă ambii operanzi sunt True, altfel False Eqv echivalenţă True dacă ambii operanzi au aceeaşi valoare, altfel False Imp implicaţie True, cu excepţia cazurilor când primul operand este True iar

al doilea False Not Nu True dacă operandul este False, False dacă operandul este TrueOr SAU True dacă cel puţin un operand este True, altfel False Xor SAU exclusiv True dacă numai un operand este True, altfel False §6.7. Conversii de tip Datele din celulele foilor de lucru EXCEL pot fi de tipuri foarte variate. Pentru a fi

prelucrate prin programe Visual BASIC ele sunt mai întâi preluate din celule şi apoi prelucrate în expresii sau funcţii. De asemenea, chiar declarate în program, o serie de variabile pot fi de alt tip decât tipul variabilelor care le vor prelua valorile.

Ca şi în limbajul C, se deosebesc două tipuri de conversii de tip: conversia automată şi cea explicită.

6.7.1. Conversia de tip automată Când se lucrează cu variabile de tipul Variant, Visual BASIC execută automat conversiile

de tip adecvate operaţiilor de executat. Cu toate acestea, anumite precauţii sunt necesare la execuţia operaţiilor aritmetice cu acest tip de date. Mai precis, variabile de tip Variant care urmează să fie convertită, trebuie sa conţină fie valori numerice, fie valori de tip şir care să poată fi convertite numeric.

De exemplu, procedura: Sub conv_date() Dim C1, C2 C1 = "100 Lei" C2 = C1 * 5 Application.Worksheets("Sheet1").Cells(1, 1) = C2 End Sub

Page 141: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 129

poate fi executată fără erori, iar celula A1 din foaia de lucru Sheet1 va afişa valoarea 500, în timp ce, modificând instrucţiunea a 2-a prin: C1 = "100 Kg" se va afişa un mesaj de eroare semnalând tip de dată nepotrivit.

Aceasta se întâmplă deoarece stilul monetar este recunoscut de EXCEL şi, ca urmare, valoarea de tip şir de caractere "100 Lei" este convertită corect la valoarea numerică 100 (practic subşirul "Lei" este ignorat), în timp ce valoarea şir de caractere "100 Kg" este tratată global ca un şir şi nu poate fi convertită la valoare numerică.

Pentru a evita astfel de situaţii, se foloseşte funcţia de test numeric IsNumeric(valoare) care returnează True dacă valoare este numerică sau este convertibilă numeric, şi False în caz contrar.

De exemplu, procedura:

Sub conv_date() C1 = Application.Worksheets("Sheet1").Cells(1, 1).Text If IsNumeric(C1) Then Application.Worksheets("Sheet1").Cells(2, 1) = C1 * 5 Else rasp = MsgBox("Tip gresit!", vbOKOnly, "Avertisment") End If End Sub preia şirul de text din celula A1 şi, dacă acesta este convertibil numeric, afişează dedesubt, adică în celula A2, valoarea numerică multiplicată cu 5. Dacă nu este posibilă conversia la tipul numeric, este afişată o cutie de dialog cu mesajul Tip greşit!

În general, funcţiile de test de tip au forma: IsTest_de_tip(valoare) unde Test_de_tip este un nume generic care indică tipul sau subtipul de date testat (de

exemplu: Array, Empty, Null, etc).

6.7.2. Conversia de tip explicită Dacă se doreşte specificarea tipului de dată la care să se facă conversia, se procedează

astfel: a. Se testează mai întâi dacă valoarea de convertit are tipul adecvat conversiei, folosinr

funcţia de test de tip IsTest_de_tip(valoare); b. Dacă rezultatul testului este True se face conversia folosind funcţia de conversie de tip,

cu forma generală: CTip_nou(valoare) unde Tip_nou indică tipul de date la care se face conversia (de exemplu: Sng pentru

conversia la tipul Single, Dbl pentru conversia la tipul Double, Lng pentru conversia la tipul Long, etc).

De exemplu:

Sub conv_date() Dim C1 As Integer C1 = 100 If IsNumeric(C1) Then Application.Worksheets("Sheet1").Cells(1, 1) = CVar(C1) Else rasp = MsgBox("Tip gresit!", vbOKOnly, "Avertisment") End If End Sub converteşte valoarea variabilei C1 în valoare de tip variant numei dacă valoarea este de tip numeric, şi o transferă celulei A1 din foaia de lucru Sheet1.

Page 142: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 130

§6.8. Enunţurile Visual BASIC În Visual BASIC există următoarele tipuri de enunţuri: - Declaraţiile, sunt enunţuri care anunţă intenţia de folosire a unor variabile cu anumite

caracteristici (nume, tip de date, valori iniţiale). Aceste probleme au fost deja discutate. - Definiţiile, sunt enunţuri care permit introducerea constantelor simbolice, sau a

elementelor de structurare şi de modularizare a programelor, numite proceduri. Acestea vor fi discutate ulterior.

- Acţiunile, sunt definite prin instrucţiuni, care pot fi de următoarele tipuri: a. Instrucţiunea de atribuire, cu sintaxa: [Let] variabilă=expresie b. Instrucţiunea With, se foloseşte pentru a efectua acţiuni multiple de genul: - stabilirea valorilor unor proprietăţi ale unui obiect, - executarea metodei a unui obiect, - atribuirea de valori unei variabile de tip definit de utilizator (structură). Sintaxa instrucţiunii With este următoarea: With obiect secvenţă_de_instrucţiuni End With unde obiect este numele obiectului sau variabilei de tip definit de utilizator asupra

căreia se acţionează. De exemplu, procedura:

Sub aspect_celula() With Application.Worksheets("Sheet1").Range("A1") With .Interior .ColorIndex = 4 .Pattern = xlGray16 End With With .Font .Size = 14 .ColorIndex = 7 End With End With End Sub modifică aspectul celulei A1 din foaia Sheet1, printr-o secvenţă de instrucţiuni With încuibate.

c. Alte tipuri de instrucţiuni, pot fi apeluri de proceduri, apeluri de funcţii, instrucţiuni de decizie, etc., care vor fi discutate mai târziu.

Un enunţ se poate fi scris prin extindere pe mai multe linii folosind caracterul secvenţa identificatoare de întrerupere compusă din caracterul spaţiu urmat imediat de caracterul de subliniere, cu sintaxa:

enunţ _ continuareenunţ De exemplu:

Application.Worksheets("Sheet1").Cells(1, 5) _ = Application.Worksheets("Sheet1").Cells(2, 5)

§6.9. Comentarii Acolo unde se simte nevoia scrierii unor texte însoţitoare, cu simplul scop de adnotare, şi

care nu trebuie luate în considerare de interpretorul Visual BASIC, se poate folosi marcatorul de început de comentariu, cu sintaxa:

Page 143: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 131

[enunţ] 'comentariu unde: enunţ este un enunţ Visual BASIC oarecare; comentariu este un text oarecare scris de utilizator după dorinţă Apariţia caracterului apostrof comunică interpretorului să ignore tot restul liniei. De exemplu: a=255 'atribuie lui a valoarea intreaga 255 Din vechiul dialect BASIC, este recunoscută şi forma: Rem comentariu unde Rem , este cuvântul cheie care face ca întreaga linie să fie ignorată de interpretor.

§6.10. Proceduri Procedurile sunt module de program Visual BASIC. Procedurile sunt de două tipuri: subrutine şi funcţii. 6.10.1. Subrutine O subrutină este un modul de program (procedură) care efectuează acţiuni în baza unei

liste de parametri. Definirea unei subrutine se face cu sintaxa: [Private | Public] [Static] Sub nume_subrutină ([listă_de_parametri]) [secvenţă_de_instrucţiuni] [Exit Sub] [secvenţă_de_instrucţiuni] End Sub unde: Private se foloseşte pentru acele proceduri care trebuie să fie vizibile numai pentru

procedurile aflate împreună cu ele în aceeaşi foaie de modul în care se face definiţia; Public se foloseşte pentru a face procedura vizibilă de către toate procedurile

din toate modulele; Static se foloseşte pentru a păstra valorile variabilelor locale (interne

procedurii) de la un apel la altul; nume_subrutină este numele procedurii de tip subrutină; listă_de_parametri este lista parametrilor formali (separaţi prin virgule)

reprezentând numele variabilelor care recepţionează valorile datelor de intrare (transmise la apelul procedurii).

Observaţie: numele Public este implicit pentru proceduri. Exemplu de definire de subrutine:

Sub Calcul_cerc(ByVal Raza As Single) Dim Arie As Double, Perimetru As Double If Raza < 0 Then MsgBox ("Raza gresita") Exit Sub End If Arie = 3.1415 * Raza ^ 2 Perimetru = 6.283 * Raza Application.Worksheets("Sheet1").Cells(2, 1) = Arie Application.Worksheets("Sheet1").Cells(3, 1) = Perimetru End Sub Sub Tratare_cerc() Calcul_cerc (Application.Worksheets("Sheet1").Cells(1, 1)) End Sub

Page 144: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 132

Scriind o valoare în celula A1 din foaia Sheet1 şi apelând apoi subrutina Tratare_cerc, valoarea din celula A1 este transmisă ca parametru subrutinei Calcul_cerc. Dacă această valoare este negativă este afişată o cutie de dialog cu un mesaj de avertizare şi execuţia se încheie. În caz contrar celula A2 primeşte valoarea ariei cercului iar celula A3 pe aceea a perimetrului lui.

6.10.2. Functii O funcţie este un modul de program (procedură) care primeşte o listă de parametri şi, pe

lângă posibila efectuare a unor acţiuni, returnează un rezultat. Definirea unei funcţii se face cu sintaxa: [Private | Public] [Static] Function nume_funcţie ([listă_de_parametri]) [As nume_tip]

[secvenţă_de_instrucţiuni] [nume_funcţie=expresie1] [Exit Function] [secvenţă_de_instrucţiuni] [nume_funcţie=expresie2]

End Function unde: Private, Public şi Static au acelaşi rol ca la definiţia subrutinei;

nume_funcţie este numele procedurii de tip funcţie; listă_de_parametri este lista parametrilor formali (separaţi prin virgule) reprezentând

numele variabilelor care recepţionează valorile datelor de intrare (transmise la apelul procedurii). nume_tip se foloseşte când funcţia returnează o valoare de un anumit tip.

În cazul listei de parametri, dacă tipurile lor nu sunt specificate, Visual BASIC îi consideră în mod implicit ca fiind de tipul Variant. Pentru a declara explicit alte tipuri de date ale parametrilor, se foloseşte sintaxa:

[Optional][ByVal | ByRef][ParamArray] nume_parametru [As nume_tip] unde: Optional indică un parametru opţional şi obligă ca toţi parametrii care urmează să fie de

asemenea opţionali şi de tip Variant. Această declaraţie nu se foloseşte împreună cu ParamArray; ParamArray se foloseşte numai la sfârşitul listei de parametri pentru a indica faptul

că ultimul parametru este un tablou opţional şi de tip Variant. Astfel se pot declara liste cu număr de parametri arbitrar. Nu se foloseşte împreună cu Optional, ByVal sau ByRef;

ByVal precizează că parametrii primesc argumente prin valoare. În acest caz, modificarea valorilor parametrilor în procedură are efect local, adică nu conduce la modificarea valorii argumentului în procedura apelantă, deoarece parametrul din procedura apelată este o copie.

ByRef produce preluarea argumentului de către parametru ca referinţă (adresă de memorie). În acest fel, atât parametrul din procedura apelată cât şi argumentul din procedura apelantă punctează la aceeaşi adresă de memorie şi, ca urmare, orice modificare a valorii lui în procedura apelată se reflectă şi în procedura apelantă.

nume_parametru este numele parametrului; nume_tip este tipul de dată al parametrului.

De exemplu:

Function Arie_patrat(ByVal Latura As Double) As Double If Latura < 0 Then MsgBox ("Latura incorecta!") Exit Function End If Arie_patrat = Latura ^ 2 End Function

Observaţie: Funcţiile pentru care nu este specificată o valoare de returnare, returnează valoarea Empty.

Page 145: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 133

6.10.3. Apelul procedurilor Apelul subrutinelor se realizează cu sintaxa: nume_subrutină[[(]listă_de_argumente[)]] La apelul subrutinelor parantezele rotunde sunt opţionale. Argumentele listei se separă prin

virgule. Deoarece subrutinele nu returnează nici o valoare ele nu pot fi folosite ca operanzi în

expresii. Apelul funcţiilor se realizează cu sintaxa: nume_funcţie[(listă_de_argumente)] Argumentele listei se separă prin virgule. Ele pot fi şi expresii sau alte funcţii. În momentul execuţiei, valorile argumentelor listei sunt transmise funcţiei. Observaţie: Când un argument de apel al unei subrutine sau funcţii este o expresie, el este

tratat ca şi cum ar fi fost folosit cuvântul cheie ByVal, adică expresia nu va fi afectată de procedură.

Observaţie: Dacă o funcţie este folosită ca operand într-o expresie, este obligatorie

închiderea listei între paranteze. §6.11. Foile pentru module Foile pentru module sunt destinate scrierii modulelor de program. Ele sunt organizate astfel: - Înainte de a defini proceduri sau funcţii, se declară constante sau variabile de uz general

(Public) şi tipuri de date definite de utilizator; - Se definesc procedurile necesare; - În orice punct al foii de modul pot fi scrise comentarii. Accesul la procedurile din aceeaşi foaie de modul este implicit. Accesul la procedurile din altă foaie de modul a aceluiaşi document EXCEL se specifică

cu sintaxa: Valoare=[Alt_modul].Procedură(listă_de_argumente) Accesul la procedurile din alt document EXCEL se specifică cu sintaxa: Valoare=[Alt_document].[Alt_modul].Procedură(listă_de_argumente) În acest ultim caz, mai întâi trebuie stabilită o referinţă la Alt_document care trebuie să fie

existent. Referinţa se stabileşte astfel: - Se activează modulul Visual BASIC apelant; - Din meniul Tools > References > se deschide cutia de dialog References; - În cutia de dialog References se selectează numele Alt_document din cutia de listare

Available References. Dacă numele Alt_document nu apare în listă, se apasă butonul Browse pentru a-l selecta din directorul unde este stocat şi a-l include în listă;

- Se selectează caseta de opţiune din dreptul numelui Alt_document; - Se apasă butonul OK. Pentru protejarea procedurii aplicaţiei contra unor apeluri nedorite ale unor proceduri din

alte module, se plasează cuvântul cheie Private înaintea numelui procedurii. Pentru protejarea întregului modul, la începutul modulului se plasează declaraţia: Option Private Module

Page 146: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 134

§6.12. Structuri de control al execuţiei în Visual BASIC Structurile prin care se obţine controlul execuţiei în Visual BASIC sunt următoarele: 6.12.1. Structura bialternanţă Structura bialternanţă se realizează cu sintaxa: If condiţie1 Then [secvenţa_S1] [ElseIf condiţie2 Then [Secvenţa_S21]]

..... [Else [Secvenţa_S2n]] End If

De exemplu: Function Tip_de_sir(sir As String) As String nr_caractere = Len(sir) If nr_caractere = 0 Then Tip_de_sir = "Sir nul" ElseIf nr_caractere = 1 Then Tip_de_sir = "Caracter unic" Else Tip_de_sir = "Pluricaracter" End If End Function

6.12.2. Structura monoalternanţă Structura monoalternanţă se obţine eliminând din instrucţiunea If alternativele ElseIf şi

Else. Se pot folosi două sintaxe: - scrierea pe o singură linie: If condiţie Then Secvenţă End If ne mai fiind necesar în acest caz, şi: - scrierea pe linii separate: If condiţie Then Secvenţă End If 6.12.3. Structura multialternanţă (selectoare) Când structura decizională a unei probleme impune selectarea uneia dintre mai multe

alternative, se foloseşte structura selectoare, cu sintaxa: Select Case expresie_test [Case listă_expresii_1 [secvenţă_S1]] [Case listă_expresii_2 [secvenţă_S2]] ..... [Case Else [secvenţă_Sn]] End Select unde: expresie_test este o expresie numerică sau de tip şir, care se evaluează o

singură dată la începutul execuţiei structurii;

Page 147: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 135

listă_expresii_j poate avea una dintre formele: a) expresie_1[, expresie_2[,...]] pentru a testa dacă expresie_test are una

dintre valorile expresie_1, expresie_2, etc; b) expresie_1 To expresie_2, cu expresie_1 < expresie_2, pentru a testa dacă

expresie_test este cuprinsă între expresie_1 şi expresie_2; c) Is operator_relaţional expresie, pentru a testa relaţia dintre test_expresie

şi expresie. Ca operator_relaţional se poate folosi orice operator relaţional cu excepţia lui Is şi Like.

Modul de lucru al instrucţiunii Select este următorul: - este evaluată expresie_test; - se compară valoarea obţinută din evaluare cu valorile din listele listă_expresii_j, j=1,...,n,

şi se execută acea alternativă Case care corespunde valorii găsite, adică se execută secvenţă_Sk, unde k este indicele listei detectate a corespunde. Execuţia are loc până la primul Case, Case Else sau End Select;

- Dacă nu a fost găsită nici o corespondenţă, se execută alternativa Case Else, adică Secvenţă_n sau, dacă nu există Case Else, se transferă controlul primei instrucţiuni de după End Select.

6.12.4. Structura repetitivă contorizată explicit Această structură, cunoscută şi sub denumirea de ciclu For, are sintaxa: For contor=valoare_iniţială To valoare_finală [Step pas] [secvenţa_S1] [Exit For] [Secvenţa_S2] Next [contor] unde: contor este o variabilă numerică; valoare_iniţială, valoare_finală şi pas sunt expresii numerice. Dacă este omis, pas

este considerat automat egal cu 1; Modul de lucru al ciclului For este următorul: - este iniţializat contor cu valoare_iniţială; - se testează dacă contor+i*pas>valoare_finală, (i=0,1,2,...), când pas>0, sau dacă este

<valoare_finală, când pas<0; - dacă nu, se execută ciclul până la Exit For sau, dacă acesta nu există sau nici o condiţie

din secvenţă_S1 nu conduce la întâlnirea lui, până la Next [contor]; - dacă da, se transferă controlul primei instrucţiuni de după Next [contor]. Observaţie: menţionarea variabilei contor după Next este opţională pentru ciclurile For

Next simple. La ciclurile încuibate, variabila contor trebuie să însoţească cuvântul cheie Next pentru a diferenţia ciclurile între ele.

De exemplu, procedura: Sub colorare_celule() imax = 5 jmax = 4 For i = 1 To imax For j = 1 To jmax Application.Worksheets("Sheet1").Cells(i,j).Interior. _ ColorIndex = (i - 1) * jmax + j Next j Next i End Sub va produce colorarea unai matrice de 5X4 celule, fiecare celulă cu o altă culoare.

Page 148: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 136

6.12.5. Structura repetitivă contorizată implicit Această structură este o variantă a ciclului For Next numeric, dar se foloseşte pentru

repetarea unei secvenţe de instrucţiuni pentru fiecare element al unei colecţii de obiecte sau al unui tablou. Ea are sintaxa:

For Each element In grup_de_elemente [secvenţa_S1] [Exit For] [Secvenţa_S2] Next [element]

Modul de lucru al acestui ciclu este următorul: - variabila element primeşte referinţa către primul element din grup_de_elemente; - se testează dacă element este ultimul din grup_de_elemente; - dacă nu, se execută instrucţiunile din ciclu până la întâlnirea unui Exit For sau, dacă acesta nu

există sau nici o condiţie din secvenţă_S1 nu conduce la întâlnirea lui, până la Next [contor]; - dacă da, se transferă controlul primei instrucţiuni de după Next [element]. Observaţie: în cazul colecţiilor, element trebuie să fie o variabilă Variant sau Object, iar în

cazul tablourilor, trebuie să fie o variabilă Variant. De exemplu, procedura:

Sub colorare_celule() i = 1 For Each c In Selection c.Interior.ColorIndex = i i = i + 1 Next c End Sub va produce un efect similar cu cel din exemplul anterior, dar asupra unor celule selectate anterior apelului procedurii.

6.12.6. Structura repetitivă condiţionată anterior Această structură are sintaxa: Do [While | Until] condiţie [secvenţă_S1] [Exit Do] [secvenţă_S2] Loop

unde: While, cu semnificaţia cât timp, se asociază cu condiţie True; Until, cu semnificaţia până când, se asociază cu condiţie False; Exit Do produce abandonarea ciclului; Loop marchează sfârşitul ciclului.

Modul de acţiune al ciclului este următorul: - este evaluată condiţie şi este testată; - dacă: = pentru While, condiţie=False, sau = pentru Until, condiţie=True ciclul este încheiat, controlul fiind transferat primei instrucţiuni de după instrucţiunea

Loop; - altfel, ciclul este reluat.

Page 149: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 137

O variantă simplificată a ciclului de tip Do While este următoarea: While condiţie secvenţă Wend De exemplu, procedura:

Sub indexare() i = 1 While i <= 10 Application.Worksheets("Sheet1").Cells(1, i) = i i = i + 1 Wend End Sub produce completarea celulelor A1 până la A10 din foaia de lucru Sheet1 cu numerele 1...10

6.12.7. Structura repetitivă condiţionată posterior Această structură are sintaxa: Do [secvenţă_S1] [Exit Do] [secvenţă_S2] Loop [While | Until] condiţie Semnificaţiile elementelor folosite sunt aceleaşi, dar testarea condiţiei are loc la nivelul

instrucţiunii Loop. De aceea, pe când la structura repetitivă condiţionată anterior execuţia secvenţelor de instrucţiuni poate să nu aibă loc nici o dată, dacă condiţie nu este de la început valabilă, la structura repetitivă condiţionată posterior execuţia secvenţelor va avea loc cel puţin o dată.

6.12.8. Instrucţiunea de salt Instrucţiunea de salt GoTo este o reminiscenţă a perioadei anterioare introducerii noţiunilor

de ingineria programării şi de programare structurată şi de aceea folosirea ei nu este recomandată. Sintaxa ei este:

On expresie GoTo listă_de_etichete unde: expresie este o expresie a cărei evaluare produce un rezultat numeric între 0 şi 255;

listă_de_etichete este o listă cu etichete de instrucţiuni de forma: etichetă1, etichetă2,..., etichetăn

Etichetele de instrucţiuni au forma: etichetă: Modul de acţiune al instrucţiunii este următorul: - se evaluează expresie; - dacă valoarea lui expresie este 0 sau mai mare decât numărul de elemente ale listei, nu se

obţine nici un efect; - dacă valoarea lui expresie este negativă sau mai mare decât 255 se obţine o eroare; - dacă valoarea lui expresie se încadrează în intervalul 1...255, controlul execuţiei este

transferat la instrucţiunea a cărei etichetă are, în listă_de_etichete poziţia de indice egal cu valoarea lui expresie.

- transferul controlului este definitiv. Instrucţiunea GoTo are varianta simplificată: GoTo etichetă ceea ce produce saltul necondiţionat la instrucţiunea cu eticheta specificată.

Page 150: Programarea Calculatoarelor si Limbaje de Programare

Cap. 6. Mediul Visual BASIC pentru EXCEL 138

§6.13. Pseudoprocedura Pseudoprocedura este o secvenţă de instrucţiuni care începe de la o etichetă şi se termină

cu o instrucţiune Return. Sintaxa saltului la pseudoprocedură este: On expresie GoSub listă_de_etichete Mecanismul de acţiune este acelaşi ca la instrucţiunea On GoTo, cu deosebirea că, la

întâlnirea instrucţiunii Return, controlul execuţiei este transferat la prima instrucţiune de după linia On GoSub.

Varianta simplificată a acestei instrucţiuni este: GoSub etichetă şi este o reminiscenţă a versiunilor de limbaj BASIC vechi, nestructurate.

Page 151: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 139

Cap. 7. Resurse de interfaţare grafică §7.1. Generalităţi Prin resurse de interfaţare grafică se înţeleg modulele de program care determină şi gestionează

forma obiectelor grafice de interacţiune. Prin obiect grafic de interacţiune se înţelege o reprezentare grafică din cadrul ferestrei de aplicaţie prin care aplicaţia interacţionează cu utilizatorul.

Printre tipurile de resurse grafice se pot enumera următoarele câteva exemple: - Pictogramă (icon); - Cursor; - Imagine bitmap; - Şir de caractete (etichetă – label); - Cutie de dialog; - Tastă acceleratoare; - Meniu; - etc. Crearea şi gestiunea resurselor se poate rezolva în două moduri diferite: a) În cazul proiectării aplicaţiilor executate direct sub sistemul de operare (în general în cazul programelor realizate prin compilare): - Se scriu fişierele de resurse care conţin descrierile resurselor, constând din componenţa lor, proprietăţile şi geometria lor (mărime şi dispunere în câmpul de lucru). Această fază de generare a resurselor se poate face şi prin tehnici interactive sau aşa-numite "vizuale"; - Fiecare resursă este asociată cu un identificator care este referit în programul care utilizează resursa; - Se compilează setul de module sursă de program; - Se compilează fişierele resurse, fază din care rezultă fişierele resursă compilate; - Se editează legăturile dintre modulele compilate şi resursele compilate b) În cazul proiectării aplicaţiilor executate sub mediul de dezvoltare de aplicaţii, aşa cum este cazul aplicaţiilor scrise în Visual BASIC sub WORD, EXCEL, MicroStation sau AutoCAD 2000, adică în cadrul programelor executate în regim interpretor: - Resursele sunt create vizual, în mod interactiv, prin generarea cu scule specializate. De exemplu, sculele Group Box, Label, Edit Box, Combo Box, etc. În acest caz, definiţiile lor nu mai sunt vizibile în forma text, deşi ele există în fişierul document care conţine aplicaţia respectivă. Ceea ce vede utilizatorul este numai aspectul resursei generate şi, prin intermediul unor instrumente de control speciale, proprietăţile modificabile ale resurselor. - Când are loc prima utilizare în cadrul aplicaţiei a resurselor generate, ele sunt compilate de către interpretorul de program (în general un dialect de Visual BASIC). În afară de cele expuse mai sus trebuie menţionat faptul că resursele grafice exploatabile în cadrul mediilor de dezvoltare a aplicaţiilor, sunt împărţite în două: - Meniurile sunt create prin mijloace distincte şi pot fi exploatate prin module de program scrise de utilizator. - Celelalte resurse (cutii de dialog, bare cu scule) sunt create de către programator şi gestionate prin module de program scrise de către acesta. Rostul acestei separări este acela de a nu expune aplicaţia container unor modificări ale instrumentelor de interacţiune de bază de natură a o face necontrolabilă. Aşadar, în cazul aplicaţiilor create în mediile de dezvoltare a aplicaţiilor se poate vorbi despre două categorii de resurse de interacţiune şi anume: - Resurse de dialog, şi - Resurse de meniu.

Page 152: Programarea Calculatoarelor si Limbaje de Programare

Cap. 7. Resurse de interfaţare grafică 140

§7.2. Tehnici de interacţiune 7.2.1. Dispozitive logice de intrare Cea mai importantă caracteristică a unui program este interfaţa cu utilizatorul, care se defineşte

ca fiind totalitatea mijloacelor şi metodelor prin care utilizatorul poate dialoga cu programul. Dintre diferitele metode de interfaţare, interfaţa sau interacţiunea grafică este cea mai

eficientă şi este preferată de utilizatori. Sistemele grafice pot avea ataşate o mare diversitate de dispozitive fizice de intrare. Pentru

a fi portabile pe cât mai multe platforme, programele trebuie să "vadă" dispozitive logice, adică să lucreze cu un dispozitiv program, în loc de a lucra direct cu dispozitivul fizic.

În acest fel, natura exactă a dispozitivului fizic nu mai trebuie să preocupe în mod deosebit programatorul de aplicaţie.

Fig.7.2.1.

Totuşi, se naşte întrebarea cum se rezolvă problemele care ţin strict de natura dispozitivului fizic? Aceasta este o sarcină care cade în seama sistemului de operare care, preluând datele adresate prin intermediul dispozitivului logic le converteşte în comenzile necesare lucrului cu dispozitivul fizic, folosind un program special, aşa numit "driver de intrare", figura 7.2.1.

Alteori, este necesar să existe alternative de accesare a intrărilor, iar programul să poată accesa un dispozitiv fizic sau altul prin intermediul unor dispozitive logice diferite.

Astfel, o serie de programe de tip CAD pot comanda cursorul grafic de desenare-localizare a entităţilor pe ecran folosind fie mişcarea mouse-ului, fie mişcarea dispozitivului de urmărire al tabletei grafice, fie apăsarea tastelor săgeţi ale tastaturii. Sau, în cazul editoarelor de text cum este WORD, defilarea în jos sau în sus a paginilor se poate face cu tastele Page Down sau Page Up sau prin intermediul barei de defilare verticală acţionată cu ajutorul mouse-ului.

Din aceste motive, standardele grafice GKS (Graphic Kernel System) şi PHIGS (Programmer's Hierarchical Graphical System) definesc şase clase de dispozitive logice de intrare, şi anume:

7.2.1.1. LOCATOR Dispozitivul LOCATOR este un subprogram care citeşte o poziţie de la un echipament de

intrare şi o furnizează (o pune la dispoziţie) programului ca valoare exprimată într-un sistem de coordonate logice (de exemplu poziţia cursorului grafic pe ecran). Poziţiile pot fi determinate cu mouse-ul, joy-stick-ul, tableta grafică sau folosind tastatura cu simboluri săgeţi.

Acest tip de dispozitiv este folosit când, de exemplu, într-un program de grafică se cere desenarea unui segment de dreaptă sau a unei polilinii introducând succesiv punctele nodurilor.

7.2.1.2. STROKE Acest tip de dispozitiv are acelaşi rol cu dispozitivul LOCATOR, dar pune la dispoziţie un

set de poziţii. Astfel, dacă se cere desenarea unui poligon regulat (triunghi, pătrat, pentagon, etc) setul de

puncte care definesc poziţiile nodurilor pot fi introduse printr-o singură comandă care apelează dispozitivul STROKE.

Page 153: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 141

7.2.1.3. VALUATOR Acest dispozitiv se foloseşte pentru introducerea unei valori reale care se poate folosi ca: - factor de scalare; - unghi de rotire; - grad de luminozitate (brightness) al unei imagini; - grad de contrast al unei imagini; - etc. Valorile pot fi introduse fie specificând valoarea dorită a parametrului, fie acţionând un

potenţiometru desenat pe ecran, ca în figura 7.2.2, în care se prezintă o parte din cutia de dialog Format Object din WORD.

Fig.7.2.2.

7.2.1.4. CHOICE

Fig.7.2.3 a. Fig.7.2.3 b. Fig.7.2.3 c

Dispozitivul logic CHOICE este folosit la selectarea unei opţiuni dintr-o listă. Valoarea returnată de subprogramul dispozitiv logic este un număr care reprezintă indicele din listă al articolului.

Când lista este afişată pe ecran, alegerea se poate face folosind mouse-ul sau defilarea cu tastele săgeţi, iar selectarea se poate face prin punctare cu mouse-ul sau prin apăsarea tastei ENTER.

În figurile 7.2.3 a, b şi c sunt prezentate diferite forme de interfaţare prin dispozitiv de tip CHOICE, acestea fiind un meniul scris Help, lista derulantă Font şi, respectiv paleta de culori Shading Color, toate extrase de pe bara de instrumente Formatting din programul WORD.

7.2.1.5. PICK În aplicaţiile grafice evoluate, elementele grafice pot fi grupate (asociate în cadrul unor

submulţimi ierarhizate pe nivele). În funcţie de nevoile lui utilizatorul poate selecta un grup sau altul pentru a-l manipula sau pentru a-l modifica. Selectarea se face prin punctare cu cursorul grafic pe ecran, tehnica curentă fiind prin clic cu mouse-ul aplicat pe elementul grafic dorit. În urma acestei acţiuni programul dispozitiv logic PICK returnează identificatorul

Page 154: Programarea Calculatoarelor si Limbaje de Programare

Cap. 7. Resurse de interfaţare grafică 142

elementului grafic punctat, identificatorul grupului din care face parte şi o informaţie de stare privind succesul sau insuccesul operaţiei.

Insuccesul operaţiei poate surveni ca urmare a unei punctări necorespunzătoare, fie în afara elementului grafic fie între două elemente grafice învecinate. Dacă se punctează într-o arie în care se suprapun mai multe elemente grafice, dispozitivul logic PICK returnează identificatorul celui mai apropiat element grafic şi anume ultimul afişat. De exemplu, în figura 4, a fost aplicat un clic pentru selectare într-un punct în care conturul dreptunghiului şi cel al elipsei se suprapun. Ca urmare a fost selectat cel mai recent desenat element dintre cele două şi anume elipsa, afişarea făcându-se în ordinea desenării dacă

nu au fost aplicate comenzi de schimbare a ordinii de afişare.

Fig.7.2.4.

7.2.1.6. STRING Dispozitivul logic STRING este destinat furnizării de şiruri de caractere care în aplicaţiile

grafice însoţesc reprezentările grafice. Acest dispozitiv este exploatat prin intermediul tastaturii. 7.2.2. Modurile de operare ale dispozitivelor logice de intrare Interacţiunea dintre programul de aplicaţie şi echipamentele de intrare se poate realiza în

mai multe moduri. Astfel, datele de intrare pot fi introduse: - la cererea programului;

PICK

PICK

STRING

Fig.7.2.5.

- la intervenţia operatorului, situaţie în care programul aşteaptă terminarea introducerii datelor după care îşi continuă execuţia.

Sistemele GKS şi PHIGS operează cu cele şase clase de dispozitive logice în următoarele trei moduri:

7.2.2.1. Modul Cerere În această modalitate de lucru programul solicită

efectuarea unei operaţii şi trece în aşteptare până când, prin intervenţia operatorului, dispozitivul logic apelat produce o dată de intrare. În acest mod de lucru, programul controlează în întregime dialogul.

De exemplu, o cutie de dialog care cere introducerea unei valori este un grup grafic compus din dispozitive logice de tipurile indicate în figura 7.2.5.

Programul nu permite utilizatorului să acceseze alte resurse până când nu apasă asupra unuia dintre butoanele care sunt controlate de dispozitivele logice de tip PICK. Mai mult, dacă rezultatul returnat de dispozitivul logic STRING (câmpul de editare Valoare:) nu este corect ca format (aceasta depinde de interpretarea valorii introduse de către un etaj de validare conţinut în dispozitivul logic STRING), programul poate afişa o cutie de dialog cu un mesaj de eroare şi se poate formula o cerere nouă până la satisfacerea ei în mod corect.

7.2.2.2. Modul Eşantionare În cadrul acestui mod de operare al unui dispozitiv logic, operatorul poate acţiona asupra

dispozitivului în orice moment, indiferent de starea programului. Sistemul grafic testează periodic (extrage eşantioane) determinând şi memorând ultima dată produsă de dispozitiv şi considerată ca "valoare curentă".

Acest mod de operare este propriu afişării pe ecran a cursorului grafic ca rezultat al mişcării mouse-ului.

Page 155: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 143

7.2.2.3. Modul Eveniment În acest mod de operare, operatorul preia din iniţiativă proprie controlul sistemului.

Dispozitivul logic devine activ şi toate datele introduse de operator prin această intervenţie sunt memorate de către sistemul grafic.

Acest mod de operare este propriu desfăşurării operaţiilor de intrare lente. Exemple de evenimente pot fi: apăsarea unor butoane grafice de tip Cancel sau Stop în

timp ce sistemul grafic desfăşoară deja o activitate, suspendarea din execuţie a unei aplicaţii care se desfăşoară într-o fereastră pentru a activa desfăşurarea unei alte aplicaţii dintr-o altă fereastră, etc.

Aceste concepte se regăsesc în variante destul de apropiate în diferitele medii de dezvoltare de aplicaţii existente în prezent în uz. Spre exemplificare vom prezenta modul în care se operează cu acestea în dialectul de Visual BASIC implementat în programul EXCEL din Pachetul Microsoft Office.

§7.3. Resurse de dialog Prin resurse de dialog se înţeleg obiectele grafice componente ale cutiilor de dialog

definibile de către utilizator prin care acesta poate interacţiona cu subrutinele create în limbajul Visual BASIC.

Fig.7.3.1. Fig.7.3.2.

7.3.1. Crearea unei cutii de dialog definită de utilizator

Pentru a se obţine accesul la facilităţile de creare de cutii de dialog, din editorul de Visual BASIC se acţionează meniul Insert, submeniul UserForm. Ca urmare, va apare o ramificaţie din nodul Microsoft Excel Objects, denumită Forms. La această ramificaţie se conectează o alta, cu denumirea UserFormk (figura 7.3.1), unde k ia diferite valori, 1, 2, … , etc. (de exemplu UserForm1, UserForm2, … , etc.), respectând ordinea cronologică a creării cutiilor de dialog. Denumirile UserFormk sunt denumiri acordate automat şi ele pot fi modificate de către utilizator, cu condiţia respectării regulilor de denumire a subrutinelor.

După această comandă, locul câmpului de editare a textului programelor este luat de un câmp de lucru în care este afişată o cutie de dialog minimală şi cutia cu butoane de comandă a creării componentelor de dialog, denumită Toolbox (figura 7.3.2).

Cu ajutorul cutiei cu scule Toolbox pot fi create o serie de aşa numite controale (obiecte destinate controlului desfăşurării execuţiei) dintre care enumerăm numai pe cele mai des folosite şi mai uşor de înţeles pentru începător. Pentru a identifica instrumentele de control utilizatorul trebuie să urmărească denumirea instrumentului afişată într-o etichetă galbenă la

Page 156: Programarea Calculatoarelor si Limbaje de Programare

Cap. 7. Resurse de interfaţare grafică 144

trecerea cursorului grafic peste instrumentul respectiv. În figura 7.3.3 este prezentată o cutie de dialog care conţine o parte din controalele care pot fi create folosind cutia Toolbox.

Mai jos sunt date denumirile acestor butoane scule: - Select Objects – serveşte la selectarea unui obiect creat anterior, cu scopul modificării

poziţiei, mărimii şi proprietăţilor acestuia; - Label – serveşte la crearea unei etichete. Eticheta este o inscripţie care poate fi plasată în

apropierea unui control pentru a oferi informaţii despre rolul acestuia (dacă controlul nu este generat cu propria lui etichetă) sau poate fi un simplu text destinat să comunice ceva utilizatorului;

- TextBox – serveşte pentru a crea o cutie de editare de text. O astfel de cutie serveşte la introducerea de către utilizator a unei informaţii sub formă de text, text care va fi apoi prelucrat de programul asociat conform unei semnificaţii specifice destinaţiei informaţiei furnizate. Trebuie reţinut că la acest tip de control răspunderea scrierii corecte a textului (din punctul de vedere al informaţiei) şi a verificării corectitudinii scrierii cade în seama programatorului. Astfel dacă urmează să se indice o valoare numerică, programul trebuie să verifice mai întâi dacă textul scris poate fi tratat ca număr şi apoi să forţeze conversia textului în dată numerică. În acest caz se poate folosi funcţia de test IsNumeric. Mai mult, dacă

numărul care va rezulta trebuie să se încadreze într-un anumit domeniu de valori, şi acest lucru trebuie să fie verificat de subrutina asociată controlului;

- ComboBox – serveşte pentru a crea o cutie combinată pentru listare de articole şi editare a unui text. Articolele listate constituie un set de texte asociat controlului. Utilizatorul poate selecta un articol din listă sau poate scrie un text diferit. Şi aici programatorul aplicaţiei are răspunderea tratării corecte a articolului/textului introdus;

- ListBox – serveşte pentru a crea o cutie de listare din care utilizatorul poate selecta un anumit articol dintr-un set asociat;

Fig.7.3.3.

- CheckBox – serveşte pentru a crea o casetă de opţiune neexclusivă. O astfel de casetă se foloseşte pentru a activa o valoare asociată unei dintre stările bifat/nebifat. Dacă există un grup care conţine mai multe asemenea casete, ele nu se exclud una pe alta, deci pot exista mai multe casete activate la un moment dat. Este răspunderea programatorului ca valorile asociate stărilor casetelor să nu fie contradictorii, cu consecinţe nefaste pentru desfăşurarea programului;

- OptionButton – serveşte pentru a crea o casetă de opţiune exclusivă sau buton radio. Asemenea casete se folosesc întotdeauna cel puţin câte două, grupate împreună şi sunt folosite pentru activarea de opţiuni care se exclud reciproc. Dacă se apasă un astfel de buton dintr-un grup, cel care erea activ anterior se dezactivează automat;

- ToggleButton - serveşte pentru a crea un buton bistabil, adică un buton care poate avea două stări stabile, apăsat sau neapăsat. Acest control este destul de asemănător, în ce priveşte comportamentul, cu controlul CheckBox;

- Frame - serveşte pentru a crea un cadru de grup; - CommandButton - serveşte pentru a crea un buton de comandă. Un astfel de buton,

Page 157: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 145

când este apăsat, lansează în lucru subrutina asociată cu el, deci emite o comandă al cărei efect este determinat de conţinutul subrutinei asociate;

- SpinButton - serveşte pentru a crea o pereche de butoane pentru incrementarea/decrementarea (creşterea/descreşterea) unei valori cu o cantitate fixată;

- Image - serveşte pentru a crea un buton care afişează o imagine. El se comportă la fel ca butonul de comandă dar, deoarece numele fişierului imagine de afişat este o proprietate variabilă a sa, prin programul (subrutina asociată) el poate afişa imagini diferite în funcţie de contextul de lucru.

Mai sunt şi alte instrumente de creare de controale în cutia TextBox. Detalii suplimentare asupra folosirii acestora pot fi aflate consultând help-ul din editorul de Visual BASIC.

7.3.2. Controlul interactiv al proprietăţilor

obiectelor Când un obiect de control este selectat, fereastra

Properties îşi schimbă automat conţinutul conform naturii obiectului. În figura 7.3.4 este reprezentată o parte din conţinutul aferent situaţiei când este selectată cutia de dialog UserForm1.

În fereastră există o listă cu o serie de articole, dispuse pe rânduri, câte unul pentru fiecare proprietate, afişând la stânga denumirea proprietăţii, iar la dreapta valoarea proprietăţii.

Se pot observa trei tipuri de articole, conform modului de completare al câmpului valorii proprietăţii:

- câmpuri de editare, în care proprietatea se introduce prin scriere. Acesta este cazul unor proprietăţi cum sunt numele (Name) obiectului (nume care poate fi folosit ca identificator de obiect

în program), titlul cutiei de dialog afişat pe bara de captare (Caption), înălţimea cutiei de dialog (Height) sau lăţimea ei (Width), etc;

Fig.7.3.4.

- câmpuri cu valori selectate din lista de selecţie ataşată, cum sunt stilul de chenar (Border Style), stare activată (Enabled), cursor de mouse afişat (Mouse Pointer), etc.;

- câmpuri cu valori selectate dintr-o cutie de dialog asociată, cum sunt corpul de literă (Font), Imagine de fond (Picture), etc.

Utilizatorul poate folosi modalităţile diverse de completare interactivă a câmpurilor ferestrei Properties pentru a stabili starea iniţială a controalelor la afişarea cutiei de dialog.

7.3.3. Controlul programat al proprietăţilor obiectelor Pentru ca un obiect de control să execute o acţiune trebuie să i se asocieze o subrutină.

Acest lucru se realizează într-un modul special de proceduri private, astfel: - se selectează obiectul; - cu obiectul selectat, se acţionează meniul View>Code. Ca urmare, aria de editare din

dreapta, a editorului de Visual BASIC, va afişa o schemă de subrutină asociată constând din declaraţiile de început şi de sfârşit ale subrutinei. De exemplu pentru obiectul CommandButton1, subrutina privată asociată creată automat va avea forma:

Private Sub CommandButton1_Click() End Sub

şi nimic altceva.

Page 158: Programarea Calculatoarelor si Limbaje de Programare

Cap. 7. Resurse de interfaţare grafică 146

Va rămâne în sarcina utilizatorului să "umple" subrutina cu instrucţiunile care descriu acţiunile pe care le va efectua obiectul de control asociat.

Proprietăţile obiectelor se pot manevra în timpul rulării prin program. Deoarece este mai uşor de învăţat practic şi vizual, vom efectua următorul exemplu: A. Se crează modulul Module1; B. Se crează cutia de dialog UserForm1; C. În această cutie de dialog se vor crea un buton de comandă (CommandButton1) şi un

buton bistabil (ToggleButton1); D. Din fereastra Properties se stabilesc următoarele proprietăţi: - pentru cutia de dialog UserForm1:

= Caption = şirul de caractere Schimbare de culori - pentru butonul de comandă CommandButton1:

= Caption = şirul de caractere Gata! = Pentru ForeColor se alege o nuanţă de Magenta (liliachiu) = Pentru Font se alege Tahoma, Bold, 14

- pentru butonul bistabil ToggleButton1: = Caption = şirul de caractere Gri = Pentru ForeColor se lasă culoarea prestabilită (negru) = Pentru Font se alege Tahoma, Bold, 14

E. Folosind selecţia obiectelor şi meniul View>Code, se crează subrutinele asociate pentru butonul de comandă şi cel bistabil: Private Sub CommandButton1_Click() Unload UserForm1 End Sub Private Sub ToggleButton1_Click() If ToggleButton1.Value = True Then UserForm1.BackColor = RGB(255, 0, 0) ToggleButton1.Caption = "Rosu" Else UserForm1.BackColor = RGB(255, 255, 0) ToggleButton1.Caption = "Galben" End If End Sub

F. În modulul Module1 se scrie subrutina:

Sub AfisareDialog() Load UserForm1 UserForm1.Show End Sub

Pentru a testa efectul lucrării, se revine într-o foaie de

lucru Excel. Din meniul Tools>Macro>Macros se deschide cutia de dialog Macros de unde se selectează denumirea AfisareDialog şi se apasă butonul Run. Va fi afişată cutia de dialog Schimbare de culori, nou creată. La început, cutia de dialog are culoare gri iar butonul bistabil este neapăsat şi afişează inscripţia Gri. Când acest buton este apăsat culoarea cutiei de dialog devine roşie iar inscripţia butonului devine

Fig.7.3.5.

Page 159: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 147

Rosu iar când este dezapăsat, culoarea cutiei de dialog trece în galben şi inscripţia butonului devine Galben. Cutia va avea la un moment dat aspectul din figura 7.3.5. Când se apasă butonul Gata! cutia de dialog se închide.

Să discutăm acum relaţia cauzală dintre evenimentele din timpul rulării aplicaţiei, şi instrucţiunile scrise în subrutinele create.

- La apăsarea butonului Run din cutia de dialog Macros este lansată în lucru subrutina AfisareDialog. Aceasta, încarcă în memorie obiectul UserForm1 şi, prin instrucţiunea UserForm1.Show afişează cutia de dialog Schimbare de culori. Prin crearea cutiei de dialog, denumirea UserForm1 este recunoscută ca obiect de către programele Visual Basic din documentul curent. Notaţia .Show apelează metoda Show a obiectului UserForm1, metodă prin care are loc afişarea cutiei de dialog;

- În subrutina ToggleButton1_Click blocul decizional bialternanţă If, prin analiza proprietăţii Value a obiectului ToggleButton1 detectează dacă acesta este apăsat (când Value = True) sau neapăsat (când Value = False). În consecinţă sunt modificate corespunzător proprietatea BackColor (culoare de fond) a obiectului UserForm1 la valoarea roşu, (funcţia RGB(roşu, verde, albastru) ia valoarea maximă 255 pentru componenta roşie) respectiv combinaţia roşu = 255 şi verde = 255 din care rezultă galbenul, şi proprietatea Caption (inscripţia) obiectului ToggleButton1 ia valoarea şir de caractere "Roşu" respectiv "Galben";

- În subrutina CommandButton1_Click, care este lansată în lucru când este apăsat butonul de comandă cu inscripţie Gata!, instrucţiunea Unload UserForm1 produce închiderea cutiei de dialog şi descărcarea ei din memorie pentru eliberarea spaţiului ocupat.

§7.4. Integrarea unei aplicaţii în mediul de aplicaţie 7.4.1. Generalităţi Exemplul anterior a prezentat numai modul de folosire a resurselor. Aplicaţia creată

funcţiona cumva ruptă de mediul în care era implementată din punctul de vedere al utilităţii ei în acel mediu.

Când se crează o aplicaţie integrată într-un mediu de dezvoltare de aplicaţii, rolul ei este de a lărgi posibilităţile de lucru în aplicaţia suport.

În principiu se urmăreşte ca prin procedurile create şi prin obiectele (resursele) de interacţiune construite să se manipuleze obiectele componente native ale mediului.

Pentru că suntem în EXCEL vom ilustra integrarea aplicaţiei în mediu prin exemple specifice acestui program.

Există două modalităţi de integrare a unei noi aplicaţii în mediu: - Prin posibilitatea înregistrării unei macrocomenzi, când mediul înregistrează un şir de

acţiuni ale utilizatorului generând un program scris automat sau, - Prin construirea de macrocomenzi de către utilizator. De asemenea, poate exista modalitatea combinată în care, se înregistrează o

macrocomandă şi apoi ea este prelucrată (modificată, adăugită, etc) de către utilizator prin modificarea şi completarea programelor generate automat.

Prima posibilitate se realizează prin facilitatea Record Macro din meniul Tools>Macro>Record New Macro.

În toate situaţiile, integrarea nu este completă dacă nu este realizată şi interfaţarea (legătura dintre mediu şi procedurile şi resursele nou create), astfel încât automatizarea lucrului să fie completă.

Pentru mai multă claritate vom analiza pe rând obiectivele de atins în cadrul construirii unei aplicaţii integrate cu mediul de dezvoltare de aplicaţii.

Page 160: Programarea Calculatoarelor si Limbaje de Programare

Cap. 7. Resurse de interfaţare grafică 148

7.4.2. Controlul prin program al obiectelor aplicaţiei suport Să presupunem o aplicaţie în care dorim să preluăm o valoare din celula existentă în stare

selectată în foaia de lucru activă, să înmulţim acea valoare cu un număr la alegerea utilizatorului şi să plasăm rezultatul în celula de dedesubt.

Pentru aceasta vom construi o cutie de dialog cu componentele din figura 7.4.1. Proprietăţile pe care trebuie să le modifice programatorul sunt:

TextBox1

TextBox2

CommandButton1

CommandButton2

Fig.7.4.1. Fig.7.4.2. - Pentru TextBox1: Enabled=False (interzicerea accesului utilizatorului în cutie); - Pentru CommandButton1: Accelerator=A, Default=True; - Pentru CommandButton2: Accelerator=n. Se crează modulul Module1 în care se scriu subrutinele:

Sub Multiplicare_cu(numar) Dim Celula As Range Set Celula = ActiveCell numar = CStr(numar) Celula.Offset(1, 0).FormulaR1C1 = "=R[-1]C*" & numar Celula.Offset(1, 0).Select End Sub

Această subrutină primeşte la apel valoarea numerică număr. Se defineşte variabila Celulă ca având tipul de dată domeniu de celule (Range) (s-a verificat anterior ca domeniul să conţină o singură celulă). Se converteşte valoarea numerică număr în şir de caractere, folosind funcţia de conversie CStr. Prin referirea de deplasare Offset(nunăr_de_rânduri, număr_de_coloane) se plasează în celula de dedesubt formula de înmulţire cu variabila număr a conţinutului celulei. În final se selectează celula de dedesubt.

Acest mod de manipulare a conţinutului face operaţia independentă de poziţia celulei selectate iniţial, în sensul că este valabilă oricare ar fi celula selectată.

Sub Operare() If Application.Selection.Count <> 1 Then Call MsgBox("Selectati o singura celula!", vbExclamation + vbOKOnly, "Eroare!") Exit Sub Else Dim Celula As Range Set Celula = ActiveCell If Not IsNumeric(Celula.Text) Then Call MsgBox("Valoare nenumerica!", vbExclamation + vbOKOnly, "Eroare!") Exit Sub Else UserForm1.TextBox1.Text = Celula.Text Load UserForm1

Page 161: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 149

UserForm1.Show End If End If End Sub Cu această subrutină se verifică mai întâi dacă selecţia din foaia de lucru Excel constă

dintr-o singură celulă. Dacă nu, se afişează o cutie cu un mesaj de avertisment, ca în figura 7.4.2 şi execuţia se termină forţat.

Apoi, se verifică dacă conţinutul celulei selectate (active) este numeric. În caz contrar se emite un mesaj de eroare şi execuţia se termină forţat.

Dacă ambele condiţii au fost satisfăcute, conţinutul celulei selectate este plasat în cutia de editare TextBox1, se încarcă în memorie cutia de dialog şi este afişată.

În modulul aferent cutiei de dialog UserForm1 se generează subrutinele următoare: Private Sub CommandButton1_Click() numar = TextBox2.Text If Not IsNumeric(numar) Then MsgBox "Introducere gresita!", vbExclamation + vbOKOnly, "Eroare!" Else Multiplicare_cu Val(numar) End If Unload UserForm1 End Sub

Această subrutină este executată la apăsarea butonului CommandButton1 (de acceptare). Ea verifică dacă textul scris de utilizator în cutia de editare TextBox2 are semnificaţie numerică. Dacă nu, este emis un mesaj de avertisment iar dacă da este apelată subrutina Multiplicare_cu având ca parametru valoarea numerică rezultată din conversia cu fincţia Cval. Pe ambele alternative ale blocului de decizie If execuţia se termină cu descărcarea din memorie şi închiderea cutiei de dialog.

Private Sub CommandButton2_Click() Unload UserForm1 End Sub

A doua subrutină este lansată la acţionarea butonului CommandButton2 (de anulare). Are loc numai descărcarea şi închiderea cutiei de dialog fără alt efect.

7.4.3. Personalizarea aplicaţiei La această etapă se realizează o conexiune între un meniu sau un buton de comandă creat

de utilizator şi cutia de dialog pentru preluarea datelor variabile ale lucrării. În analiză finală, lanţul de interacţiune este cel din figura 13:

Fig.7.4.3. Elaborarea acestei scheme de interacţiune constituie etapa de concepţie top-down (de la

vârf la bază) a unui program modular, vârful fiind considerat interacţiunea operator-meniu

Page 162: Programarea Calculatoarelor si Limbaje de Programare

Cap. 7. Resurse de interfaţare grafică 150

(sau operator-buton) iar baza fiind constituită din setul de module de program (subrutine) folosite pentru executarea acţiunilor dorite.

Faza a doua a elaborării unui program este faza down-top (bază vârf) în care, după ce au fost detectate problemele mari de rezolvat, se trece la elaborarea modulelor de program capabile să le realizeze. În această fază modulele de program care se realizează trebuie să aibă o cât mai strictă delimitare a funcţiilor realizate pentru ca, în cazul nevoii de depanare sau de modificare a lanţului de execuţie, lucrările corespunzătoare să fie făcute căt mai uşor iar rezultatul obţinut să fie cât mai sigur.

În cazul nostru, pentru simplitate preferăm crearea unui buton de comandă în foaia EXCEL.

Pentru aceasta, din foaia Excel, acţionăm meniul View>Toolbars>Forms. Se va deschide cutia cu scule Forms din care ne folosim de instrumentul Button pentru a desena un buton de comandă.

Imediat ce desenarea butonului este terminată se deschide cutia de dialog Assign Macro de unde selectăm numele Operare (subrutina definită mai sus).

Există şi facilităţi de ajustare a aspectului scrierii de pe buton, de care ne vom servi pentru a plasa pe buton inscripţia Multiplicare.

Prin acest procedeu am realizat integrarea completă a aplicaţiei. Acum este suficientă o apăsare pe butonul Multiplicare pentru a putea opera cu cutia de

dialog creată mai sus. În concluzie, execuţia lucrării trebuie să urmeze etapele: - proiectarea prin metoda Top-down a componenţei aplicaţiei; - dezvoltarea componentelor aplicaţiei prin metoda Down-top (de la bază în sus) dar

respectând obiectivele stabilite prin metoda Top-down.

Page 163: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 151

Cap.8. Limbajul FORTRAN. Versiunea FTN95 §8.1. Prezentare generală FTN95 este o versiune de limbaj FORTRAN elaborată la Universitatea SALFORD,

dedicată lucrului sub Windows pe 32 de biţi şi pe reţele Microsoft. Mediul integrat sub care se generează programele se numeşte Salford PLATO. Un program în FORTRAN are forma generală:

[PROGRAM nume ] instrucţiuni END [PROGRAM nume]

Articolele dintre paranteze drepte sunt opţionale. Pot fi incluse comentarii (dacă este necesar), ca de exemplu:

PROGRAM Program1 PRINT *, "Salut!" ! Comentariu: Scrierea unui mesaj END PROGRAM Program1

Aşa cum îl descrie numele, limbajul FORTRAN provine din prescurtarea FORmula TRANslation. Majoritatea programelor Fortran se compun din trei părţi:

- Introducerea datelor care sunt stocate ca variabile. - Evaluarea formulelor folosind datele de intrare. - Extragerea rezultatelor.

§8.2. Convenţii sintactice generale Caracterele folosite în Fotran sunt următoarele: - Literele mici şi mari ale alfabetului, fără deosebire, caracterul de subliniere _ , şi cifrele

0...9; - Caractere speciale: = + - * / ( ) , . $ ‘ : caracterul spaţiu ! “ % & ; < > ? Pot fi create simboluri prin combinarea de caractere. Caracterul spaţiu serveşte la delimitarea simbolurilor. Mai multe spaţii consecutive sunt

interpretate ca unul singur. De exemplu, scrierea: a*b este echivalentă cu a * b sau cu a * b În Fortran 95 o instrucţiune este scrisă în general pe o linie cu lungimea de maximum 132

de caractere. Comentariile sunt considerate din poziţia de la care se întâlneşte caracterul ! şi până la

capătul liniei curente. De exemplu: x = (y – z)/2.0 ! Diferenta a doua numere impartita la numarul real 2

Totuşi, caracterul ! nu iniţiază un comentariu dacă el face parte dintr-o construcţie standard a limbajului Fortran 95.

Dacă o instrucţiune nu poate fi complet scrisă pe lungimea unei linii este permisă continuarea ei pe linia următoare dacă linia de continuat se termină cu caracterul &.

Exemplul de mai sus se mai poate scrie: x= & (y – z) & /2.0

De asemenea, este permis să se scrie:

Page 164: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 152

x= & & (y – z)/2.0

Continuarea unei instrucţiuni este permisă până la limita a 39 linii adiţionale. În succesiunea de continuări este permisă intercalarea de linii de comentariu fără ca acestea

să conteze la numărarea celor maxim 39 de linii de continuare. Ca şi în limbajul C, caracterul ; separă mai multe instrucţiuni scrise pe aceeaşi linie. De exemplu:

a = 2; b = 5; c = a/b

Orice instucţiune Fortran poate fi etichetată. Eticheta este o valoare numerică întreagă de maximum 5 cifre, prima trebuind să nu fie nulă. De exemplu: 200 CONTINUE şi 0200 CONTINUE

sunt echivalente, deoarece valoarea etichetei este considerată abia de la prima cifră semnificativă (nonzero).

§8.3. Tipuri de date, declarare, iniţializare În Fortran sunt 5 tipuri de date aşa numite intrinseci (conţinute de limbaj), definind două

categorii: a. tipuri de date numerice: - tipul de date întregi, desemnat de cuvântul cheie INTEGER Datele întregi (cu semn sau fără semn) sunt numere întregi fără parte zecimală, de exemplu: 200, +32, -127 Domeniul de definiţie al acestor numere este limitat la intervalul –2n-1 ... 2n-1–1, unde n este

16 (pentru stocarea pe 2 octeţi) sau 32 (pentru stocarea pe 4 octeţi). Este posibilă schimbarea domeniului prestabilit prin folosirea parametrului de tip KIND despre care vom discuta mai târziu.

- tipul de date reale, desemnat de cuvântul cheie REAL Datele reale sunt numere cu parte zecimală şi pot fi exprimate în două forme

= forma naturală: 251.37 (mai numită şi cu virgulă fixă) = forma cu exponent zecimal: 2.5137E+02 (mai numită şi cu virgulă mobilă)

În memoria internă ele sunt stocate în formatul binar cu virgulă mobilă. Ca şi mai sus, domeniul de definiţie este limitat la anumite valori dar el poate fi modificat cu parametrul de tip KIND.

- tipul de date complexe, desemnat de cuvântul cheie COMPLEX Datele complexe constau într-o pereche de valori reale corespunzătoare părţii reale şi celei

imaginare a unui număr complex. De exemplu (1.0,-5.0) corespunde numărului imaginar 1 - 5i b. tipuri de date nenumerice: - tipul de date caracter, desemnat prin cuvântul cheie CHARACTER Datele caracter sunt şiruri de caractere încadrate de o pereche de delimitatori, ‘ sau “, de

exemplu: ‘Exemplu de sir’

sau “Exemplu de sir”

- tipul de date logice, desemnat prin cuvântul cheie LOGICAL, şi ele pot avea numai valorile .TRUE. sau .FALSE.

Page 165: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 153

Declararea tipului unei date se face în forma generală: Nume_de_tip listă_de_variabile

unde numele de tip poate fi unul dintre cele descrise mai sus iar lista de variabile este o succesiune de nume de variabile separate prin virgule.

De exemplu: INTEGER i, j, k REAL a1, b1 COMPLEX z LOGICAL stare CHARACTER(6) sir

Iniţializarea datelor se poate face într-una dintre formele: Prin instrucţiunea DATA:

DATA i, a1, z, stare, sir / 10 , 0.04, (1.0,-5.0), .TRUE., “SALUT!” /

Sau, folosind separatorul ::, astfel: INTEGER :: i = 10 REAL :: a1 = 0.04 COMPLEX :: z = (1.0,-5.0) LOGICAL :: stare = .TRUE. CHARACTER(6) :: sir='SALUT!'

§8.4. Parametrizarea Prin parametrizare, se înţelege fixarea unui atribut, de valoare sau de tip. Cuvântul cheie folosit este PARAMETER. El poate fi folosit astfel: a. Pentru declararea de constante nemodificabile:

REAL, PARAMETER :: pi = 3.14159 Declarată în acest mod, pi nu mai este o variabilă ci o constantă care nu se mai poate

modifica pe parcursul programului.

b. Pentru declararea parametrului de tip. Legat de acest subiect trebuie spus că pe diferite platforme (calculatoare, sisteme de operare) lungimea în octeţi a unui tip de dată, integer sau real, poate fi diferită. Dacă tipul de dată este definit ca în exemplele date mai sus, compilatorul va folosi lungimea de tip implicită pe calculatorul pe care se face compilarea. Ca urmare, transferat pe un alt calculator, programul ar putea să funcţioneze defectuos sau de loc, datorită modului diferit de exploatare a memoriei la scrierea/citirea datelor. De exemplu, pentru tipul integer lungimea de stocare poate fi pe unele calculatoare de 2 octeţi iar pe altele de 4. Pentru tipul real această lungime poate diferi de la 2 la 4 octeţi. Pentru a se putea realiza portabilitatea deplină a programelor trebuie declarată lungimea tipului de date în mod explicit, astfel: INTEGER, PARAMETER :: tip_i = SELECTED_INT_KIND(5) INTEGER, PARAMETER :: tip_r = SELECTED_REAL_KIND(6,99) INTEGER (KIND=tip_i) i REAL (KIND=tip_r) r

În acest exemplu, în primele două instrucţiuni, se declară constantele de tip tip_i şi tip_r folosite pentru a stoca lungimile în octeţi folosite la stocarea variabilelor de tip întreg (tip_i) şi de tip real (tip_r). Aceste lungimi sunt returnate de funcţiile intrinseci SELECTED_INT_KIND şi SELECTED_REAL_KIND. Folosirea acestor funcţii se supune următoarelor reguli:

Page 166: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 154

SELECTED_INT_KIND(nci) returnează parametrul de tip corespunzător pentru memorarea numerelor întregi cu până la nci cifre, în dat nai sus nostru nci=5, deci cuprins între –99999 şi 99999.

SELECTED_REAL_KIND(ncs,exponent) returnează parametrul de tip corespunzător pentru stocarea numerelor reale cu un număr de ncs cifre semnificative şi situat în domeniul 10-EXPONENT până la 10EXPONENT. În exemplul nostru este vorba de 6 cifre semnificative şi domeniul între 10-99 până la 1099.

Ulterior, valorile constantelor tip_i şi tip_r pot fi atribuite parametrului KIND în declaraţiile de tip, ca în ultimele două instrucţiuni, pentru variabilele i şi r.

Pentru extragerea parametrilor de tip impliciţi ale tipurilor întreg şi real sub compilatorul de Fortran Salford se poate folosi instrucţiunea: PRINT *, KIND(1), KIND(1.0)

Aşa cum se observă în acest exemplu, argumentele funcţiei KIND sunt o valoare întreagă şi, respectiv, una reală.

§8.5. Atribuirea implicită a tipului Dacă nu se specifică nimic în mod explicit asupra tipurilor de date, vechile versiuni de

Fortran atribuie tipul de date în mod implicit pe baza convenţiei că orice variabilă al cărei nume începe cu una dintre literele I…M este de tip întreg, altfel fiind considerată de tip real.

Pentru a împiedica această regulă să acţioneze, se va plasa instrucţiunea: IMPLICIT NONE

la începutul oricărei unităţi de program. Ca urmare, compilatorul va reclama orice variabilă a cărei declarare explicită a fost omisă, la fel ca alte compilatoare ale altor limbaje.

§8.6. Tipuri de date definite de utilizator (date structurate) Ca şi în alte limbaje moderne, şi Fortran permite crearea de date structurate. De exemplu, se poate defini o structura care să conţină datele de identificare ale unei

persoane, ca mai jos: TYPE persoana CHARACTER(LEN=10) :: nume CHARACTER(LEN=10) :: prenume INTEGER :: an_nastere END TYPE persoana

Pentru a declara o dată structurată de tipul de mai sus se va folosi instrucţiunea: TYPE(persoana) :: student

Un membru al structurii student poate fi referit individual prin selectorul de componentă %, astfel: student%an_nastere

De asemenea, se pot defini date structurate care referă la rândul lor structuri, ca mai jos: TYPE punct REAL :: x,y END TYPE punct TYPE triunghi TYPE(punct) :: a,b,c END TYPE triunghi

Page 167: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 155

Aşadar, vom putea face declaraţiile: TYPE(punct) :: m,n,p TYPE(triunghi) :: tr m=punct(0,0) n=punct(1,0) p=punct(0,1) tr=triunghi(m,n,p)

Ca urmare, coordonata y a punctului n va putea fi referită sub forma n%y sau sub forma

tr%b%y §8.7. Operatori şi expresii Operatorii sunt combinaţii de caractere speciale care specifică modul de atribuire şi de

transformare a valorilor (operanzilor) şi sunt folosiţi în construcţia expresiilor. În funcţie de numărul de operanzi asupra cărora se aplică, operatorii pot fi clasificaţi în operatori unari şi binari.

8.7.1. Operatori unari Operatorii unari se aplică asupra unui singur operand. Regula generală de aplicare este: operator operand De exemplu:

- a .NOT. b

8.7.2. Operatori binari Operatorii binari se aplică asupra a doi operanzi după regula generală: operand1 operator operand2 De exemplu:

a – b c * d a .NE. b

8.7.3. Precedenţa operatorilor Precedenţa operatorilor reprezintă prioritatea la aplicarea operaţiilor atunci când nu se

folosesc paranteze pentru a se forţa ordinea operaţiilor în modul dorit de programator. De exemplu, în expresia:

a + b * c Operaţia de înmulţire are prioritatea cea mai înaltă şi va fi efectuată prima. Aşadar, primul

rezultat parţial va fi b * c şi abia apoi acesta va fi adunat cu a. Operaţiile cu precedenţă egală vor fi efectuate în ordinea scrierii operaţiilor. De exemplu, în expresia: a / b * c

operaţiile de împărţire (/) şi cea de înmulţire (*) au acelaşi nivel de precedenţă deci, se va opera mai întâi operaţia a / b şi apoi acest rezultat va fi înmulţit cu c.

8.7.4. Operatori în expresii numerice În expresiile numerice se folosesc următorii operatori:

Page 168: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 156

Operator Semnificaţie Precedenţă (1 = cea mai înaltă) ** Ridicare la putere (ab) 1 * înmulţire (ab) 2 / împărţire (a/b) 2 + adunare (a+b) sau plus unar (+a) 3 - scădere (a–b) sau minus unar (–a) 3

8.7.5. Conversia de tip Atunci când un operator binar este aplicat asupra a doi operanzi de tipuri diferite,

operandul de tip mai slab (cel întreg) este convertit la tipul mai tare (cel real) iar rezultatul este de tipul cel mai tare.

De exemplu: 5 / 10.0 trece în 5.0 /10.0 ceea ce produce rezultatul 0.5 Sursa cea mai frecventă de erori apare la împărţirile între numere întregi când rezultatul

rezultă ca un întreg obţinut prin trunchiere. Deci, dacă mai sus am fi scris: 5/10 rezultatul ar fi fost 0. O eroare similară poate apare dacă se atribuie rezultatul împărţirii a două numere reale unei

variabile întregi. De exemplu, dacă presupunem că n este un număr întreg, expresia: n=5.0/10.0 Ar avea ca efect rezultatul n=0 deoarece, deşi rezultatul împărţirii a fost cel corect, adică

0.5, el a fost convertit la tipul variabilei căreia i se atribuie, adică la tipul întreg, prin trunchiere.

8.7.6. Operatori la nivel de caracter Există numai un singur astfel de operator, concatenarea, notată cu //. De exemplu: 'Tele' // 'fon' produce 'Telefon' Fiind unul singur, acest operator nu are probleme cu precedenţa. 8.7.7. Operatori relaţionali Aceşti operatori testează valabilitatea relaţiei dintre doi operanzi numerici. Tipurile

operanzilor pot fi oricare dintre tipurile întreg sau real. Deoarece expresiile în care intervin aceşti operatori nu conţin succesiuni de operanzi, problema precedenţei nu se pune.

Există următorii operatori relaţionali:

Operator Expresie Înţeles < sau .LT. a < b sau a .LT. b a strict mai mic decât b > sau .GT. a > b sau a .GT. b a strict mai mare decât b <= sau .LE. a <= b sau a .LE. b a mai mic sau egal cu b >= sau .GE. a >= b sau a .GE. b a mai mare sau egal cu b == sau .EQ. a == b sau a .EQ. b a egal cu b /= sau .NE. a /= b sau a .NE. b a diferit de b

8.7.8. Operatori logici Operatorii logici sunt folosiţi în expresiile logice care manipulează date logice cu valorile

.TRUE. sau .FALSE. La aceşti operatori apare problema precedenţei. Se folosesc următorii operatori logici:

Page 169: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 157

Operator Semnificaţie Precedenţă (1 = cea mai înaltă) .NOT. Negare logică (.TRUE. trece în .FALSE. şi

invers) 1

.AND. Şi logic (ambii operanzi sunt .TRUE.) 2

.OR. Sau logic (cel puţin un operand este .TRUE.) 3

.EQV. Echivalenţă logică (ambii operanzi sunt .TRUE. sau ambii sunt .FALSE.)

4

.NEQV. Non-echivalenţă logică (un operand este .TRUE. şi celălalt este .FALSE.)

4

§8.8. Tablouri Un tablou este o structură rectangulară de elemente de acelaşi tip. 8.8.1. Tablouri de mărime fixă Tablourile de mărime fixă se declară folosind instrucţiunea: tip, DIMENSION(mărime) :: nume_tablou De exemplu: REAL, DIMENSION(3) :: u are ca efect rezervarea unui spaţiu fix de memorie, cu lungimea de 3 poziţii de tip real

pentru tabloul unidimensional u, unde se vor putea scrie/citi valorile u(1), u(2) şi u(3). În acest caz, indicierea tabloului este implicită, începând de la elementul cu indicele 1. Dacă se doreşte o altă bază de indiciere, declaraţia se face prin explicitare, astfel: tip, DIMENSION(bază:capăt) :: nume_tablou unde capăt=bază+mărime-1 În exemplul de mai sus, pentru bază=2 şi mărime=3, se poate scrie declaraţia: REAL, DIMENSION(2:4) :: u Ca urmare elementele tabloului vor fi u(2), u(3) şi u(4). Dacă tabloul este multidimensional declaraţia va fi de forma: tip, DIMENSION(mărime_1, ..., mărime_n) :: nume_tablou Pentru indicierea cu bază implicită, sau: tip, DIMENSION(bază_1:capăt_1, ..., bază_n:capăt_n) :: nume_tablou cu aceeaşi regulă de calcul a valorilor de capăt, pe baza valorilor bazelor şi ale mărimilor

mărime_1, ..., mărime_n. În cazul şirurilor de caractere declaraţia va avea forma: CHARACTER, DIMENSION(mărime) :: şir sau: CHARACTER(LEN=mărime) :: şir Este posibilă referirea unui subşir sub forma: şir(i:j) unde i < j < mărime sunt numere întregi Sunt de asemenea posibile notaţii cu limite subînţelese prestabilite: şir(i:) este echivalent cu şir(i:mărime) şir(:i) este echivalent cu şir(1:i) şir(:) este echivalent cu şir(1:mărime) Declaraţia:

Page 170: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 158

CHARACTER(LEN=lungime), DIMENSION(nr_rânduri) :: pagina poate servi la stocarea unei pagini de text cu nr_rânduri fiecare având un număr de

caractere egal cu valoarea lungime. 8.8.2. Tablouri de mărime variabilă Tablourile de mărime variabilă sunt acele tablouri pentru care se cunoaşte numai numărul

de dimensiuni, nu şi mărimile corespunzătoare dimensiunilor, acestea urmând să fie stabilite mai târziu în decursul derulării programului. Regulile de lucru cu aceste tablouri sunt legate de mecanismele de alocare şi gestionare dinamică a memoriei.

Pentru un tablou cu n dimensiuni declararea se realizează astfel: tip, DIMENSION(:, … ,:), ALLOCATABLE :: nume_tablou Mai târziu, în cursul programului, trebuie să aibă loc alocarea memoriei cu instrucţiunea: ALLOCATE(nume_tablou(mărime_1, … , mărime_n)) După ce memoria folosită nu mai este necesară, ea trebuie dezalocată cu instrucţiunea: DEALLOCATE(nume_tablou) De exemplu, pentru un tablou cu două dimensiuni se poate scrie: REAL, DIMENSION(: , :), ALLOCATABLE :: b … ALLOCATE(b(2,3)) … DEALLOCATE(b) §8.9. Structuri de control 8.9.1. Instrucţiunea de salt necondiţionat, GO TO Instrucţiunea de salt necondiţionat GO TO are forma: GO TO etichetă ... etichetă instrucţiune_executabilă unde etichetă este o valoare numerică întreagă. Instrucţiunea GO TO este una controversată, a cărei utilizare este în general

nerecomandabilă, fiind contrară conceptului de inginerie a programării şi de programare structurată. Totuşi, există un număr de situaţii în care ea nu produce efecte negative, şi anume:

- Dacă produce saltul la sfârşitul unui bloc; - Dacă produce saltul la sfârşitul programului. În aceste situaţii instrucţiunea GO TO este utilă, servind ca instrucţiune de ieşire în situaţii

de urgenţă. 8.9.2. Instrucţiunea alternativă, IF Forma generală a instrucţiunii IF este: IF(expresie_logică) instrucţiune Dacă expresie_logică este satisfăcută se execută instrucţiune, altfel controlul este transferat

la instrucţiunea care urmează după IF. De exemplu: IF(indicator) GO TO 10 IF (a <= b) minab=a

Page 171: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 159

8.9.3. Blocul de alternative IF Formele pe care le poate lua blocul IF sunt următoarele: Blocul IF cu o ramură vidă: IF(expresie_logică) THEN ... END IF

Blocul IF cu două ramuri: IF(expresie_logică) THEN secvenţă_da ELSE secvenţă_nu END IF Blocuri IF încuibate: IF(expresie logică_1) THEN secvenţă_da_1 ELSE IF (expresie_logică_2) THEN secvenţă_da_2 ... ELSE secvenţă_nu_1 END IF Execuţia decurge prin testarea fiecărei condiţii logice în parte până când una din ele este

îndeplinită, executând alternativa afirmativă sau de tip else corespunzătoare, după care controlul este transferat la sfârşitul ciclului.

Este recomandabilă alinierea scrierii decalate a instrucţiunilor blocurilor încuibate pentru a se putea distinge uşor apartenenţa lor la alternativele diferite, mai ales în cazul încuibării.

8.9.4. Blocul alternativă multiplă SELECT CASE Forma generală a blocului alternativă multiplă este: SELECT CASE (expresie) CASE (selector_1) secvenţă_1 CASE (selector_2) secvenţă_2 ... [CASE DEFAULT secvenţă_prestabilită] END SELECT unde: expresie este o expresie care produce o valoare întreagă, de tip caracter sau de tip logic. Cel mai adesea expresie este doar o simplă valoare; secvenţă_j este o succesiune de instrucţiuni; selector_j este un set de valori pe care le-ar putea lua expresie. Selectorul poate avea una

dintre formele următoare: - o valoare individuală, de exemplu: CASE (1) - un domeniu de valori, cu forma generală CASE(inferior:superior). Sunt admise formele

subînţelese: CASE(inferior:) toate valorile mai mari decât sau egale cu inferior

Page 172: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 160

CASE(:superior) toate valorile mai mici decât sau egale cu superior - o listă care poate conţine atât valori individuale cât şi domenii, cu virgula ca separator: CASE(1, 3, 5:9, 12)

Forma: CASE DEFAULT este opţională şi este menită să asigure executarea unei alternative, în lipsa selectării

oricăreia dintre cele precedente. Execuţia blocului SELECT CASE are loc prin evaluarea expresiei şi testarea succesivă a

corespondenţei rezultatului produs de ea cu una dintre valorile conţinute de alternativele CASE oferite. Când această corespondenţă este detectată se execută secvenţa alternativă corespunzătoare, după care controlul este transferat la sfârşitul blocului SELECT CASE.

Dacă nici o corespondenţă nu a fost detectată, se execută alternativa CASE DEFAULT, adică secvenţă_prestabilită.

8.9.5. Ciclul repetitiv contorizat DO Ciclul repetitiv contorizat DO are forma DO indice = început, sfârşit, pas secvenţă END DO Ciclul funcţionează prin executarea secvenţei de un număr de ori determinat de valorile de

început şi sfârşit ale lui indice, cu pasul dat. Dacă pas = 1 el poate să fie omis, forma ciclului fiind în acest caz: DO indice = început, sfârşit secvenţă END DO O formă mai veche a instrucţiunii DO este cea cu etichetă, în forma: DO etichetă indice=început, sfârşit secvenţă etichetă CONTINUE Instrucţiunea CONTINUE este folosită şi în alte construcţii unde se doreşte să nu se

execute nimic, ea servind numai ca reper către care se dirijează execuţia. Dacă nu se doreşte executarea selectivă a instrucţiunilor ciclului se poate folosi

instrucţiunea CYCLE a cărei întâlnire produce transferul controlului execuţiei la instrucţiunea END DO. De exemplu:

DO indice = început, sfârşit secvenţă_1 IF (condiţie) THEN CYCLE secvenţă_2 END DO În exemplul de mai sus, ori de câte ori condiţie este îndeplinită, se execută instrucţiunea

CYCLE al cărei efect este de a se produce incrementarea indicelui şi executarea unui nou ciclu sărindu-se peste secvenţă_2 care nu mai este executată.

8.9.6. Ciclul DO indefinit Ciclul DO indefinit are forma:

Page 173: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 161

DO secvenţă END DO Folosit strict în această formă ciclul DO devine infinit şi conduce la blocarea programului

prin executarea la infinit a aceleiaşi secvenţe. Ieşirea din el se poate face folosind instrucţiunea EXIT, ca mai jos: DO secvenţă IF (condiţie) EXIT secvenţă END DO Folosirea acestui tip de ciclu trebuie făcută cu deosebită grijă pentru a se evita rămânerea

în buclă infinită dacă CONDIŢIE nu este niciodată satisfăcută. 8.9.7. Ciclul DO WHILE Ciclul repetitiv condiţionat anterior DO WHILE are forma: DO WHILE (condiţie) secvenţă END DO Ciclul funcţionează atât timp cât expresia logică CONDIŢIE este îndeplinită. Trebuie avut

grijă ca, pe parcursul operaţiilor derulate în secvenţa de instrucţiuni, expresia CONDIŢIE să se modifice la un moment dat, luând valoarea .FALSE., altfel ciclul poate deveni infinit.

8.9.8. Ciclul DO implicit Ciclul DO implicit este o structură folosită numai la operaţiile de intrare/ieşire. De exemplu: READ(* , *) (X(I), I=1,5) are efectul de a citi de la dispozitivul de intrare prestabilit (tastatura) valorile X(1), ..., X(5)

în mod succesiv, ceea ce este echivalentul ciclului DO explicit: DO I = 1, 5 READ (* , *) X(I) END DO 8.9.9. Etichetarea (numirea) structurilor de control În cazul structurilor de control IF şi DO, datorită faptului că acestea pot fi încuibate pe mai

multe nivele de adâncime, este utilă identificarea uşoară a nivelelor folosind denumiri. Ca urmare se pot crea structuri de control de forma: nume: IF (condiţie) THEN secvenţă END IF nume sau: nume: DO indice=început, sfârşit, pas secvenţă END DO nume

Page 174: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 162

§8.10. Unităţi de program şi proceduri 8.10.1. Generalităţi În Fortran există patru tipuri de unităţi de program: Programe principale Subrutine Funcţii Module Fiecare fişier sursă conţine unul sau mai multe unităţi de program şi este compilat separat,

după compilare fiind necesară o etapă de legare a codurilor obiect rezultate. 8.10.2. Programe principale Fiecare program Fortan trebuie să conţină un singur program principal care poate apela alte

subprograme. Forma generală în care se prezintă un program principal este următoarea: PROGRAM [nume]

instrucţiuni USE [IMPLICIT NONE] declaraţii de tip instrucţiuni executabile

END [PROGRAM [nume] ] 8.10.3. Subrutine O subrutină este o unitate de program care execută acţiuni şi poate fi apelată dintr-o altă

unitate de program cu instrucţiunea: CALL nume_subrutină (listă_de_argumente) Forma generală a unei subrutine este următoarea: [RECURSIVE] SUBROUTINE nume (listă_de_argumente)

instrucţiuni USE [IMPLICIT NONE] declaraţii de tip instrucţiuni executabile

END [SUBROUTINE [nume]] Specificaţia RECURSIVE este obligatorie dacă subrutina este recursivă adică dacă se

autoapelează. Argumentele din lista de argumente sunt transmise prin referinţă. Aceasta înseamnă că sunt

transmise adresele locaţiilor de memorie unde se află argumentele reale şi deci orice modificare a variabilelor corespunzătoare din cuprinsul subrutinei se reflectă în programul apelant. Spre deosebire de acest mecanism de transfer, transmiterea argumentelor în C şi C++ se face în mod normal prin nume (dacă nu se folosesc pointerii), ceea ce înseamnă că argumentele formale din subprogram sunt copii ale argumentelor reale şi modificările lor nu afectează programul apelant. Aşadar, mecanismul de transfer al argumentelor din FORTRAN nu respectă principiul încapsulării datelor, ceea ce este un dezavantaj din punctul de vedere al ingineriei programării şi al programării structurate. Acelaşi lucru este valabil şi pentru transmiterea argumentelor funcţiilor, despre care se va vorbi mai jos. Din aceste motive programatorul de FORTRAN trebuie să acorde o atenţie deosebită evitării efectelor laterale care ar potea fi produse involuntar, spre deosebire de cei care programează în C şi C++, unde efectele laterale se obţin în mod voit.

Page 175: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 163

8.10.4. Instrucţiunea STOP În mod normal execuţia unităţii de program se încheie la instrucţiunea END. Instrucţiunea STOP produce de asemenea încheierea execuţiei unităţii de program în care

se află inclusă. Pot exista mai multe instrucţiuni STOP într-o unitate de program, la care se poate ajunge pe diferite căi, fie prin instrucţiune de salt GO TO la o instrucţiune STOP cu etichetă fie prin includerea instrucţiunii STOP într-o structură IF, etc.

Forma generală a instrucţiunii STOP este: [etichetă] STOP ‘mesaj’ 8.10.5. Funcţii O funcţie o unitate de program care primeşte o listă de argumente şi returnează o valoare. Funcţie poate fi invocată prin simpla utilizare a numelui ei într-o expresie, de exemplu: variabilă = funcţie(listă_de_argumente) În zona de fişier sursă unde se face definirea funcţiei, numele acesteia este tratat ca o

variabilă căreia trebuie să i se definească tipul, acesta fiind tipul rezultatului returnat de funcţie.

Forma generală a unei funcţii este următoarea: [RECURSIVE] [tip] FUNCTION nume (listă_de_argumente) [RESULT (nume_rez)]

instrucţiuni USE [IMPLICIT NONE] declaraţii de tip instrucţiuni executabile

END [FUNCTION [nume]] Declaraţia RECURSIVE este obligatorie dacă funcţia este recursivă (se autoapelează). Declaraţia RESULT defineşte o variabilă care preia valoarea funcţiei pentru utilizare în

interiorul unei funcţii recursive deoarece în interior, numele funcţiei nu poate fi folosit ca variabilă.

De exemplu, pentru a calcula suma primelor n numere se poate scrie funcţia: RECURSIVE INTEGER FUNCTION sum_n(n) RESULT (rez) INTEGER n INTEGER rez if (n==0) then rez=0 else rez=n+sum_n(n-1) end if END FUNCTION sum_n Dacă se pune problema ca funcţia să se încheie altfel decât prin atingerea instrucţiunii

END, se va folosi instrucţiunea RETURN în aceleaşi condiţii ca şi instrucţiunea STOP la subrutine sau programe principale.

Forma generală a instrucţiunii RETURN este: [etichetă] RETURN 8.10.6. Argumente reale şi formale. Argumente opţionale Argumentele reale sunt cele care apar la referirea unei proceduri (apel de subrutină sau de

funcţie). Ele specifică entităţile reale pe care procedura le va folosi pe parcursul execuţiei ei. Aşadar, aceste argumente pot fi valori efective sau variabile care pot avea valori diferite la fiecare referire. Unele argumente sunt folosite ca valori de intrare în procedura referită (ele

Page 176: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 164

pot fi valori sau variabile), altele sunt variabile care receptează rezultatele execuţiei procedurii, iar altele pot avea pot avea ambele destinaţii.

Argumentele formale sunt cele care apar ca nume în interiorul procedurilor. Aceswte nume sunt specificate când procedura este definită şi sunt folosite în calculele din interiorul procedurii.

Când procedura este referită are loc o asociere între argumentul real şi cel formal pe principiul poziţionalităţii. Aceasta înseamnă că primul argument real din lista de argumente a referirii (apel de subrutină sau funcţie) este asociat cu primul argument formal al listei din definiţia procedurii, al doilea argument real cu al doilea argument formal, etc. Aceasta impune corespondeţa de tip şi dimensionalitate (în cazul tablourilor) între cele două tipuri de argumente.

Argumentele opţionale sunt acele argumente formale care pot să nu aibă un corespondent ca argument real la referirea unei proceduri, dacă într-un anume caz de execuţie particular aceasta nu este necesar. În acest caz, la referirea procedurii, argumentele reale corespunzătoare pot lipsi din lista de argumente sau pot fi specificate în altă ordine.

În definiţia procedurii opţionalitatea argumentului se semnalează prin declaraţia de atribut OPTIONAL a cărei formă este:

OPTIONAL listă_de_argumente_opţionale unde listă_de_argumente_opţionale este o listă de nume de argumente formale (interne

procedurii) separate prin virgule. Deoarece principiul corespondenţei prin poziţionalitate funcţionează şi în acest caz,

abaterea de la acest principiu constituie o excepţie care trebuie semnalată. Regula este aceea că, dacă un argument opţional este omis din lista de referire, atunci fie

toate argumentele opţionale de la el până la capătul listei sunt omise fie, existenţa celor rămase este semnalată prin scrierea argumentului real în forma:

nume_argument_formal=nume_argument_real De exemplu: PROGRAM atribuiri IMPLICIT NONE REAL a,b,c INTERFACE SUBROUTINE afisare(x,y,z) OPTIONAL y,z REAL x,y,z END SUBROUTINE afisare END INTERFACE a=1.0; b=2.0; c=3.0 CALL afisare(a,z=c) END PROGRAM atribuiri SUBROUTINE afisare(x,y,z) IMPLICIT NONE OPTIONAL y, z; REAL x,y,z,u,v,w u=x IF (PRESENT(y))THEN; v=y; ELSE; v=1.0; END IF IF (PRESENT(z))THEN; w=z; ELSE; w=1.0; END IF WRITE(*,*)u,v,w END SUBROUTINE afisare Se pune întrebarea ce se întâmplă totuşi dacă un argument opţional nu este furnizat la

apelul procedurii. Deranjează lipsa aceastuia execuţia? Acest lucru este posibil, dacă nu se

Page 177: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 165

folosesc valori prestabilite pentru argumentele lipsă. Pentru a realiza acest lucru este utilă funcţia logică intrinsecă (conţinută în biblioteca de funcţii a compilatorului) PRESENT(arg).

Ea returnează un rezultat logic (.TRUE. sau .FALSE.) care poate fi folosit pentru a adopta sau nu valoarea prestabilită, aşa cum se vede în exemplul de mai sus.

În acest exemplu a trebuit construită o interfaţă între programul principal şi procedura apelată (subrutina) folosind blocul INTERFACE care repetă în corpul programului principal semnătura subrutinei, adică numele (dacă este funcţie tipul de valoare returnată), lista de argumente, tipurile argumentelor şi proprietăţile lor.

În afară de aceste măsuri mai trebuie luată şi măsura ca un argument formal opţional care nu este prezent să nu fie invocat. Astfel, se observă că instrucţiunea WRITE(*,*)u,v,w nu foloseşte argumentele y şi z deoarece, după caz, ele ar putea sau nu să fie furnizate. Singura funcţie care poate folosi numele acestor argumente este funcţia PRESENT.

În exemplul de mai sus rezultatul afişat după rulare este: 1.000000 1.000000 3.000000 deoarece lipsind al doilea argument, adică y, el a primit valoarea 1.0 prin intermediul

blocului IF corespunzător. Argumentele opţionale pot fi furnizate şi într-o altă ordine decât cea din lista

subprogramului dacă excepţia este semnalată prin menţionarea numelor formale. 8.10.7. Conservarea valorilor. Atributul SAVE În mod normal, la revenirea dintr-un subprogram (subrutină sau funcţie) compilatorul

Fortran permite calculatorului să uite valorile variabilelor definite în subprogram. Dacă este necesară conservarea valorilor unora sau altora dintre aceste variabile, ele pot fi asociate cu atributul de salvare, astfel:

tip, SAVE :: listă _de_variabile Dacă declaraţia de tip a avut loc anterior, instrucţiunea SAVE poate fi scrisă separat: SAVE :: listă _de_variabile unde listă_de_variabile are forma nume_var_1, ... nume_var_n De exemplu: REAL, SAVE :: a, b, c O instrucţiune SAVE fără listă de variabile produce salvarea valorilor tuturor variabilelor

subprogramului. Acest lucru nu este recomandabil, deoarece nu toate compilatoarele se comportă la fel de eficient în acest caz. De asemenea, trebuie să se analizeze cu atenţie posibila apariţie de efecte laterale (transmitere nedorită de valori asupra altor variabile).

8.10.8. Module de program Modulele de program sunt colecţii de cod sursă grupate în fişiere separate care pot fi

invocate în diferite unităţi de program. Rolul lor, ca şi în alte limbaje (de exemplu fişierele antet din C) este de a realiza economia de efort, prin preluarea în unităţile de program a unor definiţii, declaraţii, subrutine şi funcţii deja scrise şi verificate.

Forma generală a unui modul este următoarea: MODULE nume_de_modul declaraţii şi definiţii de date ... CONTAINS definiţii de subprograme ale modulului ... END [MODULE [nume_de_modul]]

Page 178: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 166

Modulelor li se aplică următoarele reguli: - Dacă un modul este scris în acelaşi fişier cu programul principal, el trebuie plasat înaintea

programului principal; - Aşa cum se observă în definiţia generală de mai sus, modulul începe şi se termină cu

instrucţiunile: MODULE nume_de_modul END [MODULE [nume_de_modul]] - Orice unitate de program care foloseşte conţinutul modulului, trebuie să îl invoce cu

instrucţiunea: USE nume_de_modul plasată imediat după numele programului. După această instrucţiune variabilele şi

subprogramele conţinute în modul pot fi folosite. Dacă variabilele au fost declarate şi definite în modul, ele nu mai trebuie declarate şi definite din nou, simpla invocare a modulului prin instrucţiunea USE fiind suficientă;

- Este posibil ca un nume folosit în modul să intre în conflict (să fie acelaşi) cu un nume folosit în unitatea de program invocatoare. Pentru a se evita conflictul, în instrucţiunea USE se poate include o instrucţiune de schimbare locală a numelui conflictual din modul, în forma:

USE nume_de_modul, nume_local => nume_din_modul - Dacă nu se doreşte preluarea tuturor variabilelor din modul ci numai a unora, acest lucru

se specifică astfel: USE nume_de_modul, ONLY: variabila_1, ..., variabila_n unde variabila_1, ..., variabila_n este lista variabilelor de preluat din modul;

8.10.9. Vizibilitatea datelor din module. Atributele PUBLIC şi PRIVATE Una dintre utilizările cele mai răspândite ale modulelor este de a crea un stoc de date

comun pentru toate unităţile de program care îl folosesc. Din acest motiv, toate variabilele unui modul sunt considerate în mod implicit publice.

Dacă, din motive care ţin de separarea datelor comune de cele particulare, evitarea efectelor laterale, etc, se doreşte ca unele variabile să nu fie vizibile în exteriorul modulului, iar altele da, se va explicita aceasta folosind atributele PUBLIC şi PRIVATE, astfel:

tip, PUBLIC :: listă_de_variabile sau tip, PRIVATE :: listă_de_variabile un atribut PUBLIC sau PRIVATE neurmat de o listă de variabile declară toate variabilele

modului ca fiind publice sau private. De exemplu: PRIVATE REAL, PUBLIC :: A declară toate variabilele modulului cu excepţia variabilei reale A ca fiind private.

8.10.10. Fişiere externe. Directiva INCLUDE Nevoia de a lucra cu fişiere care să conţină porţiuni de cod sursă prefabricate, astfel încât

să se economisească efort la scrierea programelor mari, a făcut ca de la versiunea Fortran 77 să fie folosită directiva de compilator INCLUDE. Aceasta are forma:

INCLUDE ’nume_fişier’ unde ’nume_fişier’ este numele fişierului text de inclus.

Page 179: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 167

Fişierul de inclus poate conţine orice secvenţă de declaraţii şi instrucţiuni valide în contextul poziţiei din fişierul gazdă în care vor fi incluse. Efectul directivei este de a compila programul ca şi cum secvenţa de cod sursă ar fi inclusă s-ar afla efectiv începând de la linia directivei INCLUDE.

În FTN95 se poate include orice fel de fişier text, cu condiţia ca el să facă parte din structura unui fişier proiect. Cu toate acestea se preferă folosirea fişierelor cu denumirea având forma NUME.INC, deoarece numai acestea beneficiază de facilitatea de analiză sintactică constând din semnalarea corectitudinii scrierii cuvintelor cheie ale limbajului.

Ca exemplu vom restructura aplicaţia prezentată mai sus la subcapitolul de funcţii, subiectul recursivitate, astfel:

Se va folosi un proiect care va conţine fişierele următoare: Fişierul programului principal CALCUL_SUMA.f95: PROGRAM calcul USE suma_de_n INCLUDE 'date.inc' INTEGER k k=sum_n(i) WRITE(*,*) k END PROGRAM calcul

Fişierul de modul sum_n.f95: MODULE suma_de_n IMPLICIT NONE CONTAINS RECURSIVE INTEGER FUNCTION sum_n(n) RESULT (rez) INTEGER n INTEGER rez IF (n==0) THEN rez=0 ELSE rez=n+sum_n(n-1) END IF END FUNCTION sum_n END MODULE suma_de_n Fişierul de includere date.inc conţine numai declaraţia de tip cu iniţializare: INTEGER ::i=5 Rezultatul afişat de program după rulare va fi 15. Şi fişierele de modul şi cele de includere au acelaşi efect, şi anume acela de creare din

bucăţi a programului complet. Deosebirea dintre fişierul de modul şi fişierul de includere este aceea că pentru fişierul de

modul compilarea se face separat, înainte de etapa de legare a codurilor obiect individuale ale componentelor proiectului, în timp ce compilarea codului sursă al fişierului de includere se face odată cu compilarea unităţii în care el este inclus prin directiva INCLUDE.

§8.11. Operaţii de intrare/ieşire 8.11.1. Instrucţiunea FORMAT Instrucţiunea FORMAT este destinată descrierii modului cum vor fi citite sau scrise datele.

Forma ei generală este: etichetă FORMAT (listă_de_articole_de_format)

Page 180: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 168

unde: etichetă este o valoare numerică întreagă şi pozitivă. Ea este necesară pentru referirea

formatului în instrucţiunile de citire/scriere cu format explicit. listă_de_articole_de_format este o listă cu articole de forma: r descriptor_de_format separate prin virgule. Între valoarea r şi descriptor_de_format nu se lasă spaţiu separator. De exemplu: 2I5 semnifică două valori întregi cu 5 cifre. r este repetitorul, constând dintr-o valoare numerică întreagă pozitivă care stabileşte

numărul de valori de citit/scris care au acelaşi format. Dacă r=1 el nu se menţionează. În exemplul de mai sus repetitorul este 2. descriptor_de_format este o combinaţie de forma: specificator_de_format lungime_de_scriere scrise fără spaţiu separator În exemplul de mai sus descriptorul de format este I, iar lungimea de scriere este 5. Specificatorul de format poate fi unul dintre următoarele: I – pentru numere întregi. În acest caz lungime_de scriere este un număr pozitiv întreg

reprezentând numărul de poziţii rezervate pentru scrierea cifrelor numărului. De exemplu: I5 F pentru numere reale. În acest caz lungime_de scriere va apare în forma: ncî.ncz unde ncî este numărul de cifre ale părţii întregi iar ncz este numărul de cifre ale părţii

zecimale. De exemplu: F5.3 E – pentru numere reale reprezentate în format cu mantisă şi exponent zecimal. În acest caz

lungime_de scriere va apare în aceeaşi formă ca şi la specificatorul F. De exemplu: E12.5 ar putea produce o scriere de forma –0.12345E+03 echivalent în scrierea normală cu –

123.45. Deoarece semnul mantisei, cifra 0, punctul zecimal şi exponentul E+nn totalizează 7 caractere, trebuie ca numărul de cifre zecimale specificat să fie mai mic decât lungimea totală (în acest caz 12) minus 7. Astfel, un format E12.6 nu ar putea fi folosit deoarece nu ar mai rămâne destule poziţii pentru cele 7 elemente de scriere enumerate mai sus.

D – pentru numere reale în format cu exponent zecimal dar în dublă precizie. Regula este

aceeaşi ca şi la formatul E. A – pentru şiruri de caractere. În acest caz lungime_de scriere este un număr pozitiv întreg

reprezentând numărul de poziţii rezervate pentru scrierea caracterelor şirului. De exemplu: A20 X – pentru scrierea unui spaţiu gol sau ignorarea citirii unui caracter. De exemplu: 6X semnifică 6 spaţii goale.

Page 181: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 169

L – pentru valori logice. În acest caz lungime_de scriere este un număr pozitiv întreg reprezentând numărul de poziţii rezervate pentru scrierea caracterelor valorii logice (.TRUE. sau .FALSE.).

Exemple de formate de scriere: 100 FORMAT(I3, F5.2, 2I5, 3E12.5) 200 FORMAT(2(I3, F7.4), I4) Cel de al doilea exemplu prezintă un caz de folosire a listelor de articole de format încuibate. 8.11.2. Instrucţiuni pentru transferul datelor 8.11.2.1. Instrucţiunea READ Instrucţiunea READ, poate avea una dintre următoarele două forme: READ (listă_specificatori_control_I/O) listă_de_articole_de_citit sau READ etichetă_de_format , listă_de_articole_de_citit

unde listă_specificatori_control_I/O este o listă care poate conţine articolele următoare separate prin virgule. Cuvintele cheie scrise cu majuscule şi încadrate de paranteze drepte nu sunt necesare decât dacă nu se respectă ordinea de scriere a articolelor:

[UNIT=] unitate este numărul unităţii de intrare/ieşire de la care se citesc datele. Pentru dispozitivul

implicit, în acest caz tastatura, se foloseşte caracterul * iar pentru fişiere un număr definit în instrucţiunea OPEN

[FMT=] etichetă_de_format este eticheta numerică care însoţeşte instrucţiunea FORMAT [NML=] nume_de_listă_de_variabile specifică citirea unor variabile declarate ca făcând parte dintr-o listă denumită. Citirea se face

în ordinea declarării lor în listă. Instrucţiunea care crează lista este NAMELIST şi are forma: NAMELIST /nume_de_listă/ listă_de_variabile De exemplu: NAMELIST /date_personale/ an_nastere, luna_nastere, ziua_nastere [IOSTAT= variabilă_de_stare_I/O] variabilă_de_stareI/O va căpăta una dintre valorile: - 0 – citirea a avut loc cu succes - întreg negativ – a fost atins capătul de fişier (EOF) sau de înregistrare (EOR). În FTN95

Salford valorile posibile sunt: -1 pentru EOF şi –2 pentru EOR. - întreg pozitiv – a survenit o eroare de alt tip Valoarea acestei variabile este utilă atunci când se fac citiri dintr-un fişier. Analiza ei

ulterioară în program permite dirijarea execuţiei pe ramurile de tratare a erorilor adecvate cazului de eroare care a survenit în timpul operaţiilor de citire/scriere din/în fişier;

[ERR=etichetă] instruieşte programul să sară la eticheta unei ramuri de tratare a erorii survenite prin

apariţia unei erori. Aici variabila de stare I/O este utilă pentru a discerne între cazurile de eroare de intrare/ieşire;

[END=etichetă] instruieşte programul să sară la eticheta unei ramuri care tratează cazul de atingere a

sfârşitului de fişier.

Page 182: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 170

Lista de articole de citit este compusă din variabilele a căror citire se va efectua, separate prin virgule.

Dacă instrucţiunea format foloseşte numai primele două articole, UNIT şi FMT menţionarea acestor două cuvinte cheie nu este necesară şi instrucţiunea are forma:

READ (unitate, etichetă_de_format) listă_de_articole_de_citit De exemplu, instrucţiunile: READ (*, 100) i, x 100 FORMAT (I5, F7.3) vor produce citirea de la tastatură a valorilor întreagă i şi reală x cu formatul specificat la

eticheta 100. Acelaşi efect îl va avea şi: READ 100, i, x citirea făcându-se de la dispozitivul de intrare implicit, adică tastatura. 8.11.2.2. Instrucţiunea WRITE Instrucţiunea WRITE are forma: WRITE (listă_specificatori_control_I/O) listă_de_articole_de_scris iar semnificaţiile entităţilor menţionate sunt aceleaşi. Dispozitivul implicit este ecranul, iar

notaţia pentru acesta este tot caracterul *. Pentru a se evita ca la scriere să se introducă caracterul de salt la linie nouă se poate folosi

în lista de specificatori de control I/O articolul: ADVANCE = 'NO' 8.11.2.3. Instrucţiunea PRINT Instrucţiunea PRINT are forma: PRINT etichetă_de_format, listă_de_articole_de_scris Se poate folosi şi formatul implicit, în acest caz forma instrucţiunii fiind: PRINT *, listă_de_articole_de_scris 8.11.2.4. Instrucţiunea OPEN Instrucţiune OPEN stabileşte un canal de comunicaţie cu un fişier şi o unitate externă şi

stabileşte parametrii de comunicare. Forma instrucţiunii este următoarea: OPEN (listă_de_specificatori_de_comunicare) listă_de_specificatori_de_comunicare poate conţine următoarele articole separate prin

virgule: [UNIT =] număr_de_unitate asociază numărul de unitate cu fişierul de exploatat; ACCESS = tip_de_acces tip_de_acces poate fi unul dintre cuvintele cheie DIRECT sau SEQUENTIAL (implicit); ACTION = metoda_de_acţiune metoda_de_acţiune poate fi unul dintre READ, WRITE sau READWRITE; BLANK = tratare_spaţii_goale tratare_spaţii_goale poate fi: NULL pentru a ignora spaţiile goale din câmpurile numerice; ZERO interpretează toate spaţiile goale cu excepţia primului ca fiind zerouri;

Page 183: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 171

Observaţie: specificatorul BLANK se menţionează numai pentru fişierele conectate cu intrare/ieşire formatată. Valoarea prestabilită este NULL.

DELIM = tip_de_delimitator_de_şir tip_de_delimitator_de_şir poate fi unul dintre cuvintele cheie: APOSTROPHE – foloseşte apostroful ca delimitator de şir de caractere. Dacă într-un şir de

caractere va fi întâlnit un caracter apostrof, el va fi dublat; QUOTE – foloseşte ghilimelele ca delimitatori de şir. Dacă într-un şir de caractere va fi

întâlnit un caracter ghilimea, el va fi dublat; NONE – este prestabilit, nu sunt folosiţi delimitatori de şir; Observaţie: acest specificator se foloseşte numai la fişierele conectate pentru operaţii de

intrare/ieşire formatată şi este ignorat la fişierele pentru ieşire formatată; ERR = etichetă specifică eticheta unei ramuri de program care tratează apariţia unei erori de comunicare

descrisă de specificatorul IOSTAT; FILE = nume_de_fişier nume_de_fişier trebuie să respecte regulile din sistemul de operare cu care se lucrează; FORM = tip_de_înregistrări tip_de_înregistrări poate fi unul dintre cuvintele cheie: FORMATTED – toate înregistrările sunt formatate; UNFORMATTED – toate înregistrările sunt neformatate (valoare implicită dacă fişierul este

conectat pentru acces direct şi dacă specificatorul FORM este absent); IOSTAT = indicator_de_stare indicator_de_stare poate avea una dintre valorile: 0 dacă nu a intervenit nici o eroare; întreg pozitiv dacă a intervenit o eroare; PAD = completare completare poate avea ca valoare unul dintre cuvintele cheie: YES care produce completarea cu spaţii goale dacă listă_de_articole_de_citit conţine mai

multe articole decât conţine înregistrarea. Această valoare este prestabilită; NO dacă se impune ca înregistrarea de citit să conţină datele specificate de

listă_de_articole_de_citit şi de formatele specificate; POSITION = stare_indicator_de_poziţie stare_indicator_de_poziţie specifică poziţionarea în fişier a indicatorului de

poziţie curentă şi poate fi unul dintre cuvintele cheie: ASIS pentru menţinerea neschimbată a poziţiei (valoare prestabilită). Indicatorul de poziţie

va avea o valoare nedeterminată dacă fişierul nu este conectat; REWIND (redeschidere) poziţionează indicatorul la început de fişier; APPEND (adăugare) poziţionează indicatorul la sfârşit de fişier; Observaţie: Dacă fişierul este nou creat indicatorul de poziţie se va afla la început de fişier

indiferent de ce anume specifică POSITION; RECL = lungime_de_înregistrare lungime_de_înregistrare specifică lungimea unei înregistrări dacă accesul se face în

mod direct, sau lungimea maximă a unei înregistrări dacă accesul se face secvenţial;

Page 184: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 172

STATUS = indicator_de_stare_a_fişierului indicator_de_stare_a_fişierului poate fi una dintre valorile: OLD dacă se impune ca fişierul să existe NEW dacă se impune ca fişierul să fie unul nou UNKNOWN dacă fişierul are o stare dependentă de procesor REPLACE impune ca, dacă fişierul nu există să fie creat şi să i se atribuie starea OLD, iar

dacă fişierul există, să fie şters, creat ca fişier nou şi să i se atribuie starea OLD; SCRATCH dacă se cere să se creeze un fişier temporar care va exista numai până la

executarea instrucţiunii CLOSE sau până la încheierea programului. 8.11.2.5. Instrucţiunea CLOSE Instrucţiunea CLOSE produce închiderea comunicării (conexiunii) cu un fişier al unei

unităţi. Oricum, la terminarea execuţiei programului, comunicaţia cu fişierul se închide cu excepţia cazului când a avut terminarea programului a avut loc ca urmare a unei erori.

Forma instrucţiunii este următoarea: CLOSE (listă_specificatori_de_închidere) listă_specificatori_de_închidere conţine următoarele articole, cu aceleaşi

semnificaţii ca la instrucţiunea OPEN: [UNIT =] număr_de_unitate definit anterior de instrucţiunea OPEN IOSTAT = indicator_de_stare_I/O ERR = etichetă STATUS = indicator_de_stare_a_fişierului indicator_de_stare_a_fişierului poate avea una dintre valorile: KEEP indicând că fişierul va continua să existe şi după închiderea conexiunii. Această

valoare este prestabilită dacă fişierul a fost deschis cu valoarea lui STATUS oricare alta decât SCRATCH. Indicatorul este ignorat dacă fişierul nu există, fişierul rămânând inexistent;

DELETE indicând ştergerea fişierului după închidere. Această valoare este prestabilită dacă fişierul a fost desxchis cu STATUS=SCRATCH

8.11.2.6. Instrucţiunea INQUIRE Instrucţiunea INQUIRE este folosită pentru a cere informaţii cu privire la un fişier sau

unitate. Ea poate să fie executată înainte de, în timpul, sau după ce un fişier este conectat la o unitate. Toate valorile obţinute prin instrucţiunea INQUIRE sunt cele existente la momentul execuţiei instrucţiunii. Forma generală a instrucţiunii INQUIRE este:

INQUIRE (listă_specificatori_de_cerere) listă_specificatori_de_cerere poate fi constituită din următoarele articole

separate prin virgule: UNIT=număr_de_unitate număr_de_unitate specifică numărul unităţii pentru o interogare pe baza unităţii.

Valoarea trebuie să fie nenegativă, şi trebuie să fie unică pentru toate unităţile de program; FILE=nume_de_fişier nume_de_fişier specifică numele fişierului într-o interogare bazată pe nume de fişier. În

acest caz nu se foloseşte articolul UNIT. Invers, dacă se foloseşte UNIT nu se foloseşte FILE;

Page 185: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 173

IOSTAT=variabilă variabilă stochează starea de intrare/ieşire (0 – nici o eroare, întreg negativ pentru eroare; ERR=etichetă etichetă este eticheta ramurii de program la care se sare în cazul apariţiei unei erori; EXIST=variabilă variabilă specifică o variabilă logică care va avea valoarea .TRUE. dacă fişierul există

şi .FALSE. în caz contrar; OPENED=variabilă variabilă specifică o variabilă logică care va avea valoarea .TRUE. dacă fişierul sau

unitatea logică sunt conectate şi .FALSE. în caz contrar; NUMBER=variabilă variabilă memorează numărul unităţii ataşate fişierului, sau –1 dacă fişierul este neataşat; NAMED=variabilă variabilă specifică o variabilă logică care va avea valoarea .TRUE. dacă fişierul este

denumit sau .FALSE. în caz contrar; NAME=variabilă variabilă va conţine numele fişierului (dacă există) sau va fi nedefinită dacă fişierul nu

are nume sau nu este conectat la unitate; ACCESS=variabilă variabilă va conţine tipul de acces pentru care a fost deschis fişierul sau unitatea.

Valorile sunt SEQUENTIAL, DIRECT sau UNDEFINED dacă conexiunea nu există; SEQUENTIAL=variabilă variabilă va conţine valoarea YES, NO sau UNKNOWN după cum fişierul sau unitatea

sunt deschise pentru acces direct, sau modul de acces nu poate fi determinat; DIRECT=variabilă variabilă va conţine valoarea YES, NO sau UNKNOWN după cum fişierul sau unitatea

sunt deschise pentru acces direct sau nu, sau procesorul nu cunoaşte starea accesului; FORM=variabilă variabilă va conţine valoarea FORMATTED, UNFORMATTED în raport cu modul de

conectare la fişier sau unitate, sau UNKNOWN dacă fişierul sau unitatea nu sunt conectate; FORMATTED=variabilă variabilă va conţine YES, NO sau UNKNOWN după cum fişierul sau unitatea sunt deschise

pentru operaţii cu fişier formatat sau neformatat, sau procesorul nu cunoaşte starea acestuia; UNFORMATTED=variabilă variabilă va conţine YES, NO sau UNKNOWN după cum fişierul sau unitatea sunt deschise

pentru operaţii cu fişier neformatat sau formatat, sau procesorul nu cunoaşte starea acestuia; RECL=variabilă variabilă va conţine lungimea de înregistrare maximă pentru un fişier formatat sau

neformatat, sau va fi nedefinită dacă nu există conexiune;

Page 186: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 174

NEXTREC=variabilă În cazul fişierelor cu acces direct, variabilă va conţine cu 1 mai mult decât ultimul număr

de înregistrare citit (indicele iniţial este 1), sau va fi nedefinită dacă poziţia nu este cunoscută; BLANK=variabilă În funcţie de modul declarat de tratare a spaţiilor goale (a se vedea instrucţiunea OPEN),

variabilă va conţine 'NULL', 'ZERO' sau 'UNDEFINED' dacă fişierul nu este conectat pentru intrare/ieşire formatată sau nu este conectat de loc;

POSITION=variabilă În funcţie de modul de poziţionare al contorului de poziţie, variabilă va conţine

'REWIND', 'APPEND', 'ASIS' sau 'UNDEFINED' dacă fişierul este conectat pentru acces direct sau nu este conectat;

ACTION=variabilă În funcţie de tipul de acces la fişier , variabilă va conţine 'READ', 'WRITE',

'READWRITE' sau 'UNDEFINED' dacă fişierul nu este conectat; READ=variabilă În funcţie de modul de acces pentru citire, variabilă va conţine 'YES', 'NO' sau

'UNKNOWN' dacă procesorul nu poate determina admisibilitatea accesului pentru citire; WRITE=variabilă variabilă va conţine 'YES', 'NO' sau 'UNKNOWN' în funcţie de modul de acces la

fişier prin scriere admis, neadmis sau nedetectabil; READWRITE=variabilă variabilă va conţine 'YES', 'NO' sau 'UNKNOWN' în funcţie de modul de acces

citire/scriere în fişier admis, neadmis sau nedetectabil; DELIM=variabilă În funcţie de modul de tratare al delimitatorilor de şiruri de caractere, variabilă va

conţine 'APOSTROPHE', 'QUOTE', 'NONE' sau 'UNDEFINED' dacă fişierul nu este conectat pentru intrare/ieşire formatată sau nu este conectat de loc;

PAD=variabilă variabilă va conţine 'YES', sau 'NO' în funcţie modul stabilit pentru completare cu

spaţii goale (vezi instrucţiunea OPEN). 8.11.2.7. Instrucţiunile de poziţionare în fişier BACKSPACE şi REWIND Instrucţiunea BACKSPACE Instrucţiunea BACKSPACE are forma generală: BACKSPACE ([UNIT=] număr_unitate & [,IOSTAT=indicator_de_stare_I/O] & [,ERR=etichetă]) La execuţia instrucţiunii BACKSPACE fişierul conectat la unitatea specificată va avea contorul

de poziţie poziţionat înaintea înregistrarii precedente. Dacă nu există o înregistrare precedentă (la început de fişier) indicatorul de poziţie rămâne nemodificat. Dacă înregistrarea precedentă este sfârşitul de fişier, indicatorul va fi poziţionat înainte de înregistrarea de sfârşit de fişier. Nu se poate merge înapoi peste o înregistrare scrisă folosind formatul bazat pe o listă sau nume de listă.

Page 187: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 175

Specificatorii instrucţiunii sunt următorii: UNIT=număr_de_unitate dacă UNIT este singurul specificator menţionat, instrucţiunea are forma: BACKSPACE număr_de_unitate IOSTAT=variabilă variabilă va conţine valoarea 0 dacă operaţia a avut loc cu succes, sau o valoare

pozitivă pantru a semnala o eroare; ERR=etichetă etichetă este eticheta ramurii de program care tratează eroarea; Instrucţiunea REWIND Instrucţiunea REWIND are forma generală: REWIND ([UNIT=] număr_unitate & [,IOSTAT=indicator_de_stare_I/O] & [,ERR=etichetă]) Semnificaţiile specificatorilor din listă sunt aceleaşi ca şi la instrucţiunea BACKSPACE,

dar instrucţiunea are ca efect aducerea indicatorului de poziţie la început de fişier. §8.12. Variabile pointer şi ţinte 8.12.1. Definiţia pointerilor şi a ţintelor O variabilă pointer sau, pe scurt, un pointer, este un tip de variabilă special folosit şi de alte limbaje

(de exemplu C şi C++) al cărei rol este acela de referinţă către locaţia de memorie unde este stocată o altă variabilă. Altfel spus, pointerul nu are ca valoare asociată valoarea variabilei către care „ţinteşte” (sau către care „punctează”) ci are ca valoare asociată adresa locaţiei de memorie a variabilei „ţintă”.

Pointerii sunt folosiţi în special în operaţiile de alocare dinamică a memoriei, al căror rol este de a realiza consumul de memorie cu maximum de economie.

Pentru a defini un pointer (sau o listă de pointeri) se foloseşte declaraţia: tip, POINTER [,listă_de_atribute] :: listă_de_variabile_pointer unde: tip este tipul de dată asociată pointerului listă_de_atribute este o listă de alte atribute ale pointerului listă_de_variabile_pointer este lista variabilelor de tip pointer definite de

declaraţia curentă Pentru a defini variabile posibile a constitui ţinte ale unor pointeri se foloseşte declaraţia: tip, TARGET [,listă_de_atribute] :: listă_de_variabile unde: tip este tipul de dată al variabilelor ţintă listă_de_atribute este o listă de alte atribute ale variabilelor ţintă listă_de_variabile este lista variabilelor ţintă definite de declaraţia curentă Observaţie: tipurile de dată ale pointerilor şi variabilelor ţintă trebuie să fie aceleaşi pentru

a se asigura citirea corectă a datelor din memorie. Exemple de definiri de pointeri şi ţinte: REAL, POINTER :: pnt1 REAL, TARGET :: a, b, c În acest exemplu pointerul pnt1 este destinat să ţintească către variabile individuale de tip

real, aşa cum sunt definite ca ţinte variabilele a, b şi c.

Page 188: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 176

INTEGER, DIMENSION(:), POINTER:: pnt2 INTEGER, TARGET :: a(4), b(10) În acest exemplu pointerul pnt2 este destinat să ţintească către variabile de tip tablou cu o

singură dimensiune, de tip întreg, aşa cum sunt definite ca ţinte variabilele tablou a şi b. INTEGER, POINTER :: pnt3(:,:) INTEGER, TARGET, ALLOCATABLE :: a(:,:) În acest exemplu pointerul pnt3 este destinat să ţintească către variabila de tip tablou cu

două dimensiuni, de tip întreg, cu atributul ALLOCATABLE, deci cu posibilitatea de alocare dinamică ulterioară, aşa cum este definită ca ţintă variabila tablou bidimensional a.

8.12.2. Asocierea pointerilor cu ţintele. Dezasocierea pointerilor Se folosesc doi operatori pentru operarea cu pointerii: - Primul este operatorul de asociere, folosit sub forma: variabilă_pointer => variabilă_ţintă - Al doilea este operatorul de atribuire, sintaxa corectă de folosire fiind: variabilă_ţintă_receptoare = variabilă_pointer cu semnificaţia că variabila ţintă receptoare primeşte de la pointer valoarea unei alte

variabile ţintită de pointer printr-o operaţie de asociere anterioară. De asemenea, se poate folosi sintaxa de atribuire: variabilă_pointer =variabilă_donatoare cu semnificaţia că variabila ţintită de pointer printr-o operaţie de asociere anterioară

primeşte de la pointer valoarea variabilei donatoare. Variabila donatoare trebuie să nu fie una ţintită deoarece ţintirea ei schimbă asocierea anterioară.

Următorul exemplu explică mecanismele descrise mai sus în cazul variabilelor simple: PROGRAM manipulare_pointeri_simpli IMPLICIT NONE INTEGER, POINTER:: pnt INTEGER, TARGET :: j=5, k=7 INTEGER :: l=11 WRITE(*,*)' j k l' WRITE(*,*)'inainte ',j,k,l pnt=>j k=pnt WRITE(*,*)'Dupa k=pnt ',j,k,l pnt=l WRITE(*,*)'Dupa pnt=l ',j,k,l END PROGRAM manipulare_pointeri_simpli După execuţie programul va afişa: j k l inainte 5 7 11 dupa pnt k=pnt 5 5 11 dupa pnt pnt=l 11 5 11 În prima etapă, la asocierea pnt=>j pointerul este făcut să „vadă” ca ţintă variabila j. În următoarele două etape de operaţie pointerul pnt va vedea tot variabila j, deci ţinta nu se schimbă. La prima atribuire k=pnt variabila k va primi valoarea ţintei j, adică 5. La a doua atribuire pnt=l ţinta j va primi valoarea variabilei l, adică 11. Următorul exemplu ilustrează folosirea pointerilor pentru variabile indexate (tablouri)

unidimensionale:

Page 189: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 177

PROGRAM manipulare_pointeri_catre_tablouri IMPLICIT NONE INTEGER, DIMENSION(:), POINTER:: pnt INTEGER, TARGET :: j(2), k(2), l(2) j(1)=5; j(2)=7 k(1)=1; k(2)=2 l(1)=11; l(2)=13 write(*,*) 'ante ',j(1),j(2),k(1),k(2),l(1),l(2) pnt=>j pnt=k write(*,*)'post1 ',j(1),j(2),k(1),k(2),l(1),l(2) pnt=l write(*,*)'post2 ',j(1),j(2),k(1),k(2),l(1),l(2) END PROGRAM manipulare_pointeri_catre_tablouri Acest program este identic ca etape de operare cu programul prezentat anterior, dar

lucrează cu tablouri. După execuţie el va afişa: ante 5 7 1 2 11 13 post1 1 2 1 2 11 13 post2 11 13 1 2 11 13 Se poate observa unul dintre avantajele lucrului cu pointerii tablou, şi anume transferul

global de valori ale tablourilor printr-o singură atribuire. De altfel acest lucru este valabil şi la lucrul cu tablouri în general, fără a se face uz de pointeri.

Următorul exemplu ilustrează folosirea pointerilor către tablouri alocate dinamic: PROGRAM pointeri_tabl_dinamice IMPLICIT NONE INTEGER, DIMENSION(:), POINTER:: pnt INTEGER, TARGET, allocatable :: k(:), j(:) INTEGER i ALLOCATE(k(3),j(3)) DO i=1,3 k(i)=i END DO j=2*k WRITE(*,100) k(1),k(2),k(3),j(1),j(2),j(3) pnt=>k pnt=j WRITE(*,100) k(1),k(2),k(3),j(1),j(2),j(3) DEALLOCATE(k,j) 100 FORMAT(6I5) ALLOCATE(k(2),j(2)) DO i=1,2 k(i)=i END DO j=k+1 WRITE(*,200) k(1),k(2),j(1),j(2) pnt=>k pnt=j WRITE(*,200) k(1),k(2),j(1),j(2) DEALLOCATE(k,j) 200 FORMAT(4I5) END PROGRAM pointeri_tabl_dinamice După execuţie se obţine afişarea următoare:

Page 190: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 178

1 2 3 2 4 6 2 4 6 2 4 6 1 2 2 3 2 3 2 3

Dezasocierea pointerilor de ţintele lor se face cu instrucţiunea: NULLIFY(listă_de_pointeri) Un pointer dezasociat va ţinti către nimic. Starea unui pointer se poate testa folosind funcţia: ASSOCIATED (listă_de_pointeri [,ţintă] ) Rezultatul returnat de funcţia ASSOCIATED este unul logic, adică .TRUE. sau .FALSE. Dacă argumentul ţintă lipseşte funcţia va returna .TRUE. dacă pointerul este asociat cu o

ţintă oarecare, altfel, dacă nu este asociat cu ţinta sau a fost nulificat, va returna .FALSE. Dacă argumentul ţintă este prezent, funcţia va returna .TRUE. numai dacă toţi pointerii

listei sunt asociaţi cu ţinta în cauză. 8.12.3. Alocarea dinamică a memoriei pentru tablouri Aşa cu s-a văzut încă din exemplele de mai sus, un pointer poate fi asociat nu numai cu

variabile ţintă simple ci şi cu variabile ţintă de tip tablou cărora li se specifică numai forma (numărul de dimensiuni) dar nu şi mărimea (numerele de elemente pe dimensiunile respective). Cu alte cuvinte, compilatorul este înştiinţat numai asupra structurii generale a zonei de memorie ţintită, nu şi asupra structurii de detaliu, repectiv a spaţiului exact pe care îl va ocupa zona. Mărimea acestei zone de memorie va fi specificată folosind instrucţiunea ALLOCATE, ca în exemplul de mai jos:

REAL, POINTER :: pnt, pnt_spre_tablou(:) INTEGER :: m=20 ... ALLOCATE( pnt, pnt_spre_tablou(m) ) ... DEALLOCATE( pnt, pnt_spre_tablou ) În exemplul de mai sus pointerul pnt este unul simplu care poate ţinti o variabilă simplă,

pe când pnt_spre_tablou este un pointer care poate ţinti spre o variabilă tablou cu o singură dimensiune, Când se execută instrucţiunea ALLOCATE se specifică faptul că pnt_spre_tablou va putea ţinti o variabilă de tip tablou cu o dimensiune pe care se pot stoca 20 de elemente. La momentul când memoria folosită nu mai este necesară, se foloseşte instrucţiunea DEALLOCATE.

§8.13. Mediul PLATO3 IDE 8.13.1. Generalităţi Prescurtarea IDE provine de la Integrated Developing Environment, sau mediu integrat de

dezvoltare (a aplicaţiilor). Salford PLATO3 este un asemenea mediu, el reunind într-un singur instrument cele 3

funcţii de bază minimale ale unui instrument modern de programare: - Editorul de text; - Compilatorul; - Editorul de legături. PLATO poate genera programe simple, adică programe conţinute integral într-un singur

fişier, sau poate genera programe ale căror componente sunt conţinute în fişiere distincte (fişier sursă principal, fişiere modul, fişiere de includere). În acest din urmă caz, se lucrează cu un aşa numit proiect constând dintr-un sistem de fişiere de tipurile enumerate mai sus care,

Page 191: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 179

la încărcarea proiectului, sunt încărcate şi deschise împreună, iar prelucrarea produsului final, fişierul cod executabil, se face corelat.

8.13.2. Construirea şi rularea unui proiect Crearea unui proiect se realizează folosind meniul File/New Project care deschide cutia de

dialog New Project din figura 8.13.1. Se selectează natura proiectului dorit din lista Project Types, se stabileşte numele în cutia

de editare Name şi directorul de stocare a fişierului proiect folosind butonul Browse. După executarea acestei comenzi fereastra aplicaţiei PLATO are aspectul din figura 8.13.2. Aşa cum se observă în fereastra Project Explorer, un proiect poate conţine fişiere sursă,

fişiere de includere şi fişiere referite. Pentru adăugarea de noi componente se poate folosi meniul contextual (clic dreapta pe

articolul nod selectat). După aplicarea unui asemenea set de operaţii, un proiect poate arăta ca în figura 8.13.3.

Fişierele sursă sunt fişiere care conţin: - Fişierul care conţine programul principal şi un anumit număr de proceduri (subrutine şi funcţii); - Fişiere care conţin module (unităţi de program separate conţinând declaraţii şi proceduri)

utilizabile în diverse programe gazdă prin invocarea lor de către instrucţiunea USE;

Fig.8.13.1.

- Fişiere de includere, care conţin secvenţe de program în formă sursă (text) care pot fi invocate şi încărcate din alte unităţi din program ca şi cum s-ar afla incluse începând de la instrucţiunea de includere (INCLUDE);

- Fişiere referite, care conţin cod executabil extern cum sunt fişierele DLL (Dynamic Link Library) sau LIB.

În figura 8.13.3 fişierele componente sunt: - Programul principal conţinut în fişierul Main.f95, conţinând instrucţiunile: PROGRAM CALCUL USE FACT_DE_N INCLUDE 'DATE.INC' INTEGER K,N N=I K=FACT_N(N) write(*,*) "K!=",K END PROGRAM

Page 192: Programarea Calculatoarelor si Limbaje de Programare

Cap.8. Limbajul FORTRAN. Versiunea FTN95 180

- Fişierul modul Modul_FTN.f95, conţinând instrucţiunile: MODULE FACT_DE_N IMPLICIT NONE CONTAINS RECURSIVE INTEGER FUNCTION FACT_N(n) RESULT (rez) INTEGER n INTEGER rez if (n==0) then rez=1 else rez=n*FACT_N(n-1) end if END FUNCTION FACT_N END MODULE FACT_DE_N - Fişierul de includere DATE.INC, conţinând instrucţiunile: INTEGER :: I=5

Fig.8.13.2.

Construirea programului se poate face: - pe etape separate, apelând comanda Compile separat pe fiecare componentă, fie din

meniul Build/Compile fie din meniul contextual direct de pe eticheta (Tab-ul) fiecărei ferestre de componentă sau de pe articolul de proiect din fereastra Project Explorer, ca în figurile 8.13.4 şi, respectiv, 8.13.5, şi apoi folosind comanda Build din meniul Build.

- global, prin comanda Build/Build sau cu meniul contextual din fereastra Project explorer cu articolul nume de proiect selectat.

Page 193: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 181

Comanda Rebuild produce şi recompilarea componentelor, lucru necesar atunci când ele au suferit modificări.

Fig.8.13.3.

Fig.8.13.4. Fig.8.13.5.

Mesajele rezultate în urma compilării şi construcţiei pot fi urmărite în fereastra Output de

la baza ferestrei mediului PLATO. Rularea programului obţinut se realizează folosind comanda Build/Start Run sau butonul

Start de pe bara cu butoane Build. Mai multe despre manevrele realizabile în mediul PLATO pot fi aflate consultând meniul

Help al mediului.

Page 194: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 182

Cap.9. Limbajul AutoLISP pentru AutoCAD §9.1. Generalităţi Limbajul AutoLISP este un dialect de limbaj LISP destinat dezvoltării aplicaţiilor sub

AutoCAD. Limbajul LISP este un limbaj care are ca unică structură lista. Denumirea limbajului derivă

din LISt Processor (procesor de listă) definind sintetic filozofia acestui limbaj. În LISP lista poate fi atât stoc de date cât şi funcţie. Datorită acestei dualităţi, limbajul

posedă însuşirea unică de a se putea automodifica în timpul execuţiei. Limbajul AutoLISP este destinat scrierii de programe executabile în regim de interpretor.

Din acest motiv el nu este la fel de rapid ca programele scrise în limbaje compilabile şi, ca urmare, este mai raţional să fie folosit pentru a transmite comenzi interpretorului de comenzi al AutoCAD-ului, astfel încât, pe cât mai mult posibil, acesta să lucreze cu facilităţile sale proprii care sunt de fapt module de program compilate şi, implicit, mult mai rapide.

§9.2. Lista ca structură de bază în AutoLISP. Funcţii Atât funcţiile cât şi datele manipulate sub AutoLISP au structură de listă. Acest aspect al

AutoLISP-ului îl face deosebit de flexibil deoarece funcţiile pot fi construite nu numai de către programator ci şi de către program pe baza unor reguli de algoritmizare.

9.2.1. Lista O listă este un şir de aşa-numite entităţi (atomi, date, liste, funcţii sau expresii) desemnate

prin simboluri incluse între paranteze, după cum urmează: (e1 e2 … en) Fiecare dintre aceste entităţi poate fi, la rândul ei, o listă, ceea ce conduce la o structură

arborescentă, ca în figura 9.2.1.

(e1 e2 … en)

(e11 e12 … e1k) (e21 e22 … e2j) (en1 en2 … enm)

(e211 e212 … e21q)

Fig.9.2.1.

Este important de reţinut că aceste liste pot fi eterogene (constituite din entităţi de tipuri diferite). De exemplu, fie lista TRIUNGHI conţinând datele care definesc cele trei vârfuri ale unui

triunghi: TRIUNGHI ≡ (V1 V2 V3) V1, V2 şi V3 sunt la rândul lor liste care conţin caracterul de notare al vârfului şi lista

coordonatelor sale x, y şi z: V1 ≡ (“A” CV1) V2 ≡ (“B” CV2) V3 ≡ (“C” CV3) CV1 ≡ (0 0 0) CV2 ≡ (100 0 0) CV3 ≡ (0 100 0)

Page 195: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 183

9.2.2. Funcţia Spre deosebire de lista de date, funcţia este constituită dintr-un şir de entităţi dintre care

primul este numele funcţiei iar restul sunt argumentele ei. De exemplu: (command “LINE” ‘(0 0 0) ‘(100 0 0) ‘(0 100 0) “C”) constituie o funcţie care transmite interpretorului de comenzi din AutoCAD comanda de

trasare a segmentelor componente ale unui triunghi cu vârfurile în punctele definite de sublistele argumente. Ultimul argument, adică şirul de caractere “C” este directiva de închidere a triunghiului.

Funcţiile din AutoLISP sunt de trei tipuri principale: a. Funcţii standard (cum este funcţia command din exemplul de mai sus) conţinute de

AutoLISP la iniţializare; b. Funcţii definite de utilizator care pot fi create în scopul realizării de facilităţi noi. În

acest scop se foloseşte funcţia definitoare de funcţii DEFUN; c. Funcţii de comandă AutoCAD definite de utilizator. Acestea sunt tot funcţii definite

de utilizator dar care sunt recunoscute şi de către interpretorul de comenzi AutoCAD. Acemenea funcţii se crează prin prefixarea numelui funcţiei cu caracterele “C:”. Pe această cale, repertoriul de comenzi din AutoCAD poate fi îmbogăţit cu noi comenzi.

Tipuri de argumente ale unei funcţii AutoLISP Argumentele unei funcţii AutoLISP sunt de două tipuri: - argumente de intrare (sau formale); - argumente interne (sau variabile locale). Când se defineşte o funcţie prin intermediul funcţiei DEFUN, argumentele se include în

interiorul unei liste de argumente. Pentru înţelegere, vom lua exemplul unei funcţii simple care calculează media a două

valori. Definirea funcţiei se face astfel:

(defun MID (a b / c) (setq c (/ (+ a b) 2) d (+ c 2))

c

) Numele funcţiei este MID. Lista de argumente (a b / c) conţine două câmpuri: - câmpul argumentelor formale a şi b. Simbolurile a şi b au valabilitate numai în interiorul

funcţiei şi reprezintă valorile argumentelor transmise la apelul funcţiei sub forma (MID u v), unde u şi v sunt argumentele de apel;

- câmpul argumentelor locale conţine aici numai simbolul c. Argumentele menţionate în acest câmp sunt folosite numai în interiorul funcţiei şi nu sunt vizibile în exteriorul acesteia (alocarea de memorie pentru aceste argumente este ştearsă la terminarea execuţiei funcţiei).

Dacă în interiorul funcţiei apar simboluri neincluse în nici unul dintre câmpurile listei de argumente, aceste simboluri reprezintă variabile globale, vizibile atât din interiorul cât şi din exteriorul funcţiei, aşa cum este variabila cu simbolul d.

Caracterul / joacă rolul de separator de câmpuri de argumente. În corpul funcţiei este folosită funcţia de atribuire cu “îngheţarea” evaluării setq. Forma

acestei funcţii este:

(setq acceptor1 donator1 acceptor2 donator2 … acceptorn donatorn) Aici există o două perechi acceptor-donator, astfel:

Page 196: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 184

Acceptor1 este variabila locală c iar donator1 este lista funcţie (/ (+ a b) 2); Acceptor2 este variabila globală d iar donator2 este lista lista funcţie (+ c 2). Noţiunea de “îngheţare” se referă la blocarea evaluării simbolului acceptorului, astfel încât,

orice valoare ar fi avut anterior, el primeşte o nouă valoare provenită din evaluarea donatorului. Au fost folosite funcţiile:

(/ deînpărţit înpărţitor) şi (+ număr1 număr2). Conform convenţiei LISP, numele funcţiilor de mai sus sunt operatorii / şi + , celelalte

simboluri din listă fiind operanzii. Modul de utilizare a funcţiei MID definită mai sus rezultă din următorul exemplu, extras

dintr-un program: (setq u 1 v 2 d 0) atribuie simbolurilor u, v şi d valorile 1, 2 şi 0 (setq f (mid u v)) atribuie lui f valoarea medie a lui u şi v

După execuţia ultimei funcţii setq vom constata că f primeşte valoarea (1 + 2)/2 =1.5, iar d nu mai are valoarea 0 ci valoarea (1.5 + 2) = 3.5. Acest lucru se întâmplă deoarece d este variabilă globală.

Dacă în loc de (setq f (mid u v)) am fi scris numai (mid u v), rezultatul 1.5 ar fi fost pierdut nefiind preluat de nici un alt simbol, singurul rezultat conservat fiind valoarea 3.5 atribuită lui d. Ca şi în limbajul C acest efect poartă denumirea de efect lateral şi, dacă nu este urmărit în mod special, este recomandabil să fie evitat prin controlul strict al vizibilităţii variabilelor (programatorul trebuie să ştie exact care sunt variabilele locale şi care cele globale).

Rămâne o întrebare: de ce, în funcţia de definire a funcţiei MID a fost scris ca ultim argument simbolul c?

Pentru a înţelege, trebuie expus ciclul funcţional de bază al limbajului LISP, aşa cum urmează. §9.3. Evaluarea în AutoLISP 9.3.1. REP – ciclul de funcţional bază în AutoLISP REP este prescurtarea de la Read - Eval – Print, adică succesiunea etapelor de lucru în

AutoLISP: R – citeşte simbolul E – evaluează simbolul prin valoarea atribuită lui P – tipăreşte (returnează) rezultatul ultimei evaluări. Conform acestei succesiuni, o funcţie va returna întotdeauna numai rezultatul ultimei

evaluări, indiferent câte alte evaluări ar mai fi avut loc anterior în interiorul ei. Din acest motiv, pentru ca funcţia să returneze media argumentelor a şi b, adică c, acesta a

trebuit să fie scris ca ultim argument al funcţiei (defun MID …). Altfel, ultima evaluare ar fi fost aceea dată de lista (+ c 2), adică cu totul altceva decât se urmărea.

Eliminând efectul lateral cauzat de invocarea simbolului d în corpul funcţiei defun şi folosind judicios ciclul REP, se poate scrie o variantă mai simplă şi mai robustă a funcţiei de mai sus, astfel:

(defun MID (a b /)

(/ (+ a b) 2) )

În general, cu riscul risipei de spaţiu, preferăm scrierea pe linii separate, deşi am fi putut scrie totul pe un singur rând:

(defun MID (a b /) (/ (+ a b) 2))

Prima modalitate este preferabilă, permiţând scrierea conformă cu regulile de structurare şi uşurând efortul de a controla corectitudinea închiderii parantezelor, esenţială pentru LISP.

Page 197: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 185

9.3.2. Evaluarea simbolurilor Pentru a aprecia corect efectele obţinute cu un program AutoLISP trebuie cunoscute

regulile după care are loc acţiunea de evaluare a simbolurilor folosite în program. Acestea sunt următoarele:

- Evaluarea unei date de tip valoare numerică sau şir de caractere se face prin ea însăşi; - Un simbol se evaluează prin ultima valoare care i-a fost atribuită; - O listă se evaluează în concordanţă cu primul ei argument care reprezintă un nume de

funcţie. Dacă acest argument nu a fost definit ca nume de funcţie, AutoLISP semnalează eroare şi opreşte execuţia.

De exemplu, dacă nu a fost folosită funcţia DEFUN pentru definirea funcţiei mid din exemplul anterior, la apelul:

(mid 2 5)

în loc de rezultatul 3.5 aşteptat, AutoLISP va emite mesajul: error: null function §9.4. Convenţii sintactice în AutoLISP La scrierea unui program AutoLISP trebuie să se ţină seama de următoarele reguli sintactice: - Numele unui simbol se poate scrie folosind orice caractere, cu excepţia următoarelor: ( ) . ‘ “ ; şi caracterul spaţiu - Numele simbolurilor trebuie să fie separate prin cel puţin un spaţiu. - O expresie, funcţie sau listă poate fi scrisă pe oricâte linii, dacă este necesar. Totuşi, nu se

trece la o altă linie în cuprinsul unui şir de caractere încadrat între ghilimele. În acest caz caracterul ENTER nu este filtrat (ignorat). Dacă o astfel de trecere la linie nouă are loc în cuprinsul unui şir de caractere de afişat ca mesaj, respectivul mesaj va apare fragmentat pe linii succesive exact în locul unde, în program a avut loc trecerea la o nouă linie. Dacă şirul de caractere reprezintă o comandă transmisă interpretorului de comenzi AutoCAD, prezenţa caracterului ENTER va perturba succesiunea normală aparametrilor comenzii şi rezultatul va fi o execuţie defectuoasă sau imprevizibilă.

- Valorile întregi sunt cuprinse în intervalul –32768…+32767; - Valorile reale se exprimă în forma parte_întreagă.parte_zecimală sau în format E; - Un şir de caractere este incadrat de o pereche de ghilimele, de exemplu “SIR DE

CARACTERE”; - În interiorul unui şir de caractere caracterul \ se foloseşte pentru desemnarea de caractere

de control, astfel: \e pentru caracterul ESCAPE \n pentru salt la linie nouă \r pentru caracterul ENTER \t pentru caracterul TAB De asemenea, se folosesc combinaţiile: \\ pentru caracterul spaţiu \” pentru caracterul “ - Caracterul apostrof ‘ se foloseşte ca abreviaţie a funcţiei QUOTE (îngheţarea evaluării). - O linie care începe cu caracterul ; este complet ignorată fiind considerată comentariu. §9.5. Funcţii primitive în AutoLISP Funcţiile primite constituie un set de funcţii standard care pot fi utilizate ca set minimal de

funcţii. Acestea sunt:

Page 198: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 186

(CONS nou_element_prim listă) Această funcţie adaugă un nou element la începutul unei liste. De exemplu, fie lista l≡(b c d). Atunci, funcţia: (cons a l) produce lista l≡(a b c d). Dacă, în loc de o listă, al doilea argument al funcţiei CONS este un atom, funcţia

returnează o “pereche cu punct”, astfel: (setq a 1 b 2) (cons a b)

produce lista (1 . 2)

(CAR listă) Această funcţie extrage primul element al listei. De exemplu, fie lista l≡(b c d). Atunci,

funcţia: (car l)

produce ca rezultat b. (CDR listă) Această funcţie returnează o listă căreia îi lipseşte primul argument. De exemplu, fie lista l≡(b c d). Atunci, funcţia:

(cdr l) returnează ca rezultat lista (c d). (QUOTE expresie) Această funcţie blochează (îngheaţă) evaluarea simbolului expresie şi îl returnează

neevaluat. Sintaxa prescurtată a acestei funcţii este ‘expresie. De exemplu: (quote a) sau echivalent ‘a

returnează simbolul a (quote a b) sau echivalent ‘(a b)

returnează lista (a b) (SET simbol expresie) Această funcţie evaluează expresie, evaluează simbol, şi apoi atribuie valoarea de evaluare

a expresiei valorii evaluate a lui simbol. De exemplu, să presupunem că am atribuit simbolului b valoarea simbol a, folosind funcţia: (setq b ‘a)

Atunci:

(set b 10) îl evaluează pe 10 prin el însuşi, produce a prin evaluarea lui b şi atribuie lui a valoarea 10. Dacă acum scriem funcţia:

(eval a) obţinem ca rezultat 10. În schimb, dacă am fi scris: (setq b 2) şi apoi: (setq b 10) am fi obţinut mesajul de eroare:

Page 199: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 187

error: bad argument type deoarece s-ar fi încercat atribuirea valorii constante 10 nu unui simbol care reprezintă o

locaţie de memorie care poate stoca o valoare ci unei alte valori constante, şi anume 2. (SETQ simbol expresie) este echivalent cu

(set (quote simbol) expresie) Această funcţie evaluează expresie, blochează evaluarea lui simbol şi atribuie simbolului

neevaluat valoarea rezultată din evaluarea expresiei. De exemplu: (setq a 9) atribuie valoarea 9 simbolului a.

Dacă s-ar scrie: (setq a 1) (setq (eval a) 9)

ar rezulta o eroare la fel ca mai sus, deoarece s-ar încerca atribuirea valorii 9 valorii 1. În schimb, scriind:

(setq a ‘b) (setq (eval a) 9)

lucrurile vor decurge normal producând atribuirea valorii 9 simbolului b. (LIST e1 e2 … en) Această funcţie produce o listă compusă din valorile de evaluare ale elementelor e1, e2, …

en. De exemplu: (setq a 1 b “doi” c ‘d) (list a b c)

produce lista (1 “doi” d)

unde simbolul d este neevaluat. (APPEND lista1 lista2 … listan) Această funcţie alipeşte elementele neevaluate ale listelor lista1, lista2, … listan,

producând o nouă listă. De exemplu, fie secvenţa de program:

(setq a 1 b “W” c 2.3 d “SIR”) (setq l1 (list a b) l2 (list c d) l3 (list a l2))

va avea ca efect producerea listelor: l1≡(1 “W”) l2≡(2.3 “SIR”) l3≡(1 (2.3 “SIR”)) Atunci:

(setq lap (append l1 l2 l3)) va produce lista: lap≡(1 “W” 2.3 “SIR” (2.3 “SIR”))

§9.6. Predicate de bază în AutoLISP Un predicat este o funcţie care realizează un test şi produce un rezultat logic (T pentru

TRUE şi NIL ca echivalent al lui FALSE din alte limbaje). AutoLISP lucrează cu următoarele predicate:

Page 200: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 188

(ATOM simbol) Un atom este o entitate AutoLISP care nu mai referă alte componente (nu este o listă, sau,

conform terminologiei grafurilor arborescente este frunză de arbore şi nu nod). Funcţia ATOM produce rezultat T dacă simbol este un atom AutoLISP şi NIL în caz

contrar. De exemplu: (atom 1) produce rezultatul T pentru că 1 este o entitate constantă; (atom lap) produce rezultatul nil pentru că lap este listă (a se vedea exemplul de mai sus); (atom nil) produce rezultatul T pentru că nil este o constantă logică.

(EQUAL e1 e2) Această funcţie testează dacă două expresii sunt identice. De exemplu, scriind:

(setq e1 ‘(1 2 3) e2 ‘(1 2 3) e3 ‘(1 5 2)) (equal e1 e2) produce rezultat T, iar (equal e1 e3) produce rezultat nil.

(NULL simbol) Funcţia testează lipsa referinţei unui conţinut de către simbol, caz în care produce T, altfel

produce NIL. De exemplu: (setq a “SIR” b 1.2 c nil) (null a) produce nil (null b) produce nil (null c) produce T.

(MEMBER simbol listă) Această funcţie testează dacă valoarea evaluată a simbolului se regăseşte printre membrii

listei. Rezultatul returnat este o sublistă care începe de la prima apariţie a valorii de evaluare a lui simbol şi continuă până la capăt, sau NIL în caz contrar.

De exemplu, considerând lista lap din exemplul de la funcţia APPEND, se poate scrie: (member 2.3 lap) produce ca rezultat sublista (2.3 “SIR” (2.3 “SIR”)) (member “X” lap) produce nil. (NUMBERP simbol) Această funcţie testează dacă rezultatul evaluării lui simbol este un număr şi, în acest caz,

returnează T, altfel returnează NIL. De exemplu, considerând lista: lap≡(1 “W” 2.3 “SIR” (2.3 “SIR”))

şi scriind: (numberp (car lap)) se returnează T deoarece primul element al listei lap este atomul

numeric 1, pe când: (numberp (cdr lap)) va returna NIL deoarece (cdr lap) este sublista (“W” 2.3 “SIR” (2.3

“SIR”)) şi nu un număr. (ZEROP simbol) Această funcţie returnează T dacă rezultatul evaluării lui simbol este o valoare numerică

nulă, sau NIL în caz contrar. De exemplu:

(setq a 1) (zerop a) returnează NIL (zerop (- a 1)) returnează T

Page 201: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 189

(MINUSP simbol) Această funcţie returnează T dacă rezultatul evaluării lui simbol este un număr egal cu

zero, sau NIL în caz contrar. De exemplu:

(setq a 1) (minusp a) returnează NIL (minusp (- a 2)) returnează T.

(LISTP simbol) Această funcţie returnează T dacă rezultatul evaluării lui simbol este o listă, sau NIL în caz contrar. De exemplu, considerând lista lap de mai sus:

(listp lap) returnează T (list (car lap)) returnează NIL.

§9.7. Funcţii de test logic în AutoLISP AutoLISP foloseşte următoarele funcţii de test logic: (NOT simbol) Această funcţie returnează T dacă simbol se evaluează prin NIL, sau NIL în caz contrar.

De exemplu, scriind: (setq a 1 b nil) (not a) returnează NIL (not b) returnează T.

(AND e1 e2 … en) Această funcţie returnează NIL dacă în cursul evaluării de la stânga la dreapta a expresiilor

e1, e2, …, en, a fost întâlnită o expresie care, prin evaluare, produce un rezultat NIL. Evaluarea se opreşte imediat ce a fost întâlnită prima expresie evaluată prin NIL, fără a le mai evalua şi pe celelalte. Dacă toate expresiile sunt diferite de NIL este returnat rezultatul T.

De exemplu, considerând atribuirile de mai sus pentru a şi b: (and a b) returnează NIL (and a (not b)) returnează T.

(OR e1 e2 … en) Această funcţie returnează T dacă în cursul evaluării de la stânga la dreapta a expresiilor

e1, e2, …, en, a fost întâlnită o expresie care este evaluată prin T. Evaluarea se opreşte imediat ce a fost întâlnită o asemenea expresie, fără a le mai evalua şi pe celelalte. Dacă, prin evaluare, nici o expresie nu produce T, este returnat rezultatul NIL.

De exemplu, considerând atribuirile de mai sus pentru a şi b: (or a b) returnează T (or (not a) b) returnează NIL.

§9.8. Funcţiile READ şi EVAL AutoLISP are posibilitatea de a transforma şiruri de caractere în simboluri şi de a le evalua.

Acest lucru se realizează prin intermediul a două funcţii: (READ “expresie”) Această funcţie citeşte şirul de caractere “expresie” şi returnează simbolul expresie

neevaluat.

Page 202: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 190

De exemplu: (read “(+ 2 1)”) returnează ‘(+ 2 1)

(EVAL expresie) Această funcţie returnează valoarea evaluată a expresiei. De exemplu:

(eval ‘(+ 2 1)) returnează 3 §9.9. Funcţii alternativă AutoLISP foloseşte următoarele funcţii alternativă: (IF expresie_de_test expresie_da [expresie_nu]) Această funcţie evaluează expresie_de_test. Dacă rezultatul acestei evaluări este diferit de

nil atunci se evaluează expresie_da. Dacă expresie_de_test este nil este evaluată expresie_nu dacă aceasta este prezentă, iar dacă nu, funcţia if se încheie fără efect.

(COND (expresie_de_test_1 expresie_1) (expresie_de_test_2 expresie_2)

… (expresie_de_test_n expresie_n)

) Această funcţie evaluează pe rând expresiile expresie_de_test_j până când o întâlneşte pe

prima care este diferită de nil şi evaluează expresia expresie_j corespunzătoare. Se poate construi o alternativă default (ca în limbajul C la instrucţiunea switch), astfel: (COND … (T expresie_prestabilită) ) Exemplu de folosire a funcţiilor alternativă:

(setq a 1) (if (< a 0) t) va returna nil (efect identic cu minusp) (cond ((< a 0) “negativ”) ((= a 0) “zero”) ((> a 0) “pozitiv”) ) va returna şirul de caractere “pozitiv”

§9.10. Expresii ciclice AutoLISP foloseşte următoarele funcţii ciclice: (WHILE expresie_de_test expresie_1 expresie_2 … expresie_n) Această funcţie evaluează expresiile expresie_1 … expresie_n atât timp cât

expresie_de_test este diferită de nil. De exemplu: (setq i 1 f 1) (while (< i 6) (setq f (* f i) i (1+ i))) returnează ca rezultat f=5!

(REPEAT număr expresie_1 expresie_2 … expresie_n) Această funcţie repetă evaluarea expresiilor expresie_1 … expresie_n de număr ori. De

exemplu: (setq prod 1 baza 2) (repeat 5 (setq prod (* prod baza))) returnează ca rezultat prod=25

Page 203: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 191

§9.11. Funcţia program (PROGN expresie_1 expresie_2 … expresie_n) Această funcţie este folosită în acele funcţii care acceptă un singur argument specific, ca de

exemplu IF şi COND, atunci când este nevoie, totuşi, să se efectueze o succesiune de evaluări. Funcţia returnează ca rezultat ultima evaluare efectuată (pe aceea a lui expresie_n).

În cazul funcţiei IF, folosirea funcţiei progn conduce la o structură de forma: (if test (progn (…) … (…) ) (progn (…)… (…))) §9.12. Funcţii de test numeric Funcţiile de test numeric folosite de AutoLISP sunt următoarele: (= en1 en2 … enn) Această funcţie evaluează expresiile numerice en1, en2, …, enn, în ordine de la stânga la

dreapta. Imediat ce este obţinută o evaluare care produce un rezultat cu valoare diferită de en1, evaluarea este oprită (celelalte expresii nu mai sunt evaluate) şi este returnat rezultatul nil. Dacă toate expresiile numerice au fost evaluate şi au fost egale cu en1 este returnat ca rezultat T.

(/= en1 en2 … enn) Această funcţie evaluează expresiile numerice en1 … enn, în ordine de la stânga la dreapta

şi returnează nil la întâlnirea primei evaluări care produce un rezultat de egalitate cu oricare dintre expresiile evaluate anterior, oprind evaluarea celorlalte expresii. Dacă evaluarea tuturor expresiilor a produs rezultate diferite, este returnat T.

(< en1 en2 … enn) Această funcţie evaluează expresiile numerice en1 … enn, în ordine de la stânga la dreapta

şi returnează nil la întâlnirea primei evaluări care produce un rezultat mai mic sau egal cu evaluarea anterioară, oprind evaluarea celorlalte expresii. Dacă toate evaluările au produs rezultate care sunt strict crescătoare, este returnat T.

(<= en1 en2 … enn) Această funcţie evaluează expresiile numerice en1 … enn, în ordine de la stânga la dreapta şi returnează

nil la întâlnirea primei evaluări care produce un rezultat mai mic decât evaluarea anterioară, oprind evaluarea celorlalte expresii. Dacă toate evaluările au produs rezultate care sunt crescătoare, este returnat T.

(> en1 en2 … enn) Această funcţie evaluează expresiile numerice en1 … enn, în ordine de la stânga la dreapta

şi returnează nil la întâlnirea primei evaluări care produce un rezultat mai mare sau egal cu evaluarea anterioară, oprind evaluarea celorlalte expresii. Dacă toate evaluările au produs rezultate care sunt strict descrescătoare, este returnat T.

(>= en1 en2 … enn) Această funcţie evaluează expresiile numerice en1 … enn, în ordine de la stânga la dreapta

şi returnează nil la întâlnirea primei evaluări care produce un rezultat mai mare decât evaluarea anterioară, oprind evaluarea celorlalte expresii. Dacă toate evaluările au produs rezultate care sunt descrescătoare, este returnat T.

§9.13. Funcţii de prelucrare a listelor Fiind un limbaj de prelucrare de liste, AutoLISP foloseşte o serie de funcţii destinate

acestui scop, după cum urmează:

Page 204: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 192

(CXXXXR listă) În funcţia de mai sus avem de a face cu o notaţie generică, X putând fi A sau D, rezultând

combinaţii de funcţii CAR şi CDR până la nivelul 4. De exemplu: (CADR (list a b c d)) produce acelaşi rezultat ca şi (CAR (CDR (list a b c d))) adică

evaluarea simbolului b. (REVERSE listă) Această funcţie returnează o listă inversată. De exemplu: (reverse (list (list a b) c (list d e f) g h)) returnează lista (h g (d e f) c (a b)) Se observă din exemplul de mai sus că sublistele interne sunt tratate ca simple argumente

nefiind afectate de inversare. (ASSOC articol listă_asociativă) Pentru a înţelege modul de lucru al acestei funcţii reamintim efectul funcţiei CONS: când

ambele argumente sunt atomi funcţia returnează o pereche cu punct. O listă asociativă este o listă având ca elemente subliste formate din perechi cu punct de

tipul (a . b), sau asociaţii. Dacă articol există în interiorul unei subliste a listei asociative, atunci funcţia ASSOC

returnează prima pereche cu punct întâlnită, care conţine argumentul articol, ignorând celelalte subliste care urmează acesteia (chiar dacă printre ele se mai găsesc şi altele care conţin articolul). De exemplu:

(setq l (list (cons ‘c 1) (cons ‘a 2) (cons ‘a 3) (cons ‘b 2))) (assoc ‘a l) returnează sublista (a . 2), aceasta fiind prima întâlnită care conţine atomul a. (NTH expresie_numerică listă) Această funcţie extrage din listă elementul cu indicele de ordine egal cu

expresie_numerică, indicierea fiind considerată începând de la 0. De exemplu: (setq l1 ‘(a b c d) l2 ‘((a b c) d)) (nth 1 l1) returnează b (nth 0 l2) returnează (a b c).

(LAST listă) Această funcţie returnează ultimul element al listei. De exemplu:

(setq l1 ‘(a b c d)) (last l1) returnează d.

(LENGTH listă) Această funcţie returnează o valoare numerică egală cu lungimea listei (numărul de

argumente ale listei). De exemplu: (setq l1 ‘(a b c d) l2 ‘((a b c) d)) (length l1) returnează 4 (length l2) returnează 2. (SUBST articol_nou articol_vechi listă) Această funcţie substituie toate apariţiile în listă a lui articol_vechi cu articol_nou. De exemplu: (setq l (list 2 1 1 5)) (setq l (subst 3 1 l)) modifică lista l la forma (2 3 3 5).

§9.14. Funcţii numerice În scopul facilitării calculelor necesare într-un algoritm, AutoLISP pune la dispoziţia

programatorului următoarele funcţii de calcul numeric:

Page 205: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 193

(+ en1 en2 … enn) Această funcţie evaluează expresiile numerice en1, …, enn şi returnează suma valorilor

lor. De exemplu: (+ 1 7 3) returnează 11. (- en1 en2 … enn) Această funcţie scade din en1 valorile lui en2, …, enn. De exemplu: (- 7 3 1) returnează 3. (* en1 en2 … enn) Această funcţie returnează produsul valorilor expresiilor en1, …, enn. De exemplu: (* 2 3 4) returnează 24. (/ en1 en2 … enn) Această funcţie împarte valoarea expresiei en1, pe rând, la en2, …, enn. De exemplu: (/ 24 4 3) returnează 2. (1+ en) Această funcţie realizează incrementarea valorii expresiei numerice en. De exemplu: (setq a 5) (1+ a) returnează 6. (1- en) Această funcţie realizează decrementarea valorii expresiei numerice en. De exemplu: (setq a 5 b (1- a)) returnează 4 ca valoare atribuită lui b. (ABS en) Această funcţie returnează valoarea absolută a valorii de evaluare a expresiei en. De exemplu: (abs –3) returnează 3. (EXPT bază exponent) Această funcţie returnează valoarea bazei ridicată la puterea exponent. De exemplu: (expt 2 3) returnează 8 (EXP en) Această funcţie returnează valoarea numărului natural e ridicat la puterea dată de evaluarea

expresiei numerice en. (SQRT en) Această funcţie returnează rădăcina pătrată a valorii expresiei numerice en. (SIN en) Această funcţie returnează sinusul valorii expresiei numerice en considerată în radiani. De

exemplu: (sin (/ pi 6.0)) returnează valoarea 0.5. Observaţie: simbolul pi este recunoscut de AutoLISP ca valoare a numărului π. (COS en) Această funcţie returnează cosinusul valorii expresiei numerice en considerată în radiani.

De exemplu:

Page 206: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 194

(cos (/ pi 3.0)) returnează valoarea 0.5. (ATAN en1 [en2]) Această funcţie returnează arcul tangentei valorii en1, sau, dacă argumentul en2 este

prezent, arcul tangentei valorii en1/en2, în intervalul - π … + π. (LOG en) Această funcţie returnează logaritmul natural al valorii expresiei en. (FIX en) Această funcţie trunchează valoarea expresiei numerice en la întregul cel mai apropiat. De

exemplu: (fix 2.6) returnează 2. (FLOAT en) Această funcţie converteşte valoarea expresiei numerice en de la număr întreg la număr

real. De exemplu: (float 2) returnează 2.0

§9.15. Comenzi definite de utilizator Utilizatorul îşi poate defini comenzile proprii folosind funcţia DEFUN, astfel: (defun C:comandă_nouă (/ argloc1 argloc2 … arglocn) …) Aşadar, o funcţie definită de utilizator cu scopul de a fi recunoscută ca o comandă nouă de

către interpretorul de comenzi din AutoCAD, trebuie să aibă numele prefixat de caracterele “C:”.

Se observă o caracteristică întâlnită şi în alte limbaje, ca de exemplu în Visual Basic la crearea de macrocomenzi, şi anume, funcţia nou creată cu rolul de a servi drept comandă nu are parametri de intrare (câmpul argumentelor formale al listei de argumente este vid). Motivul acestei caracteristici este evident: pentru uşurinţa manipulării, o comandă este invocată ca un simplu nume, neexistând posibilitatea de a se transmite şi parametri.

De exemplu: (defun c:tri () (command “line” ‘(0 0) ‘(2 0) ‘(1 2) “C”) )

Această funcţie defineşte o comandă nouă cu numele TRI. Scriind acest nume ca linie de comandă AutoCAD, programul va desena un triunghi isoscel cu vârfurile în punctele de coordonate 0,0, 2,0 şi 1,2.

§9.16. Comunicarea prin AutoLISP AutoLISP permite comunicarea cu mediul de aplicaţie AutoCAD (în principal cu

interpretorul de comenzi al acestuia, dar şi cu alte facilităţi), folosind următoarele categorii de funcţii:

9.16.1. Funcţii de conversie valorică Pentru a opera conversia valorilor de diferite tipuri AutoLISP foloseşte funcţiile următoare: (ANGTOS unghi [mod [precizie]]) Această funcţie converteşte valoarea argumentului unghi exprimat în radiani într-un şir de

caractere.

Page 207: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 195

Argumentul mod îndeplineşte rolul variabilei de sistem AUNITS din AutoCAD, care stabileşte unităţile de exprimare a unghiurilor.

Argumentul precizie îndeplineşte rolul variabilei de sistem AUPREC din AutoCAD, care stabileşte precizia de exprimare a unghiurilor.

Dacă mod şi precizie sunt omise, conversia este făcută conform stării variabilelor de sistem menţionate. Dacă argumentele sunt menţionate, sunt folosite următoarele valori şi semnificaţii:

Pentru argumentul mod 0 grade sexagesimale exprimate cu punct zecimal 1 grade minute secunde 2 grade centesimale 3 radiani 4 unităţi de navigaţie De exemplu: (setq p1 ‘(5.0 1.33) p2 ‘(2.4 1.33) a (angle p1 p2)) (angtos a 0 0) returnează “180” (angtos a 0 4) returnează “180.0000” (angtos a 1 4) returnează “180d0’0”” (angtos a 4 2) returnează “W”. (ANGTOF şir [mod]) Această funcţie converteşte argumentul de tip şir de caractere şir reprezentând un unghi într-o

valoare reală exprimată în radiani. Modul în care este interpretat şirul de caractere depinde de argumentul mod care, ca şi la funcţia ANGTOS, are aceeaşi semnificaţie. De exemplu:

(angtof “180d0’0\”” 1) returnează valoarea 3.14159.

(ATOI şir) Această funcţie converteşte un şir de caractere ASCII în număr întreg. De exemplu: (atoi “2”) returnează 2 (atoi “2.3”) returnează 2.

(ATOF şir) Această funcţie converteşte un şir de caractere ASCII în număr real. De exemplu: (atof “2”) returnează 2.0 (atof “2.3”) returnează 2.3. (ITOA eni) Această funcţie converteşte expresia numerică întreagă eni în şir de caractere ASCII. De

exemplu: (itoa 2) returnează “2” (itoa 2.3) produce mesajul error: bad argument type. (RTOS enr) Această funcţie converteşte expresia numerică reală enr în şir de caractere. De exemplu: (rtos 2) returnează “2.0000” (rtos 2.3) returnează “2.3000”. 9.16.2. Funcţii de operare asupra şirurilor de caractere Operarea asupra valorilor de tip şir de caractere se realizează cu funcţiile următoare:

(STRCAT şir1 şir2 … şirn) Această funcţie leagă (concatenează) într-un singur şir de caractere şirurile şir1, şir2, …

Page 208: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 196

şirn. De exemplu: (setq disp “C:” dir1 “Alfa” dir2 “Beta” sep “\\”) (setq cale (strcat disp sep dir1 sep dir2)) atribuie simbolului cale valoarea şir de caractere

“C:\\Alfa\\Beta”. (STRLEN şir) Această funcţie returnează o valoare numerică întreagă reprezentând numărul de caractere

din şir. De exemplu: (strlen “Abcd”) returnează 4. (STRCASE şir [mod]) Această funcţie converteşte argumentul şir de caractere într-o altă formă determinată de

valoarea argumentului mod. Dacă mod este prezent şi este diferit de nil, caracterele sunt convertite în litere mici, altfel

sunt convertite în litere mari. (strcase “Abcd”) sau (strcase “Abcd” nil) returnează “ABCD” (strcase “Abcd” t) returnează “abcd”. (SUBSTR şir început [lungime]) Această funcţie extrage din argumentul şir un subşir începând de la caracterul de indice

egal cu valoarea argumentului numeric întreg început şi atâtea caractere câte indică argumentul numeric întreg lungime. Dacă lungime este omis, sau dacă este mai mare decât restul de caractere rămase, subşirul este extras până la capăt. De exemplu:

(substr “ABCD” 2 2) returnează “BC” (substr “ABCD” 2) returnează “BCD” (substr “ABCD” 2 5) returnează “BCD”. 9.16.3. Funcţii de intrare/ieşire Operaţiile de intrare/ieşire din AutoLISP se realizează cu funcţiile următoare: (OPEN nume_fişier mod) Această funcţie deschide un fişier identificat prin argumentul nume_fişier conform

modului de deschidere specificat prin argumentul mod. Funcţia returnează un descriptor de fişier care trebuie atribuit unui simbol, altfel rezultatul se pierde şi nu se poate face operaţia de închidere a fişierului.

Numele de fişier trebuie să descrie calea completă către fişier conform regulilor sistemului de operare DOS. Separatorul de cale este perechea de caractere “\\” în loc de obişnuitul caracter “\”, aceasta datorită semnificaţiei de prefix pentru caractere speciale acordată caracterului backslash (a se vedea exemplul de la funcţia STRCAT).

Argumentul mod poate avea valorile: “r” deschidere pentru citire. Dacă fişierul nu există se returnează nil. “w” deschidere pentru scriere. Dacă fişierul nu există este creat unul nou. “a” deschidere pentru adăugare. Dacă fişierul nu există este deschis unul nou. Dacă

fişierul există este deschis, iar pointerul de evidenţă este poziţionat la sfârşitul fişierului, astfel încât noile date sunt scrise în continuarea celor existente.

Descriptorul de fişier returnat va fi folosit ulterior pentru: - citire de date cu funcţia read-char sau read-line la fişierele deschise pentru citire; - scriere de date cu funcţia write-char sau write-line la fişierele deschise pentru scriere

(modurile “w” şi “a”);

Page 209: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 197

- închiderea fişierului cu funcţia close. De exemplu: (setq df (open “C:\\ALFA\\BETA\\NUME.DTA”)) returnează descriptorul de fişier df. (CLOSE descriptor_de_fişier) Această funcţie închide fişierul specificat de argumentul descriptor_de_fişier obţinut

anterior folosind funcţia open.

(READ-CHAR [descriptor_de_fişier]) Această funcţie citeşte un caracter din fişierul specificat prin argumentul

descriptor_de_fişier. Dacă acest argument lipseşte citirea se face din bufferul de caractere al tastaturii. Funcţia returnează o valoare întreagă reprezentând codul ASCII al caracterului citit. De exemplu:

(read-char) returnează 97 dacă se apasă tasta “a” sau 65 dacă se apasă tasta “A” Dacă se doreşte obţinerea caracterului citit se va folosi funcţia: (CHR cod) Această funcţie returnează caracterul ASCII al cărui cod este furnizat ca argument. De exemplu: (chr 97) returnează “a”. (WRITE-CHAR cod [descriptor_de_fişier]) Această funcţie scrie în fişierul deschis specificat prin argumentul descriptor_de_fişier

caracterul al cărui cod este furnizat ca argument. Dacă descriptor_de_fişier lipseşte scrierea se face pe ecran în poziţia curentă a cursorului.

Pentru a se obţine codul caracterului de scris se foloseşte funcţia: (ASCII şir) Această funcţie returnează codul primului caracter din şir. De exemplu: (ascii “abc”) returnează 97 (write-char (ascii “abc”)) scrie pe ecran caracterul “a” deoarece descriptorul de fişier

lipseşte. (READ-LINE [descriptor_de_fişier]) Această funcţie citeşte o linie (un şir de caractere terminat cu caracterul ENTER) din

fişierul deschis specificat de argumentul descriptor_de_fişier sau, dacă acesta lipseşte, de la tastatură.

(WRITE-LINE şir [descriptor_de_fişier]) Această funcţie scrie în fişierul deschis specificat de argumentul descriptor_de_fişier şirul

de caractere şir ca pe o linie terminată prin caracterul ENTER. Dacă descriptor_de_fişier lipseşte scrierea se face pe ecran în poziţia curentă a cursorului.

(PROMPT “mesaj”) Această funcţie scrie pe ecran şirul de caractere constituit de argumentul mesaj. (TERPRI) Această funcţie scrie pe ecran o linie de text goală. Funcţia este folosită prin includerea ei

pe ultima linie a unui program AutoLISP ca ieşire “tăcută”, pentru a evita afişarea ultimei evaluări a unei funcţii.

(LOAD fişier_lisp) Această funcţie serveşte la încărcarea unui fişier sursă AutoLISP specificat ca argument.

Identificatorul fişierului trebuie să conţină dispozitivul şi calea către fişier, conform

Page 210: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 198

convenţiei DOS, ca la funcţia OPEN. Numele unui fişier AutoLISP are extensia de tip .LSP, dar aceasta nu este necesar să fie specificată.

9.16.4. Realizarea dialogului dintre AutoCAD şi AutoLISP Există un număr de funcţii care pot fi folosite pentru a construi un dialog între interpretorul

de comenzi AutoCAD şi un program scris în AutoLISP. Prin utilizarea lor se pot cere sau introduce informaţii din/în baza de date a AutoCAD-ului, sau se pot transmite comenzi către interpretorul de comenzi AutoCAD.

(COMMAND arg1 arg2 … argn) Această funcţie este cea mai folosită şi serveşte la transmiterea către interpretorul de comenzi din

AutoCAD a unei succesiuni de cuvinte de comandă rezultate din evaluarea argumentelor arg1, … , argn. Setul de argumente transmis poate fi incomplet, urmând o succesiune de alte funcţii de naturi diferite, dar comanda, odată iniţiată, trebuie încheiată, folosind alte funcţii command ulterioare.

La scrierea şirurilor de caractere ale argumentelor sintaxa comenzii AutoCAD trebuie respectată, după exact aceleaşi exigenţe ca şi în cazul scrierii ei de la tastatură. De exemplu: (command “line” ‘(0 0) ‘(1 1) “”)

are acelaşi efect ca şi setul de comenzi AutoCAD următor: command:LINE From point:0,0 To point:1,1 To point:<ENTER> adică trasarea unei linii drepte de la punctul de coordonate 0,0 la punctul de coordonate 1,1. Observaţie: simbolul predefinit PAUSE poate fi folosit ca argument al funcţiei

COMMAND pentru a realiza o pauză în succesiunea transmiterii de argumente către interpretorul de comenzi. La momentul pauzei utilizatorul poate interveni furnizând argumentul el însuşi. De exemplu: (command “circle” “5,5” pause)

are ca efect desenarea unui cerc cu centrul în punctul de coordonate 5,5 şi raza furnizată de utilizator.

Observaţie: funcţia COMMAND returnează întotdeauna rezultatul nil.

(ANGLE punct1 punct2) Această funcţie returnează unghiul cu orizontala făcut de linia care trece prin punctele

punct1 şi punct2, măsurat în radiani. De exemplu: (angle ‘(0 0) ‘(1 1)) returnează valoarea 0.785398, adică π/4. (DISTANCE punct1 punct2) Această funcţie returnează distanţa dintre punctele punct1 şi punct2. De exemplu: (setq p1 (list 0 0) p2 (list 1 1) d (distance p1 p2)) returnează 1.41421. (GETANGLE [punct1] [mesaj]) Această funcţie poate apare în următoarele forme: (getangle) aşteaptă plasarea cu cursorul grafic a două puncte în câmpul de

lucru al AutoCAD şi returnează unghiul cu orizontala al liniei care uneşte punctele; (getangle punct1) aşteaptă plasarea celui de al doilea punct de către utilizator şi

returnează unghiul cu orizontala al dreptei rezultante; (getangle “mesaj”) acelaşi efect ca şi la (getangle) dar în prealabil afişează şirul de

caractere “mesaj”; (getangle punct1 “mesaj”) acelaşi efect ca şi la (getangle punct1) dar în prealabil afişează

“mesaj”.

Page 211: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 199

(GETDIST [punct1] [mesaj]) Această funcţie prezintă aceleaşi patru forme ca şi funcţia getangle, dar returnează distanţa

dintre două puncte. (GETINT [“mesaj”]) Această funcţie preia de la utilizator o valoare întreagă şi o returnează ca rezultat. Dacă

argumentul “mesaj” este specificat el este afişat ca mesaj de cerere. Dacă utilizatorul introduce altceva decât o valoare întreagă este afişat mesajul: Requires an inetger value. Try again:.

(GETREAL [“mesaj”]) Această funcţie preia de la utilizator o valoare reală şi o returnează ca rezultat. Dacă

argumentul “mesaj” este specificat el este afişat ca mesaj de cerere. Dacă utilizatorul introduce altceva decât o valoare numerică este afişat mesajul: Requires a value. Try again:.

(GETORIENT [punct1] [“mesaj”]) Această funcţie se comportă la fel cu funcţia GETANGLE dar unghiul returnat este

raportat la direcţia de referinţă stabilită prin comanda UNITS. (GETPOINT [“mesaj”]) Această funcţie preia de la utilizator un punct şi returnează lista coordonatelor sale. Dacă

argumentul “mesaj” este prezent el este afişat ca mesaj de cerere. (GETSTRING [caz] [“mesaj”]) Această funcţie preia de la utilizator un şir de caractere şi îl returnează ca rezultat. Dacă

argumentul caz este prezent şi diferit de nil, şirul de caractere poate conţine şi spaţii. Dacă argumentul “mesaj” este prezent el este afişat ca mesaj de cerere.

(GETVAR “nume_variabilă”) O largă serie de comenzi din AutoCAD funcţionează în concordanţă cu o gamă de

parametri de lucru stabiliţi de aşa-numitele variabile de sistem AutoCAD identificate prin nume_variabilă. Marea lor majoritate sunt de tip read-write, altele fiind doar de tip read-only. Aceste variabile de sistem pot fi citite din AutoLISP cu funcţia GETVAR, iar cele care nu sunt de tip read-only pot fi şi modificate cu funcţia SETVAR.

(SETVAR “nume_variabilă” valoare) Această funcţie permite modificarea valorii unei variabile specificate prin nume_variabilă,

dacă aceasta este de tip read-write.

(GRAPHSCR) Această funcţie comută regimul de lucru în fereastra grafică AutoCAD. Returnează nil. (TEXTSCR) Această funcţie deschide fereastra text AutoCAD. Returnează nil. (REDRAW [nume_de_entitate [mod]]) Această funcţie poate avea ca unul dintre argumente un aşa-numit nume de entitate,

returnat de una din funcţiile speciale de acces la baza de date a entităţilor grafice din AutoCAD, funcţii despre care vom discuta mai târziu. Argumentul mod determină modul de redesenare a entităţii de nume specificat, astfel:

1 – redesenarea pe ecran a entităţii; 2 – ascunderea de pe ecran a entităţii;

Page 212: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 200

3 – evidenţierea entităţii; 4 – dezactivarea evidenţierii entităţii. Dacă mod nu se specifică are loc redesenarea entităţii. Dacă nume_de_entitate şi mod nu

se specifică este redesenat portul de vedere curent. Funcţia returnează întotdeauna nil.

(INITGET [opţiune] [listă_de_cuvinte_cheie]) Această funcţie iniţializează modul de acţiune pentru următorul apel al unei funcţii de

forma GETXXXX, mai puţin GETSTRING şi GETVAR, şi returnează nil. Argumentul opţiune poate avea valorile: 1 – interzicerea răspunsului nul (binar 00000001); 2 – interzicerea valorilor numerice nule (binar 00000010); 4 – interzicerea valorilor numerice negative (binar 00000100); 8 – ignoră încadrarea în limitele desenului chiar dacă variabila LIMCHECK este ON (binar

00001000); etc, până la 128 cu semnificaţii diferite (a se vedea manualul de utilizare). Prin însumarea valorilor de mai sus se pot obţine combinaţii pentru valoarea opţiunii.

Astfel 5=1+4 (00000101) poate fi folosită pentru a specifica simultan opţiunile corespunzătoare (nu este permisă introducerea ca răspuns a caracterului ENTER şi nici valoare negativă).

După iniţializarea cu INITGET, dacă râspunsul utilizatorului la o cerere a o funcţie GETXXXX este neconformă ce cerinţele este afişat un mesaj de eroare şi este repetată cererea.

Argumentul listă_de_cuvinte_cheie este un şir de caractere sau set de şiruri de caractere separate prin spaţii şi care constituie posibile răspunsuri. De exemplu:

(initget “CENtru RAZa”) (getkword “Metoda?:) permite un răspuns prin centru, raza, cen sau raz. Aşadar majusculele specifică

prescurtările prin care se poate furniza răspunsul. Funcţia INITGET returnează nil, iar efectul ei încetează după primul apel al unei funcţii

GETXXXX. (GETKWORD “mesaj”) Această funcţie testează introducerea de către utilizator a unui cuvânt cheie autorizat de

către funcţia INITGET folosită anterior şi repetă acţiunea până la obţinerea răspunsului corect pe care îl returnează ca rezultat.

§9.17. Accesul la baza de date a entităţilor AutoCAD Utilizatorul poate accesa baza de date pentru entităţi AutoCAD folosind următoarele

categorii de funcţii. 9.17.1. Funcţii de manipulare a entităţilor grafice Entităţile grafice ale AutoCAD-ului pot fi manipulate folosind următoarele funcţii

AutoLISP:

(ENTSEL [“mesaj”]) Această funcţie permite selectarea manuală de către utilizator a unei entităţi grafice de pe ecran. Rezultatul returnat este o listă de forma: (nume_de_entitate punct_de_selectare) Argumentul “mesaj” este opţional şi este afişat ca mesaj de cerere. De exemplu: Command:LINE From point:1,1 To point:6,6

Page 213: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 201

To point:<ENTER> Command:(setq ent (entsel “\nAlegeti o entitate:”)) Alegeti o entitate:3,3 (<Entity name: 3180520> (3.0 3.0 0.0)) Numele de entitate va putea fi folosit ulterior la operaţii de indicare a entităţii. De exemplu: (setq nument (car ent)) returnează <Entity name: 3180520> Observaţie: Numele de entitate este un indicator de poziţie în baza de date a fişierului

temporar cu care lucrează AutoCAD. El diferă de la o sesiune de lucru la alta. (ENTGET nume_de_entitate) Această funcţie foloseşte argumentul nume_de_entitate obţinut anterior cu funcţia

ENTSEL, ENTLAST, ENTNEXT sau SSNAME, şi returnează o listă compusă din subliste care definesc entitatea.

De exemplu, pentru entitatea selectată la exemplul anterior: (setq elist (entget nument)) returnează lista următoare (listă de entitate): ((-1 . <Entity name: 3180520>) numele entităţii (0 . "LINE") tipul entităţii … (8 . "0") stratul entităţii … (62 . 1) culoarea entităţii … (10 1.0 1.0 0.0) punctul iniţial al entităţii (11 6.0 6.0 0.0) punctul final al entităţii … ) (ENTLAST) Această funcţie returnează numele ultimei entităţi introdusă în baza de date. Dacă, în

exemplul anterior, linia 1,1-6,6 ar fi fost ultima generată, se putea folosi cu acelaşi rezultat: (entget (entlast))

(ENTNEXT [nume_de_entitate]) Această funcţie are ca efecte: - dacă nume_de_entitate lipseşte este returnat numele primei entităţi din baza de date; - dacă nume_de_entitate este specificat se returnează numele entităţii următoare din baza de date; - când nume_de_entitate reprezintă ultima entitate din baza de date funcţia returnează nil. (ENTDEL nume_de_entitate) Această funcţie şterge din baza de date entitatea de nume specificat. Dacă entitatea a fost

deja ştearsă ea va fi restaurată.

(ENTMOD listă_de_entitate) Acestei funcţii i se transmite ca argument o listă de entitate în care au fost operate

modificări prin intermediul funcţiilor prelucrătoare de liste (în special folosind SUBST), dar fără a se opera asupra asociaţiei cu –1 (cea care conţine numele de entitate – a se vedea exemplul de mai sus). Funcţia modifică entitatea conform modificării operate în listă.

De exemplu, pentru linia de mai sus: (setq oldcul (assoc 62 elist)) returnează perechea cu punct (62 . 1) conţinând vechea

culoare a entităţii (setq elist (subst (cons 62 5) oldcul elist)) returnează o listă nouă de entitate in care

Page 214: Programarea Calculatoarelor si Limbaje de Programare

Cap.9. Limbajul AutoLISP pentru AutoCAD 202

perechea cu punct (62 .1) este înlocuită cu perechea (62 . 5) (entmod elist) modifică entitatea conform noii componenţe a listei elist Observaţie: în cazul entităţilor simple modificarea operată de ENTMOD este imediat vizibilă pe

ecran. În cazul entităţilor complexe modificarea va fi vizibilă abia după folosirea funcţiei ENTUPD. (ENTUPD nume_de_entitate) Această funcţie actualizează entitatea de nume specificat prin redesenarea ei conform

ultimelor modificări operate asupra ei în baza de date. 9.17.2. Funcţii de acces la tabela de simboluri Obiectele predefinite şi având denumiri atribuite, cum ar fi straturile, tipurile de linii,

stilurile de text şi blocurile de entităţi grafice, se reflectă într-o tabelă de simboluri la care se poate avea acces numai pentru citire, prin intermediul funcţiilor TBLNEXT şi TBLSEARCH.

(TBLNEXT tip_de_obiect [redeschidere]) Această funcţie caută în tabela de simboluri prima înregistrare care urmează ultimei

înregistrări returnate de un apel anterior de căutare pentru obiectul de tipul specificat. Dacă o asemenea înregistrare există este returnată o listă de definiţie, altfel se returnează nil.

Dacă argumentul redeschidere există şi este diferit de nil, rezultatul este returnarea primei înregistrări de tipul specificat existentă în baza de date.

De exemplu: (tblnext “BLOCK”) ar putea returna următoarea listă: ((0 . “BLOCK”) numele tipului de obiect căutat (2 . “CUTIE”) numele obiectului (70 . 0) indicator de stare (10 9.0 2.0 0.0) punct de inserare (-2 . <Entity name : 3180552>) numele primei entităţi conţinută în bloc ) (TBLSEARCH tip_de_obiect nume_atribuit [corelare]) Această funcţie caută în tabela de simboluri o înregistrare pentru un obiect de tip specificat şi

având numele atribuit specificat. Dacă argumentul corelare este prezent şi este diferit de nil, atunci următoarea evaluare a funcţiei TBLNEXT va returna înregistrarea care urmează după cea returnată de apelul curent al funcţiei TBLSEARCH, altfel cele două funcţii lucrează independent.

Ca exemplu, rezultatul obţinut mai înainte de funcţia TBLNEXT putea fi obţinut şi direct prin funcţia:

(TBLSEARCH “BLOCK” “CUTIE”) 9.17.3. Funcţii pentru manipularea seturilor de selecţie Un set de selecţie în AutoLISP este o colecţie de nume de entităţi. El constituie o bază de

date temporară care permite manipularea mai comodă a entităţilor. Funcţiile care manipulează seturile de selecţie sunt următoarele:

(SSGET [“mod”] [punct1 [punct2]] [lista_de_puncte] [lista_de_filtrare]) Această funcţie selectează o colecţie (set) de entităţi. Argumentul opţional “mod”, de tip

şir de caractere, poate fi unul dintre şirurile de caracterele acceptate la selecţia de entităţi sub AutoCAD, adică:

W – metoda Window (numai entităţile complet incluse într-o fereastră dreptunghiulară); WP – metoda WPolygon (numai entităţile complet incluse într-o fereastră poligonală); C – metoda Crossing (toate entităţile care traversează o fereastră dreptunghiulară);

Page 215: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 203

CP – metoda CPolygon (toate entităţile care traversează o fereastră poligonală); L – ultima entitate generată (Last); P – setul de selecţie selectat anterior (Previous); F – metoda Fence (toate entităţile care traversează un traseu poligonal neînchis; X – toate entităţile din baza de date. Argumentele punct1 şi punct2 sunt liste de coordonate de puncte folosite pentru definirea

colţurilor diagonal opuse ale unor ferestre la metodele W şi C. Dacă argumentul punct2 lipseşte AutoCAD aşteaptă introducerea lui de către utilizator.

Argumentul listă_de_puncte este o listă de liste de coordonate de puncte şi este folosită la metodele WP, CP şi F.

Dacă SSGET este folosită fără argumente, AutoCAD invită la selectarea manuală obişnuită, încheiată prin ENTER.

Argumentul lista_de_filtrare este o listă de asociaţii (perechi cu punct) care descriu proprietăţi ale entităţilor de selectat. Din totalitatea entităţilor încadrabile în aria descrisă de argumentul mod vor fi reţinute în set numai cele care se potrivesc cu cerinţele listei de filtrare.

De exemplu: (setq cercuri_rosii (ssget “X” (list (cons 0 “CIRCLE”) (cons 62 1)))) va reţine din toată baza de date numai entităţile de tip cerc de culoare roşie. Numărul maxim de seturi de selecţie este de 128, orice încercare de a crea un set în plus se

va solda cu returnarea rezultatului nil. Pentru a desfiinţa un set de selecţie devenit inutil acesta trebuie asociat cu nil, de exemplu: (setq cercuri_rosii nil) (gc) Funcţia GC (Garbage collection – colectare de gunoaie) restituie sistemului memoria

ocupată de entităţile AutoLISP desfiinţate. (SSLENGTH set_de_selecţie) Această funcţie returnează numărul de entităţi din setul de selecţie. Valoarea returnată este

de tip întreg dacă este de până la 32767 de entităţi şi de tip real pentru un număr mai mare. (SSNAME set_de_selecţie indice) Această funcţie returnează numele de entitate conţinută într-un set de selecţie, al cărei

indice de ordine (începând de la 0) este specificat de argumentul indice. (SSADD [nume_de_entitate [set_de_selectie]]) Această funcţie are variantele următoare: (ssadd) construieşte un nou set de selecţie vid; (ssadd nume_de_entitate) construieşte un nou set de selecţie conţinând entitatea de

nume specificat; (ssadd nume_de_entitate set_de_selectie) adaugă entitatea de nume specificat la setul de

selecţie specificat. (SSDEL nume_de_entitate set_de_selectie) Această funcţie elimină entitatea de nume specificat din setul de selecţie specificat. Dacă

entitatea nu face parte din set este returnat nil.

(SSMEMB nume_de_entitate set_de_selectie) Această funcţie testează apartenenţa entităţii de nume specificat la setul de selecţie

specificat şi returnează T sau nil, după caz.

Page 216: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 204

Cap.10. Aplicaţii de programare în C şi C++

§10.1. Elaborarea unui program în limbaj C într-un mediu de programare integrat

10.1.1. Generalităţi asupra mediului de lucru Limbajul C este un limbaj pentru lucrul prin procedeul compilator. La ora actuală este un

limbaj foarte răspândit. Existent în diferite versiuni ca mediu de programare de sine stătător, el se află chiar inclus în anumite medii integrate de dezvoltare din unele aplicaţii.

Dată fiind, deci, răspândirea lui, se cuvine să prezentăm câteva elemente privind concepţia lui şi modul său de folosire.

Limbajul C are trei avantaje principale, şi anume: - este un limbaj de programare cu destinaţie generală. Cu ajutorul lui se pot construi orice

fel de programe, de la editoare de text şi programe de calcul matematic, până la jocuri dintre cele mai complexe;

- este un limbaj structurat. Limbajul C posedă capabilităţi de structurare completă ceea ce conferă programelor o mare robusteţe şi uşurinţa modificării;

- este un limbaj standardizat. Aceasta face ca în cea mai mare parte din cazuri, cu foarte mici modificări sau fără nici o modificare, un program în C scris pe o anumită maşină să poată fi compilat pe o alta.

Pentru simplitate, vom prezenta un produs de natură didactică, cu funcţionalitate limitată dar foarte potrivit pentru programatorul începător. Este vorba de compilatorul de C care însoţeşte cartea lui Tom Swan, "Învăţăm C pas cu pas", Editura Tehnică, Bucureşti, 1996. Acest compilator este o variantă simplificată a unui mediu de programare foarte popular la un moment dat, produs de firma Borland, şi anume TURBO C++.

Acest adevărat mediu de programare este destinat exclusiv sistemului de operare DOS. Pentru un începător, imposibilitatea folosirii acestui compilator pentru scrierea de programe pentru WINDOWS este un lucru bun deoarece simplifică mult lucrurile, permiţând începătorului să se concentreze pe problemele de esenţă ale lucrărilor de programare, evitând multele detalii ale programării pentru WINDOWS care l-ar putea descuraja.

Fig. 10.1.

Page 217: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 205

10.1.2. Lansarea în lucru a compilatorului de C Versiunea de compilator descrisă mai sus este instalată sub denumirea de TCLITE. Programul se poate lansa fie cu ajutorul butonului Start>Programs>TcLite, fie cu

ajutorul pictogramei TcLite de pe Desktop, dacă aceasta a fost creată. La lansare, compilatorul deschide o fereastră ca în figura 10.1. Componenţa ferestrei compilatorului reflectă o etapă de interfaţare grafică premergătoare

sistemului WINDOWS. Se observă şi aici o componenţă destul de asemănătoare cu aceea a ferestrelor de aplicaţie din sistemul WINDOWS, şi anume:

- o bară de meniu scris, cu articolele File, Edit, Search, … , Window şi Help; - un chenar al câmpului de lucru de mărime reglabilă prin tragere cu mouse-ul; - un buton de închidere a ferestrei câmpului de lucru (la stânga, sus - [ ]): - un buton de maximizare – restaurare a ferestrei de lucru (la dreapta, sus - [ ]); - două bare de defilare, pe verticală şi, respectiv, pe orizontală; - o bară de meniu rapid, la baza ferestrei aplicaţiei, cea care conţine simbolurile tastelor

funcţionale F1, F2, F3, Alt-F9, F9 şi F10. Inscripţia NONAME.CPP de pe chenarul ferestrei de lucru reprezintă denumirea fişierului

sursă acordată automat la lansarea aplicaţiei. 10.1.3. Utilizarea meniului mediului de programare În continuare vom prezenta pe scurt numai acele meniuri şi articole ale lor strict necesare

pentru un începător.

Fig.10.1.2. Fig.10.1.3. Fig.10.1.4.

Fig.10.1.5. Fig.10.1.6. Făcând o scurtă examinare a figurilor 10.1.2 ... 10.1.8, se observă că unele dintre articolele

de meniu sunt afişate cu negru iar celelalte cu gri. Motivul este acelaşi ca şi în Windows, şi anume contextualitatea comenzilor cu situaţia de lucru curentă. Dacă o comandă este aplicabilă într-un anumit moment al lucrului ea va fi afişată cu negru, altfel este afişată cu gri.

Page 218: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 206

Ca şi în Windows, comenzile direct executabile nu sunt urmate de un alt simbol (de exemplu New, Save, ... , Quit). Comenzile care deschid o nouă listă de meniu sunt urmate de o săgeată sub formă de triunghi (de exemplu în meniul Options, comanda Environment) În sfârşit, comenzile care deschid o cutie de dialog sunt urmate de trei puncte ... (de exemplu Open, Save as, ..., etc.).

Meniul File (figura 10.1.2) este destinat lucrului cu fişiere şi conţine articolele: - Open - pentru deschiderea unui fişier program sursă existent; - New - pentru crearea unui fişier program sursă nou; - Save - pentru salvarea fişierului curent, cu numele existent şi în directorul asociat; - Save as - pentru salvarea fişierului curent, cu un alt nume şi într-un alt director; - Save all - pentru salvarea tuturor fişierelor deschise în sesiunea de lucru curentă, ca şi

Save, adică având denumirile şi directoarele deja stabilite; - Change dir - pentru schimbarea directorului de lucru curent; - Print - pentru transmiterea la imprimantă a conţinutului fişierului curent; - Get info - pentru obţinerea informaţiilor referitoare la fişierul curent; - DOS shell - pentru părăsirea temporară a mediului de lucru pentru a efectua o operaţie

sub sistemul de operare DOS. În condiţiile lucrului sub sistemul Windows, această comandă nu îşi mai găseşte utilitatea de altă dată;

- Quit - pentru ieşirea din mediul de programare.

Fig.10.1.7. Fig.10.1.8. Meniul Edit (figura 10.1.3) este destinat operaţiilor de editare (modificare) în fişierul de

lucru curent şi conţine articolele: - Restore line - este echivalentul comenzii Undo din programele Windows, restaurând

situaţia anterioară ultimei modificări; - Cut, Copy şi Paste, au aceleaşi semnificaţii ca şi în Windows; - Copy example. Mediul TcLite pune la dispoziţie o serie de exemple care, cu această

comandă, pot fi copiate în Clipboard în întregime; - Show Clipboard - deschide fereastra Clipboard în care se află stocat textul copiat

anterior cu comenzile Copy sau Cut; - Clear - şterge textul selectat fără a-l mai copia în Clipboard. Meniul Search (figura 10.1.4) este destinat operaţiilor pentru căutare şi/sau înlocuire de

secvenţe de text şi conţine articolele: - Find - pentru căutarea unui şir de text selectat; - Replace - pentru înlocuirea unui şir de text selectat cu un altul specificat; - Search again - pentru repetarea căutării unui şir de text; - Go to line number - pentru poziţionarea cursorului la o linie de text de număr indicat; - Previous error - pentru poziţionarea cursorului la eroarea semnalată de compilator

anterioară erorii la care se află în mod curent cursorul (în timpul operaţiilor de depanare a programelor);

Page 219: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 207

- Next error - pentru poziţionarea cursorului la eroarea semnalată de compilator ulterioară erorii la care se află în mod curent cursorul;

- Locate function - se foloseşte în programele mari pentru poziţionarea cursorului la începutul definiţiei unei funcţii cu numele indicat de utilizator.

Comenzile Previous error, Next error şi Locate function pot fi folosite numai pe parcursul lucrului cu depanatorul.

Meniul Run (figura 10.1.5) este destinat operaţiilor de rulare a programelor de sub mediul de programare şi conţine articolele:

- Run - rulează programul curent; - Program reset - efectuează următoarele aţiuni: opreşte sesiunea curentă de depanare;

eliberează memoria pe care programul şi-a alocat-o; închide orice fişier pe care l-a deschis programul în cursul rulării şi care a rămas eventual neînchis de către program;

- Go to cursor - rulează programul până la linia la care se află cursorul; - Trace into - transferă rularea pas cu pas din timpul depanării la prima linie a funcţiei

curente. În caz contrar, dacă se foloseşte rularea de depanare cu Step over, este efectuată rularea întregului cod al funcţiei, după care cursorul sare la linia de program ulterioară funcţiei;

- Step over - vezi mai sus; - Arguments - permite specificarea argumentelor de care programul curent ar avea nevoie

dacă el ar fi rulat de sub sistemul DOS. Dacă programul nu are asemenea argumente această comandă nu trebuie folosită;

Meniul Compile (figura 10.1.6) este destinat compilării programului curent şi conţine articolele:

- Compile to OBJ - se foloseşte în prima fază de compilare pentru a se produce codul obiect din codul sursă (text) al programului. În această fază este făcută analiza sintactică şi este semnalată majoritatea erorilor;

- Make EXE file - se foloseşte în a doua fază de compilare în cazul programelor care au la bază un fişier proiect (nume.PRJ) în care sunt specificate şi alte module. Rezultatul acestei faze este codul obiect executabil rezultat din codurile obiect separate ale fişierelor necurente şi editarea legăturilor dintre modulul rezultat din fişierul curent compilat cu Compile to OBJ şi modulele obiect ale fişierelor program necurente;

- Link EXE file - este folosit la editarea legăturilor dintre module compilate anterior separat cu Compile to OBJ;

- Build all - execută toate fazele de compilare şi legare ale tuturor fişierelor din proiect indiferent de starea lor de actualitate;

- Remove messages - elimină toate mesajele din fereastra Message. Meniul Debug conţine comenzi necesare în timpul depanării. Deocamdată vom sări peste

acest subiect, urmând să revenim la el mai târziu când se vor acumula mai multe cunoştinţe. Meniul Project este destinat gestionării fişierelor proiect. Aceste fişiere descriu programe

complexe definite din mai multe module. Vom sări şi peste acest subiect care va fi tratat mai târziu. Meniul Options (figura 10.1.7) administrează opţiunile de lucru cu compilatorul şi

conţine articolele: - Compiler defines - este o comandă destinată înlocuirii unei directive DEFINE care nu

este prezentă în textul sursă; - Directories - deschide cutia de dialog din figura 8 care permite specificarea

următoarelor: = Include Directories - directoarele care conţin fişierele în cod sursă invocate de

directiva INCLUDE;

Page 220: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 208

= Library Directory - directoarele care conţin fişiere de bibliotecă în cod obiect sau executabil care trebuie legate cu fişierul de compilat sau sunt apelate de acesta în cursul execuţiei;

= Output directory - directorul de ieşire, adică acela în care este stocat produsul compilării sub formă de fişier obiect (OBJ).

- Environment - pentru stabilirea setărilor de lucru ale mediului de programare (preferinţe de folosire a ecranului, opţiuni privind editorul de text, modul de comportare al mouse-ului);

- Save - comandă de salvare a opţiunilor de lucru stabilite cu meniul Options. Meniul Window este destinat lucrului cu ferestrele mediului de programare. Este destul de

explicit şi uşor de înţeles, astfel încât, pentru economia acestei lucrări vom renunţa la prezentarea lui, cu atât mai mult cu cât meniul Help pune la dispoziţia utilizatorului lămuririle necesare.

10.1.4. Aplicaţie Vom trece acum la un exemplu de program C++, prin care vom încerca să parcurgem

practic etapele de lucru cu acest mediu de programare.

#include <stdio.h> /* directive preprocesor */ #include <conio.h> #include <iostream.h> void main() /* functia principala */ {int i; /* declaratii de tipuri de variabile */ char c; i=0; /* urmeaza instructiunile */ while ((c=getchar()) != '\n') {i=i+1;}/* asteapta apasarea tastei ENTER si numara apasarile de taste */ cout << "Inainte de a apasa ENTER ati apasat " << i << " taste\n"; getch(); /* asteapta apasarea unei taste */ }

Componenţa programului: Programul conţine două blocuri, şi anume: - blocul directivelor preprocesor. În acest bloc apar directivele include. El înştiinţează

compilatorul ca, pentru funcţiile nedefinite în corpul programului să se efectueze o căutare în fişierele stdio.h, conio.h şi iostream.h. Aceste căutări sunt necesare pentru funcţiile getchar, getch şi cout, care nu sunt definite în program.

- funcţia principală, main. În această funcţie sunt conţinute instrucţiunile programului. Textele incluse între perechile de caractere /* şi */ constituie comentarii şi sunt ignorate de

compilator. Etapele de lucru pentru elaborarea programului sunt: - După lansarea programului compilator, se scrie textul sursă (cel prezentat mai sus).

Editorul de text este inclus în mediul de programare şi nu necesită accesare separată. Practic, programatorul se găseşte tot timpul în editorul de text;

- Înainte de a se trece la următoarele etape, pentru a nu se pierde programul sursă ca urmare a unei erori de execuţie care ar conduce la blocarea compilatorului (se poate întâmpla oricând din diferite motive, legate mai ales de o concepţie defectuoasă a programului), se salvează fişierul sursă. La prima salvare se va folosi comanda Save as din meniul File. Se va alege un director de depozitare a fişierului program sursă şi i se va atribui un nume. Numele

Page 221: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 209

trebuie urmat de extensia C sau CPP după cum este vorba de folosirea limbajului C standard sau a versiunii sale extinse, şi anume C++.

- Următoarea etapă este cea de compilare. Pentru aceasta se foloseşte meniul Compile, din care se selectează comanda Compile to OBJ. Aceasta produce fişierul cod obiect relocabil. Dacă la salvare s-a ales numele DID1.CPP, la compilare va fi produs fişierul DID1.OBJ.

În această fază are loc depistarea erorilor de sintaxă şi de definire. Compilatorul nu va raporta îndeplinirea sarcinii de compilare dacât atunci când toate erorile vor fi fost eliminate. Dacă apar erori, acestea sunt raportate într-o fereastră de mesaje (Message Window) care se deschide la baza ferestrei compilatorului.

- În cazul unei lucrări mai complexe, pentru crearea unui program din mai multe module, se foloseşte un fişier proiect (nume.PRJ) care conţine indicaţiile privind componenţa lucrării.

În cazul nostru, deoarece nu există un proiect, se pot folosi numai comenzile Compile to OBJ şi Make EXE file. Pentru simplitate, vom folosi numai Compile to OBJ pentru a activa analiza erorilor. Nu vom mai folosi Make EXE file deoarece comanda Run din meniul Run îndeplineşte funcţiile cumulate ale comenzilor Compile to OBJ şi Make EXE file.

Am putea folosi de la început comanda Run dar nu este indicat deoarece încă nu am eliminat erorile şi ne expunem pericolului unei căderi a programului compilator din cauza erorilor neeliminate.

Obs. O serie de erori greu detectabile sunt cele de execuţie, cauzate de vicii de concepţie.

Aceste erori nu sunt de tip sintactic, nici de definire, şi nu sunt detectabile în faza de compilare. Ele nu se manifestă decât la execuţie şi pot cauza efecte nedorite dintre cele mai diverse, de la simple rezultate eronate până la căderi ale sistemului.

§10.2. Programe simple în C Fiecare dintre exerciţiile următoare trebuie realizat ca fişier program sursă de sine stătător.

Ele pot avea extensia de tip C, deoarece nu conţin instrucţiuni caracteristice variantei C++. Desigur, ele sunt recunoscute şi în cazul realizării unui program C++, caz în care trebuie să aibă extensia de tip CPP. Puteţi opta pentru oricare variantă dintre cele două.

Primul exerciţiu are ca scop producerea afişării unui text. Se observă din textul sursă de mai jos succesiunea blocurilor de program:

- mai întâi directivele de includere a textului sursă din fişierele antet (nume.h) în care se găsesc definiţiile funcţiilor de bibliotecă ale limbajului C;

- apoi, directivele de definire a constantelor de tip şir de text care se regăsesc ulterior în textul sursă al programului şi pe care compilatorul le va înlocui cu textul din definiţie;

- definiţiile de tipuri de date noi; - definiţiile funcţiilor apelate în programul principal şi care trebuie cunoscute de

compilator în momentul întâlnirii apelurilor acelor funcţii, în situaţia când acele funcţii sunt definite de programator şi nu sunt funcţii de bibliotecă;

- în sfârşit, programul principal, sub forma funcţiei main. Exercitiul A #include <stdio.h> /*directive preprocesor*/ #include <conio.h> #define UNU 1 typedef int intreg; /*definitii de tipuri noi*/ void mesaj(intreg numar) /*definirea unei functii*/ {printf("acesta este programul numarul %i\n", numar);}

Page 222: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 210

void main(void) /*functia main = programul principal*/ {intreg primul=UNU; mesaj(primul); getch(); }

Funcţiile definite de utilizator pot fi definite şi după funcţia main. Totuşi, compilatorul are nevoie să ştie măcar tipurile argumentelor de intrare în funcţie şi tipul rezultatului returnat de funcţie, altfel, la întâlnirea apelurilor respectivelor funcţii în funcţia main, nu va putea aloca spaţiile necesare în memorie.

Din acest motiv, dacă definirea unei funcţii se va face după funcţia main, trebuie ca inaintea funcţiei main să se plaseze un "prototip" al respectivei funcţiei, prototip al cărui rol este de a defini tipurile datelor de intrare şi ieşire în/din funcţie.

Observaţie: funcţia getch are numai rolul de a conserva starea ecranului până când utilizatorul apasă pe o tastă. Altfel, mediul de programare ar prelua imediat controlul reafişând textul sursă din editorul de text al mediului TcLite. Pentru un program rulabil direct de sub sistemul DOS, această instrucţiune nu ar fi necesară.

Exemplul al doilea este o variantă a primului exemplu, dar cu folosirea unui prototip de funcţie. Exercitiul B #include <stdio.h> /*directive preprocesor*/ #include <conio.h> #define UNU 1 typedef int intreg; /* definitii de tipuri */ void mesaj(intreg) /* prototipul functiei mesaj */ void main(void) /* programul principal */ {intreg al_doilea=UNU+1; mesaj(al_doilea); getch(); } void mesaj(intreg numar) /*definirea functiei mesaj*/ {printf("acesta este programul numarul %i\n", numar);}

Al treilea exemplu ilustrează folosirea funcţiilor în scopul simplificării scrierii unui program. Funcţia intrebare afişează pe ecran textul unei întrebări folosind funcţia de bibliotecă printf. Funcţia raspuns afişează pe ecran textul preluat de la utilizator prin intermediul funcţiei de

bibliotecă gets.

Exercitiul C #include <stdio.h> /*directive preprocesor*/ #include <conio.h> void intrebare(void) /* definirea functiilor */ {printf("Cum te cheama?\n");} void raspuns(char &nume) {printf("Ma bucur de cunostinta, %s\n",&nume);}

Page 223: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 211

void main(void) /* programul principal */ {char nume[50]; intrebare(); gets(nume); raspuns(*nume); getch(); }

Al patrulea exemplu este o variantă a celui de al treilea în care şirul de caractere al răspunsului este receptat în cuprinsul funcţiei intrebare. Astfel, programul principal este simplificat la maximum.

Exercitiul D #include <stdio.h> /*directive preprocesor*/ #include <conio.h> char * intrebare(void) /* definirea functiilor */ {char nume[100]; printf("Cum te cheama?\n"); gets(nume); return nume; } void raspuns(char &nume) {printf("Ma bucur de cunostinta, %s!\n", &nume);}

void main(void) /* programul principal */ {char * numestud; numestud=intrebare(); raspuns(*numestud); getch(); }

§10.3. Folosirea structurilor ca tipuri de date complexe În cadrul acestui exemplu este definită structura de date denumită punct2D reluîndu-se

aplicaţia prezentată la punctul 2.3.5. În cuprinsul funcţiei oglinda din Aplicaţia 1 este folosită tehnica de transfer a datelor prin

pointeri şi adrese cât şi aşa numitul efect lateral (vizibilitatea datelor prin intermediul adreselor comune programului principal şi funcţiei - se observă că funcţia oglindă nu returnează nici o valoare dar variabila pct este vizibilă din exterior). Această tehnică încalcă principiul încapsulării datelor în favoarea economiei de memorie. Folosirea ei necontrolată poate fi dăunătoare siguranţei aplicaţiei. Aplicaţia 1 pentru structuri #include <iostream.h> struct punct2D {float x,y;}; void oglinda_oy(struct punct2D *pct) {pct->x=-pct->x;} void main () {struct punct2D A={5,3}; cout << "Punctul original A are x=" << A.x << " si y=" << A.y << "\n"; oglinda_oy(&A); cout << "Punctul oglindit A' are x=" << A.x << " si y=" << A.y << "\n"; }

Page 224: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 212

În Aplicaţia 2 a fost evitată încălcarea principiului încapsulării datelor prin folosirea transferului datelor prin valoare (p1 şi p2 sunt copii interne ale valorilor a şi b din programul principal, iar pm este copiat în programul principal sub forma variabilei c). Aplicaţia 2 pentru structuri #include <iostream.h> typedef struct {float x,y;} punct2D; punct2D punct_mediu(punct2D p1, punct2D p2) {punct2D pm, ptemp; pm.x=0.5*(p1.x+p2.x); pm.y=0.5*(p1.y+p2.y); ptemp=p1; p1=p2; p2=ptemp; return pm; } void main () {punct2D a={0,0}, b={6,6}, c; cout << "a(" << a.x << "," << a.y << ")\n"; cout << "b(" << b.x << "," << b.y << ")\n"; cout << "c(" << c.x << "," << c.y << ")\n"; c=punct_mediu(a,b); cout << "a(" << a.x << "," << a.y << ")\n"; cout << "b(" << b.x << "," << b.y << ")\n"; cout << "c(" << c.x << "," << c.y << ")\n"; }

§10.4. Aplicaţii simple în C++ Aplicatia 1: Selectarea numerelor naturale dupa paritate. #include <iostream.h> #include <conio.h> void selpar(int nr) /* selectarea numarului par*/ {if((nr%2)!=0) cout << "x;"; else cout << nr << ";"; return; } void selimpar(int nr) /* selectarea numarului impar*/ {if((nr%2)==0) cout << "x;"; else cout << nr << ";"; return; } void main() {int a1,a2,a3,a4,a5,a6; cout << "\nIntroduceti 6 numere naturale!"; cout << "\na1="; cin >> a1; cout << "\na2="; cin >> a2; cout << "\na3="; cin >> a3; cout << "\na4="; cin >> a4; cout << "\na5="; cin >> a5; cout << "\na6="; cin >> a6; cout << "\nNumerele pare sunt:"; selpar(a1); selpar(a2); selpar(a3); selpar(a4); selpar(a5); selpar(a6); cout << "\nNumerele impare sunt:";

Page 225: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 213

selimpar(a1); selimpar(a2); selimpar(a3); selimpar(a4); selimpar(a5); selimpar(a6); cout << "\n"; getch(); }

Aplicatia 2: Suma primelor n numere naturale. #include <iostream.h> #include <conio.h> void main() {int suma=0,i=0,n; cout << "\nSpecificati numarul n:"; cin >> n; while(i<n){i++; suma=suma+i;} cout << "\nSuma primelor " << n << " numere naturale=" << suma << "\n"; getch(); } Aplicatia 3: Produsul primelor n numere naturale (factorial). #include <iostream.h> #include <conio.h> void main() {int prod=1,i=0,n; char c; cout << "\nSpecificati numarul n:"; cin >> n; while(i<n){i++; prod=prod*i;} cout << "\nFactorial de " << n << "=" << prod << "\n"; cin >> c; getch(); }

§10.5. Aplicaţii de utilizare a tablourilor

Aplicatia 1 - Incrementarea elementelor unui tablou #include <iostream.h> #include <conio.h> #define DIM1 2 #define DIM2 2

void increment(float tablou[DIM1][DIM2]) {int i,j; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) tablou[i][j]++; }

void tiptab(float tablou[DIM1][DIM2]) {int i,j; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) cout << "tabl(" << i << "," << j << ")=" << tablou[i][j] << "\n"; }

void main() {float tabl[DIM1][DIM2]={{11,12},{21,22}}; cout << "Tabloul initial\n";

Page 226: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 214

tiptab(tabl); increment(tabl); cout << "Tabloul incrementat\n"; tiptab(tabl); getch(); }

Aplicatia 2 - Determinarea elementului minim al unui tablou #include <iostream.h> #include <conio.h> #define DIM 5

float min2v(float a, float b) {return(a<b ? a : b);}

int sorttab(float tablou[DIM]) {int i,indmin; float valmin; valmin=tablou[0]; indmin=0; for(i=1;i<DIM;i++) {valmin=min2v(valmin,tablou[i]); if(valmin==tablou[i]) indmin=i; } return indmin; }

void tiptab(float tablou[DIM]) {int i; for(i=0;i<DIM;i++) cout << "tabl(" << i << ")=" << tablou[i] << "\n"; }

void main() {float tabl[DIM]={2,5,1,4,6}; int imin; cout << "Tabloul initial\n"; tiptab(tabl); imin=sorttab(tabl); cout << "Elementul minim din tablou este: tabl(" << imin << ")=" << tabl[imin] << "\n"; getch(); }

§10.6. Aplicaţii la transmiterea tablourilor ca pointeri Aplicaţia 1: tablouri unidimensionale #include <iostream.h> #include <conio.h> #define DIM 3

float cere_element(int i) {float elem; cout << "a(" << (i+1) << ")="; cin >> elem; cout << "\n"; return elem; }

Page 227: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 215

void afis_tablou(float *ptablou) {int i; for(i=0;i<DIM;i++) cout << "a(" << (i+1) << ")=" << *(ptablou+i) << "\n"; }

void main() {float tablou[DIM]; int i; float *ptablou; ptablou=tablou; cout << "Introduceti elementele tabloului\n"; for(i=0;i<DIM;i++) tablou[i]=cere_element(i); cout << "Elementele tabloului sunt:\n"; afis_tablou(ptablou); getch(); }

Aplicaţia 2: tablouri multidimensionale #include <iostream.h> #include <conio.h> #define DIM1 3 #define DIM2 2

float cere_element(int i, int j) {float elem; cout <<"a("<<(i+1)<<","<<(j+1)<<")=";cin>>elem;cout<<"\n"; return elem; } void afis_tablou(float **ptablou) {int i,j; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) cout <<"a("<<(i+1)<<","<<(j+1)<<")="<<*((*ptablou)+i*DIM2+j)<<"\n"; }

void main() {float tablou[DIM1][DIM2]; int i,j; float *ptablou; ptablou=*tablou; cout << "Introduceti elementele tabloului\n"; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) tablou[i][j]=cere_element(i,j); cout << "Elementele tabloului sunt:\n"; afis_tablou(&ptablou); getch(); }

§10.7. Alocarea dinamică a memoriei Un dezavantaj al limbajelor compilate (Fortran, Pascal, C, C++, etc) este alocarea fixă

de memorie, în cazul folosirii tablourilor. Pentru a lucra cu tablouri, compilatorul trebuie să cunoască mărimea acestuia şi să-i aloce

spaţiu de memorie. Acest spaţiu rămâne alocat pe toata durata vieţii programului, indiferent

Page 228: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 216

dacă spaţiul este folosit integral sau nu. În plus, încercarea de a folosi spaţiu peste cel alocat, se soldează cu o eroare de execuţie si cu abandonarea programului.

Limbajele interpretoare (Basic, LISP, s.a.), nu au, în general, acest dezavantaj, în schimb au viteza mică de execuţie.

Pentru a înlătura acest dezavantaj, păstrând în acelaşi timp şi avantajul vitezei mari de execuţie, limbajul C (şi C++) posedă funcţii de alocare/eliberare de memorie în cursul execuţiei. In acest caz, în loc de a utiliza tablouri, se foloseşte tehnica de lucru cu pointeri combinată cu folosirea funcţiilor de alocare/eliberare a memoriei.

Pentru alocarea memoriei, sub DOS, se foloseşte funcţia calloc care are prototipul: void *calloc(size_t nrart, size_t marime) unde: size_t este tipul de date de stocat; nrart este numărul de date de stocat; marime

este lungimea în octeţi a tipului de date de stocat. Pentru a scuti programatorul de cunoaşterea mărimii tipului în functie de implementarea limbajului C şi pentru a asigura portabilitatea programelor pe diferite platforme, se foloseşte funcţia sizeof(tip) la calculul mărimii în octeţi a tipului de date de stocat. Funcţia calloc alocă un spaţiu (bloc) de memorie de nrart*marime octeţi în memoria de bază si returneaza un pointer (void * înseamnă pointer către orice tip) către blocul de memorie alocat, sau valoarea NULL dacă nu a putut fi găsit disponibil pentru alocare spaţiul de memorie cerut sau dacă nrart sau marime este 0.

Functia calloc nu poate aloca mai mult de 64 Kbytes de memorie. O altă funcţie de alocare de memorie este malloc cu sintaxa: void *malloc(size_t marime)

care funcţioneaza asemănător, cu deosebirea că i se transmite un singur argument calculat anterior, şi anume marime=nrart*marime_tip

Eliberarea memoriei se face prin funcţia free cu sintaxa: void free(*bloc)

unde *bloc este pointerul către un bloc de memorie alocat anterior cu funcţia calloc sau malloc.

Schema generală de lucru la alocarea dinamică de memorie este: - calculul mărimii blocului de memorie de alocat; - alocarea blocului; - testarea succesului alocării: dacă alocarea a avut succes se execută exploatarea memoriei în scopul dorit; se eliberează memoria; altfel se emite mesaj de avertisment;

Exemplul 1. Alocarea de spatiu pentru un tablou unidimensional #include <iostream.h> #include <conio.h> #include <alloc.h> float cere_element(int i) {float elem; cout << "a(" << (i+1) << ")="; cin >> elem; cout << "\n"; return elem; } void afis_tablou(int n,float *tablou)

Page 229: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 217

{int i; for(i=0;i<n;i++) cout << "a(" << (i+1) << ")=" << *(tablou+i) << "\n"; }

void main() {int n,i; float *tablou; cout << "Specificati numarul de elemente ale tabloului, n="; cin >> n; tablou=(float *)calloc(n,sizeof(float)); if(tablou!=NULL) {cout << "\nIntroduceti elementele tabloului\n"; for(i=0;i<n;i++) *(tablou+i)=cere_element(i); cout << "Elementele tabloului sunt:\n"; afis_tablou(n,tablou); free(tablou); } else cout << "Alocare esuata!\n"; getch(); }

Testarea programului: 1. La cererea “Specificati numarul de elemente ale tabloului, n=” răspundeţi

introducând valoarea 0. Veţi obţine răspunsul “Alocare esuata!” 2. Acelaşi efect îl veţi obţine şi introducând valoarea 20000 (deoarece sizeof(float)=4,

nrart*sizeof(float)=4*20000>64 Kbytes); 3. Răspunzând cu o valoare corespunzătoare posibilităţilor funcţiei, de exemplu 5, rularea

programului va decurge normal.

Exemplul 2. Alocarea de spaţiu pentru un tablou bidimensional de caractere În acest exemplu fiecare dintre şirurile de caractere “SIR DE STOCAT IN MEMORIE”

este un tablou unidimensional format din valori de tip caracter. Acest tablou este iniţializat ca pointer. Variabila psir este un pointer către un pointer, constituind un tablou bidimensional. Alocarea de spaţiu pentru acest tablou a fost făcuta cu functia malloc astfel: mai întâi a fost alocat un bloc de memorie pentru un tablou care stocheaza pointerii catre pointeri (psir) şi apoi, de nrart ori, în acest tablou au fost stocaţi pointerii către blocurile de memorie în care se vor stoca ulterior şirurile “SIR DE STOCAT IN MEMORIE”.

Funcţia strcpy a fost folosită pentru a copia la adresele conţinute de aceşti pointeri şirurile de caractere menţionate.

Funcţia exit(1) produce încheierea forţată a programului. Eliberarea memoriei se face în ordine inversă: mai întâi se eliberează blocurile de

memorie alocate pentru şiruri şi apoi se eliberează blocul de memorie în care sunt stocaţi pointerii catre şiruri. #include <iostream.h> #include <conio.h> #include <alloc.h> #include <string.h> #include <stdlib.h>

void main() {char *sirstoc="SIR DE STOCAT IN MEMORIE"; char **psir; int nrart=5,i;

Page 230: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 218

if((psir=(char **) malloc(nrart*sizeof(char*)))==NULL) {cout << "Alocare esuata!\n"; exit(1);} else {for(i=0;i<nrart;i++) if( (psir[i]=(char *)malloc((strlen(sirstoc)+1)*sizeof(char))) ==NULL ) {cout << "Alocare esuata!\n"; exit(1);} else strcpy(psir[i],sirstoc); } cout << "Sirul " << sirstoc << " a fost alocat in " << nrart << "blocuri distincte.\n"; for(i=0;i<nrart;i++) cout << psir[i] << "\n"; cout << "Memoria pentru cele " << nrart << " blocuri \"" << sirstoc << "\"\n va fi eliberata apasand o tasta\n"; getch(); for(i=0;i<nrart;i++)free(psir[i]); free(psir); }

§10.8. Funcţii de acces la ecranul text Aplicaţia 1

#include <stdio.h> #include <conio.h> void main() {clrscr(); printf("Apasa o tasta pentru a sterge linia de la cursor pana la capat"); gotoxy(14,1); getch(); clreol(); printf("Apasa o tasta pentru a sterge tot ecranul"); getch(); clrscr(); printf("Apasa o tasta pentru a iesi din program"); getch(); }

Rezultatul rulării acestui program este apariţia succesivă pe prima linie a ecranului, la fiecare apăsare de tastă, a următoarelor afişări: Apasa o tasta_pentru a sterge linia de la cusor pana la capat Apasa o tastaApasa o tasta pentru a sterge tot ecranul Apasa o tasta pentru a iesi din program

Aplicaţia 2 #include <conio.h> void main() {int i,n=9; clrscr(); for(i=1;i<=n;i++) {gotoxy(i,i); cprintf("*");} for(i=1;i<=n;i++) {gotoxy(i,n+1-i); cprintf("*");} getch(); }

Rezultatul rulării acestui program este apariţia pe ecran a următoarei configuraţii:

Page 231: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 219

* *_ * * * * * * * * * * * * * * *

Aplicaţia 3 #include <conio.h> void main() {char tampon[62]; int i; clrscr(); gotoxy(10,10); cprintf("Text de control. Apasa o tasta."); getch(); gettext(10,10,40,10,tampon); for(i=1;i<=5;i++) {clrscr(); puttext(10+i,10,40+i,10,tampon); getch();} }

Rezultatul rulării acestui program este deplasarea textului afişat cu câte o poziţie către dreapta la fiecare apăsare a unei taste.

Textul are lungimea de 31 de caractere dar tabloul tampon în care este el stocat are lungime dublă (62) deoarece, pentru a fi manipulat prin funcţiile gettext şi puttext fiecare caracter trebuie memorat pe 2 octeţi, unul pentru codul ASCII al caracterului iar celălalt pentru codul de culoare.

Funcţia gettext culege textul existent pe ecran într-un dreptunghi cu coordonatele colţ stânga sus - colţ dreapta jos exprimate în coordonate întregi indice coloană, indice rând. Textul cules este memorat în tabloul tampon.

Funcţia puttext pune textul din tampon într-un dreptunghi cu coordonatele colţurilor exprimate în acelaşi mod.

Pentru detalii a se vedea HELP-ul mediului de programare.

Aplicaţia 4

Fig.10.8.1.

#include <conio.h> void main() {char sir[]="ABCDEFGHIJ"; int i; clrscr(); for(i=0;i<=7;i++) {gotoxy(10,10+i); textbackground(i); textcolor(i+1); cprintf(sir); } getch(); }

Rezultatul rulării acestui program este afişarea pe ecran a unei succesiuni de şiruri de text cu diferite culori pe diferite fonduri, ca în figura 10.8.1.

Afişarea are loc începând din coloana 10 şi de la rândul 10 în jos.

Page 232: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 220

§10.9. Accesul la ecranul grafic Următorul exemplu prezintă succesiunea unor etape de lucru cu ecranul grafic. Aplicaţia 1

#include <graphics.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <string.h>

void main() {/* parametrii de autodetectare grafica */ int gdriver = DETECT, gmode, errorcode; /* definirea unor date din program */ int i, maxcolor, maxx, maxy, xmed, ymed; char dest[40], mesaj[]="Numarul maxim de culori este ", numcolor[3]; /* initializarea tabloului sir de caractere de concatenare */ for(i=0;i<40;i++) dest[i]=0; /* initializarea modului grafic */ initgraph(&gdriver, &gmode, ""); /* citirea rezultatului initializarii */ errorcode = graphresult(); if (errorcode != grOk) /* daca a survenit o eroare */ {printf("Eroare grafica: %s\n", grapherrormsg(errorcode)); printf("Apasa o tasta pentru oprire:"); getch(); exit(1); /* iesire in caz de eroare */ } maxcolor=getmaxcolor(); /* numarul maxim de culori */ maxx=getmaxx(); /* numarul maxim de pixeli pe orizontala */ maxy=getmaxy(); /* numarul maxim de pixeli pe verticala */ xmed=maxx/2; /* coordonatele centrului ecranului */ ymed=maxy/2; /* pregatire pentru afisarea unui text grafic */ setcolor(MAGENTA); settextjustify(CENTER_TEXT,CENTER_TEXT); settextstyle(DEFAULT_FONT,HORIZ_DIR,2); /* text cu marime dubla */ itoa(maxcolor+1,numcolor,10); /* conversia din intreg in sir de

caractere exprimat zecimal */ strcat(dest,mesaj); /* concatenarea sirurilor de caractere */ strcat(dest, numcolor); outtextxy(xmed,ymed,dest); /* afisarea textului */ getch(); /* pauza pana la apasarea unei taste */ for(i=0;i<=maxcolor;i++) /* ciclare pentru toate culorile */ {setbkcolor(i); /* stabilirea culorii fondului */ cleardevice(); /* stergerea ecranului grafic */ setfillstyle(SOLID_FILL,maxcolor-i); /* stabilirea stilului si a

culorii de umplere */ bar(maxx/4,maxy/4,0.75*maxx,0.75*maxy); /* desenarea unui dreptunghi cu interiorul umplut */ getch(); /* pauza pana la apasarea unei taste */ } closegraph(); /* inchiderea dispozitivului grafic */ }

Page 233: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 221

Rezultatul rulării acestui program este desenarea unui text şi a unei succesiuni de fonduri de ecran şi de dreptunghiuri pline.

Următorul exemplu ilustrează modul de compunere a culorilor pe ecranul grafic DOS. Aplicaţia 2

#include <graphics.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <math.h> #include <alloc.h> #include <mem.h> /* definire structuri*/ struct centru {int x, y;}; struct imagine {void * bloc;}; /* functie de generare si stocare a imaginii */ imagine stocare_cerc(int culoare, centru cent, int raza) {imagine imag_cerc; int marime; /* stabilirea stilului si a culorii de umplere */ setfillstyle(SOLID_FILL,culoare); /* stabilirea culorii conturului */ setcolor(culoare); /* desenarea unui disc umplut */ pieslice(cent.x,cent.y,0,360,raza); /* determinarea marimii imaginii */ marime=imagesize(cent.x-raza,cent.y-raza,cent.x+raza,cent.y+raza); /* alocarea spatiului de memorie pentru stocarea imaginii */ imag_cerc.bloc=malloc(marime); /* stocarea imaginii in spatiul alocat */ getimage(cent.x-raza,cent.y-raza,cent.x+raza,cent.y+raza, imag_cerc.bloc); return imag_cerc; }

void main() {int gdriver = DETECT, gmode, errorcode; int maxx,maxy,xc,yc,raza=70,raza1,dist; centru c1, c2, c3, c4; imagine imag_cerc; void * cerc1, * cerc2, * cerc3, * cerc4; /* initializarea grafica */ initgraph(&gdriver, &gmode, ""); errorcode = graphresult(); if (errorcode != grOk) {printf("Eroare grafica: %s\n", grapherrormsg(errorcode)); printf("Apasa o tasta pentru oprire:"); getch(); exit(1); } /* calcul parametri geometrici */ maxx=getmaxx(); maxy=getmaxy(); xc=maxx/2; yc=maxy/2; dist=0.5*raza/cos(M_PI*30/180);

Page 234: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 222

c1.x=xc-0.5*raza; c1.y=yc-0.5*raza*tan(M_PI*30/180); c2.x=xc+0.5*raza; c2.y=c1.y; c3.x=xc; c3.y=yc+dist; c4.x=xc; c4.y=yc; /* stergerea ecranului, stabilirea culorii de fond */ cleardevice(); setbkcolor(0); /* generarea si stocarea succesiva a imaginilor */ imag_cerc=stocare_cerc(RED, c1, raza); cerc1=imag_cerc.bloc; imag_cerc=stocare_cerc(GREEN, c2, raza); cerc2=imag_cerc.bloc; imag_cerc=stocare_cerc(BLUE, c3, raza); cerc3=imag_cerc.bloc; raza1=0.8*raza; imag_cerc=stocare_cerc(DARKGRAY, c4, raza1); cerc4=imag_cerc.bloc; /* stergerea ecranului si afisarea aditionala a imaginilor */ cleardevice(); putimage(c1.x-raza,c1.y-raza,cerc1,OR_PUT); putimage(c2.x-raza,c2.y-raza,cerc2,OR_PUT); putimage(c3.x-raza,c3.y-raza,cerc3,OR_PUT); putimage(c4.x-raza1,c4.y-raza1,cerc4,OR_PUT); /* pauza de afisare */ getch(); /* eliberarea memoriei si inchiderea dispozitivului grafic */ free(cerc1); free(cerc2); free(cerc3); free(cerc4); closegraph(); }

Fig.10.9.1.

Cuvintele simbolice folosite pentru culori în C sub DOS, pentru majoritatea dispozitivelor grafice mai actuale, sunt date în tabelul de mai jos.

Page 235: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 223

Cod binar Cuvânt simbolic Culoare Valoare zecimală 0000LRGB

BLACK Negru 0 00000000 BLUE Albastru 1 00000001

GREEN Verde 2 00000010 CYAN Turcoaz 3 00000011 RED Roşu 4 00000100

MAGENTA Liliachiu 5 00000101 BROWN Brun 6 00000110

LIGHTGRAY Gri deschis 7 00000111 DARKGRAY Gri închis 8 00001000 LIGHTBLUE Albastru deschis 9 00001001

LIGHTGREEN Verde deschis 10 00001010 LIGHTCYAN Turcoaz deschis 11 00001011 LIGHTRED Roşu deschis 12 00001100

LIGHTMAGENTA Liliachiu deschis 13 00001101 YELLOW Galben 14 00001110 WHITE Alb 15 00001111

§10.10. Aplicaţie grafică pentru construcţia diagramelor Aplicaţia 1

#include <conio.h> #include <iostream.h> #include <graphics.h> #define NINT 100 #define NPCT NINT+1

void sir_val_func (int ordin, float termeni[], int nvalsir_x, float sir_x[], float sirval[]) {int i,j; for(i=0;i<nvalsir_x;i++) {sirval[i]=termeni[ordin]; for(j=ordin-1;j>=0;j--) sirval[i]=termeni[j]+sirval[i]*sir_x[i]; } } float valmax(int nval, float sir_val[]) {int i; float vmax; vmax=sir_val[0]; for(i=1;i<nval;i++) if(vmax<sir_val[i]) vmax=sir_val[i]; return vmax; } float valmin(int nval, float sir_val[]) {int i; float vmin; vmin=sir_val[0]; for(i=1;i<nval;i++) if(vmin>sir_val[i]) vmin=sir_val[i]; return vmin; } void desen_diag(float sir_valx[], float sir_valy[], int x1, int y1, int lung, int inalt, int culfond, int culdiag, int culcadru, char *titlu) {float xmin, xmax, ymin, ymax, scx, scy;

Page 236: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 224

int i; viewporttype vinfo; settextstyle(DEFAULT_FONT,HORIZ_DIR,2); settextjustify(CENTER_TEXT,CENTER_TEXT); setcolor(YELLOW); outtextxy(x1+lung/2,0.5*y1,titlu); getviewsettings(&vinfo); setviewport(x1,y1,x1+lung,y1+inalt,1); setfillstyle(SOLID_FILL,culfond); bar(0,0,lung,inalt); xmin=valmin(NPCT,sir_valx); xmax=valmax(NPCT,sir_valx); ymin=valmin(NPCT,sir_valy); ymax=valmax(NPCT,sir_valy); scx=(xmax-xmin)/lung; scy=(ymax-ymin)/inalt; if(scy==0) scy=1; setcolor(culdiag); setlinestyle(SOLID_LINE,0,3); for(i=0;i<NINT;i++) line((sir_valx[i]-xmin)/scx,inalt-(sir_valy[i]-ymin)/scy, (sir_valx[i+1]-xmin)/scx,inalt-(sir_valy[i+1]-ymin)/scy); setcolor(culcadru); setlinestyle(SOLID_LINE,0,1); rectangle(0,0,lung,inalt); setviewport(vinfo.left,vinfo.top,vinfo.right,vinfo.bottom,vinfo.clip); }

void main() {float fx[NPCT], x[NPCT], term[NINT], xs, xd, dx; int ord, i, dispgr=DETECT, modgr; int xmaxecran, ymaxecran, lungdiag, inaltdiag, xc, yc; cout << "Introduceti ordinul polinomului: "; cin >> ord; for(i=0;i<=ord;i++) {cout << "a(" << i << ")="; cin >> term[i];} cout << "Introduceti domeniul de calcul: "; cout << "x minim="; cin >> xs; cout << "x maxim="; cin >> xd; initgraph(&dispgr, &modgr, ""); xmaxecran=getmaxx(); ymaxecran=getmaxy(); setbkcolor(BROWN); clrscr(); dx=(xd-xs)/NINT; for(i=0;i<NPCT;i++) x[i]=xs+i*dx; sir_val_func(ord,term,NPCT,x,fx); cleardevice(); lungdiag=0.4*xmaxecran; inaltdiag=0.8*ymaxecran; xc=0.25*xmaxecran; yc=0.5*ymaxecran; desen_diag(x,fx,xc-lungdiag/2,yc-inaltdiag/2,lungdiag,inaltdiag, LIGHTMAGENTA,BLUE,LIGHTCYAN,"FUNCTIA"); ord=ord-1; /* Calculul coeficientilor derivatei polinomului */ for(i=0;i<=ord;i++) term[i]=(i+1)*term[i+1]; sir_val_func(ord,term,NPCT,x,fx); desen_diag(x,fx,xmaxecran/2+xc-lungdiag/2,yc-inaltdiag/2,lungdiag, inaltdiag,LIGHTMAGENTA,RED,LIGHTCYAN,"DERIVATA"); getch(); }

Explicaţii În funcţia sir_val_func se calculează valorile unei funcţii polinomiale într-un sir de puncte

x pe baza formulei iterative:

Page 237: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 225

f(x)=a0+a1x1+a2x2+a3x3+...+an-1xn-1+anxn=a0+x(a1+x(a2+x(a3+... +x(an-1+x(an))...))) Derivata polinomului este:

f '(x)=a1+2a2x1+3a3x2+...+(n-1)an-1xn-2+nanxn-1 şi este tratată la fel ca şi funcţia.

Fig.10.10.1.

Funcţiile valmin şi valmax extrag valoarea minimă şi pe cea maximă dintr-un şir de valori. Funcţia desen diag afişează diagrama functiei. Programul permite desenarea diagramelor unui polinom şi a derivatei acestuia pentru orice

ordin. Ca rezultat al rulării lui pentru setul de valori: ordin = 2 a[0]= -4 a[1]= 0 a[2]= 1 x minim = -3 x maxim = 3 se va obţine afişarea din figura 10.10.1.

Aplicaţie grafică folosind structuri cu membri funcţii Următoarea aplicaţie este o restructurare a primei aplicaţii. Aici diferitele valori ale

diagramei apar ca proprietăţi ale unui obiect, iar funcţiile de generare ale diagramei apar ca metode de tratare a datelor obiectului diagramă. Deşi încă nu este vorba de o programare orientată pe obiecte în sensul actual al noţiunii, aplicaţia prefigurează această tehnică de programare. #include <conio.h> #include <iostream.h> #include <graphics.h> #define NINT 100 #define NPCT NINT+1

typedef struct {int ordin; float termeni[NPCT], sir_x[NPCT], sir_y[NPCT], xs, xd;

Page 238: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 226

int xdiag1, ydiag1; char * titlu; int lung, inalt, culfond, culdiag, culcadru; /* functii membre ale structurii */ void sir_val_func(void); float valmax(int, float *); float valmin(int, float *); void desen_diag(void); } diagrama; /* definitiile functiilor membre ale structurii */ void diagrama::sir_val_func(void) {int i,j; for(i=0;i<NPCT;i++) {sir_y[i]=termeni[ordin]; for(j=ordin-1;j>=0;j--) sir_y[i]=termeni[j]+sir_y[i]*sir_x[i]; } } float diagrama::valmax(int nval, float sir_val[]) {int i; float vmax; vmax=sir_val[0]; for(i=1;i<nval;i++) if(vmax<sir_val[i]) vmax=sir_val[i]; return vmax; } float diagrama::valmin(int nval, float sir_val[]) {int i; float vmin; vmin=sir_val[0]; for(i=1;i<nval;i++) if(vmin>sir_val[i]) vmin=sir_val[i]; return vmin; } void diagrama::desen_diag(void) {float xmin, xmax, ymin, ymax, scx, scy; int i; viewporttype vinfo; settextstyle(DEFAULT_FONT,HORIZ_DIR,2); settextjustify(CENTER_TEXT,CENTER_TEXT); setcolor(YELLOW); outtextxy(xdiag1+lung/2,0.5*ydiag1,titlu); getviewsettings(&vinfo); setviewport(xdiag1,ydiag1,xdiag1+lung,ydiag1+inalt,1); setfillstyle(SOLID_FILL,culfond); bar(0,0,lung,inalt); xmin=valmin(NPCT,sir_x); xmax=valmax(NPCT,sir_x); ymin=valmin(NPCT,sir_y); ymax=valmax(NPCT,sir_y); scx=(xmax-xmin)/lung; scy=(ymax-ymin)/inalt; if(scy==0) scy=1; setcolor(culdiag); setlinestyle(SOLID_LINE,0,3); for(i=0;i<NINT;i++) line((sir_x[i]-xmin)/scx,inalt-(sir_y[i]-ymin)/scy, (sir_x[i+1]-xmin)/scx,inalt-(sir_y[i+1]-ymin)/scy); setcolor(culcadru); setlinestyle(SOLID_LINE,0,1); rectangle(0,0,lung,inalt); setviewport(vinfo.left,vinfo.top,vinfo.right,vinfo.bottom,vinfo.clip); }

Page 239: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 227

void main() {float dx; int i, dispgr=DETECT, modgr, xmaxecran, ymaxecran, xc, yc; diagrama diagfunc, diagderiv; cout << "Introduceti ordinul polinomului: "; cin >> diagfunc.ordin; for(i=0;i<=diagfunc.ordin;i++) {cout << "a(" << i << ")="; cin >> diagfunc.termeni[i];} cout << "Introduceti domeniul de calcul: "; cout << "x minim="; cin >> diagfunc.xs; cout << "x maxim="; cin >> diagfunc.xd; initgraph(&dispgr, &modgr, ""); xmaxecran=getmaxx(); ymaxecran=getmaxy(); setbkcolor(BROWN); clrscr(); dx=(diagfunc.xd-diagfunc.xs)/NINT; for(i=0;i<NPCT;i++) diagfunc.sir_x[i]=diagfunc.xs+i*dx; diagfunc.sir_val_func(); cleardevice(); diagfunc.lung=0.4*xmaxecran; diagfunc.inalt=0.8*ymaxecran; diagfunc.culfond=LIGHTMAGENTA; diagfunc.culdiag=BLUE; diagfunc.culcadru=LIGHTCYAN; diagfunc.titlu="FUNCTIA"; xc=0.25*xmaxecran; yc=0.5*ymaxecran; diagfunc.xdiag1=xc-diagfunc.lung/2; diagfunc.ydiag1=yc-diagfunc.inalt/2; diagfunc.desen_diag(); diagderiv=diagfunc; diagderiv.ordin=diagderiv.ordin-1; for(i=0;i<=diagderiv.ordin;i++) diagderiv.termeni[i]=(i+1)*diagderiv.termeni[i+1]; diagderiv.sir_val_func(); diagderiv.xdiag1=xmaxecran/2+xc-diagderiv.lung/2; diagderiv.culdiag=RED; diagderiv.titlu="DERIVATA"; diagderiv.desen_diag(); getch(); }

Au fost folosite două structuri: diagfunc pentru diagrama funcţiei şi diagderiv pentru diagrama derivatei.

Deoarece o anumită parte dintre datele diagramei derivatei sunt aceleaşi ca şi pentru diagrama funcţiei, instrucţiunea diagderiv=diagfunc copiază toate aceste date de la o structură la alte, ulterior fiind modificate numai datele diferite.

Se observă că scrierea programului principal devine mai explicită şi, totodată, mai flexibilă, chiar dacă aparent, sunt ceva mai multe instrucţiuni de scris. Această impresie este falsă deoarece aplicaţia este de mică amploare. În realitate, în cazul aplicaţiilor mari, programele devin mai scurte, deoarece se manevrează numai asupra datelor şi doar sunt invocate funcţiile de tratare din cazul structurilor.

§10.11. Aplicaţie grafică la utilizarea claselor Vom relua aplicaţia anterioară făcând un pas înainte prin introducerea conceptului de clasă.

Acesta permite crearea de obiecte, adică de module de program care, pe lângă date, conţine şi metodele de tratare a acestora.

În aplicaţia de mai jos este creată clasa de obiecte diagrama care conţine ca date două membre structuri:

Page 240: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 228

- structura de tip datefunctie denumită dfun şi - structura de tip paramdiag denumită pdiag. Structura dfun conţine datele de tratat de către clasă şi anume: tabloul termeni care

conţine coeficienţii polinomului, tabloul sir_x care conţine şirul de valori x în care este discretizat intervalul dintre limita stânga xs şi dreapta xd, şi tabloul sir_y care conţine valorile calculate ale polinomului în punctele din sir_x.

Structura pdiag conţine parametrii de constructie şi afişare ai diagramei, şi anume:

dimensiunile în pixeli ai ecranului xmaxecran şi ymaxecran, coordonatele ecran ale colţului din stânga sus al diagramei xdiag1 şi ydiag1, un pointer către şirul de caractere de afişat ca titlu al diagramei, lungimea şi lăţimea în coordonate ecran ale diagramei lung şi inalt, şi codurile de culoare pentru fondul diagramei (culfond), curba diagramei (culdiag) şi chenarul diagramei (culcadru).

În cadrul clasei este definită o funcţie constructor de copiere cu autoreferire denumită

copie_date. Ea serveşte la copierea unei instanţe a clasei într-o alta, cu scopul de a reduce numărul de instrucţiuni de stabilire a caracteristicilor unei diagrame dacă ele sunt deja definite în obiectul diagramă sursă.

Astfel, după ce este creat obiectul diafun pentru diagrama polinomului şi îi sunt definite caracteristicile, obiectul nou creat diaderiv pentru diagrama derivatei va copia instanţa diafun şi vor fi stabilite prin declaraţiile corespunzătoare numai acele caracteristici care diferă de acelea ale diagramei polinomului. #include <conio.h> #include <iostream.h> #include <graphics.h> #define NINT 100 #define NPCT NINT+1 /* definitii de structuri de date */ struct datefunctie {int ordin; float termeni[NPCT], sir_x[NPCT], sir_y[NPCT], xs, xd; };

struct paramdiag {int xmaxecran, ymaxecran, xdiag1, ydiag1; char * titlu; int lung, inalt, culfond, culdiag, culcadru; }; /* definirea clasei de obiecte pentru generarea de diagrame */ class diagrama {public: /* datele membre ale clasei */ datefunctie dfun; paramdiag pdiag; /* functiile membre ale clasei */ diagrama& copie_date(diagrama& sursa) /* constructor de copiere cu autoreferire */ {dfun=sursa.dfun; pdiag=sursa.pdiag; return * this;}; void sir_val_func(void); /* generarea valorilor funcţiei */ float valmax(int, float *); /* extragerea valorii maxime dintr-un sir */ float valmin(int, float *); /* extragerea valorii minime dintr-un sir */

Page 241: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 229

void desen_diag(void); /* desenarea diagramei */ };

/* definitiile functiilor membre ale clasei */ void diagrama::sir_val_func(void) {int i,j; for(i=0;i<NPCT;i++) {dfun.sir_y[i]=dfun.termeni[dfun.ordin]; for(j=dfun.ordin-1;j>=0;j--) dfun.sir_y[i]=dfun.termeni[j]+dfun.sir_y[i]*dfun.sir_x[i]; } }

float diagrama::valmax(int nval, float sir_val[]) {int i; float vmax; vmax=sir_val[0]; for(i=1;i<nval;i++) if(vmax<sir_val[i]) vmax=sir_val[i]; return vmax; }

float diagrama::valmin(int nval, float sir_val[]) {int i; float vmin; vmin=sir_val[0]; for(i=1;i<nval;i++) if(vmin>sir_val[i]) vmin=sir_val[i]; return vmin; }

void diagrama::desen_diag(void) {float xmin, xmax, ymin, ymax, scx, scy; int i; viewporttype vinfo; settextstyle(DEFAULT_FONT,HORIZ_DIR,2); settextjustify(CENTER_TEXT,CENTER_TEXT); setcolor(YELLOW); outtextxy(pdiag.xdiag1+pdiag.lung/2,0.5*pdiag.ydiag1,pdiag.titlu); getviewsettings(&vinfo); setviewport(pdiag.xdiag1,pdiag.ydiag1, pdiag.xdiag1+pdiag.lung,pdiag.ydiag1+pdiag.inalt,1); setfillstyle(SOLID_FILL,pdiag.culfond); bar(0,0,pdiag.lung,pdiag.inalt); xmin=valmin(NPCT,dfun.sir_x); xmax=valmax(NPCT,dfun.sir_x); ymin=valmin(NPCT,dfun.sir_y); ymax=valmax(NPCT,dfun.sir_y); scx=(xmax-xmin)/pdiag.lung; scy=(ymax-ymin)/pdiag.inalt; if(scy==0) scy=1; setcolor(pdiag.culdiag); setlinestyle(SOLID_LINE,0,3); for(i=0;i<NINT;i++) line((dfun.sir_x[i]-xmin)/scx,pdiag.inalt-(dfun.sir_y[i]-ymin)/scy, (dfun.sir_x[i+1]-xmin)/scx,pdiag.inalt-(dfun.sir_y[i+1]-ymin)/scy); setcolor(pdiag.culcadru); setlinestyle(SOLID_LINE,0,1); rectangle(0,0,pdiag.lung,pdiag.inalt); setviewport(vinfo.left,vinfo.top,vinfo.right,vinfo.bottom,vinfo.clip); } void main() {float dx; int i, dispgr=DETECT, modgr; diagrama diafun; /* este creat obiectul diafun */

Page 242: Programarea Calculatoarelor si Limbaje de Programare

Cap.10. Aplicaţii de programare în C şi C++ 230

/* se definesc datele diagramei */ cout << "Introduceti ordinul polinomului: "; cin >> diafun.dfun.ordin; for(i=0;i<=diafun.dfun.ordin;i++) {cout << "a(" << i << ")="; cin >> diafun.dfun.termeni[i];} cout << "Introduceti domeniul de calcul: "; cout << "x minim="; cin >> diafun.dfun.xs; cout << "x maxim="; cin >> diafun.dfun.xd; dx=(diafun.dfun.xd-diafun.dfun.xs)/NINT; /* se genereaza sirul de valori x pe intervalul de definitie */ for(i=0;i<NPCT;i++) diafun.dfun.sir_x[i]=diafun.dfun.xs+i*dx; diafun.sir_val_func(); /* se genereaza sirul de valori al functiei */ initgraph(&dispgr, &modgr, ""); /* initializarea grafica */ cleardevice(); /* stergerea ecranului */ setbkcolor(BROWN); /* stabilirea culorii ecranului */ /* se definesc parametrii grafici de afisare ai diagramei */ diafun.pdiag.xmaxecran=getmaxx(); diafun.pdiag.ymaxecran=getmaxy(); diafun.pdiag.lung=0.4*diafun.pdiag.xmaxecran; diafun.pdiag.inalt=0.8*diafun.pdiag.ymaxecran; diafun.pdiag.xdiag1=0.25*diafun.pdiag.xmaxecran-diafun.pdiag.lung/2; diafun.pdiag.ydiag1=0.5*diafun.pdiag.ymaxecran-diafun.pdiag.inalt/2; diafun.pdiag.culfond=LIGHTMAGENTA; diafun.pdiag.culdiag=BLUE; diafun.pdiag.culcadru=LIGHTCYAN; diafun.pdiag.titlu="FUNCTIA"; diafun.desen_diag(); /* se deseneaza diagrama polinomului */ diagrama diaderiv; /* se creaza obiectul diaderiv */ diaderiv.copie_date(diafun); /* se copiaza diafun in diaderiv */ /* se modifica datele din diaderiv diferite de cele din diafun */ /* se definesc coeficientii derivatei polinomului */ diaderiv.dfun.ordin=diaderiv.dfun.ordin-1; for(i=0;i<=diaderiv.dfun.ordin;i++) diaderiv.dfun.termeni[i]=(i+1)*diafun.dfun.termeni[i+1]; diaderiv.sir_val_func(); /* se genereaza valorile derivatei */ /* se definesc parametrii grafici diferite */ diaderiv.pdiag.xdiag1=0.75*diaderiv.pdiag.xmaxecran-diaderiv.pdiag.lung/2; diaderiv.pdiag.ydiag1=0.5*diaderiv.pdiag.ymaxecran-diaderiv.pdiag.inalt/2; diaderiv.pdiag.culfond=CYAN; diaderiv.pdiag.culdiag=RED; diaderiv.pdiag.titlu="DERIVATA"; diaderiv.desen_diag(); /* se deseneaza diagrama derivatei */ getch(); }

Se observă că prin această tehnică programul principal, funcţia main, s-a redus la o succesiune de atribuiri de valori pentru datele membre ale obiectelor clasei diagrama, şi la invocarea funcţiilor membre.

Diagrama care se obţine pentru datele: ordin = 2 a[0]= -4 a[1]= 0 a[2]= 1 x minim = -3 x maxim = 3 este aceea prezentată în figura 10.11.1.

Page 243: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 231

Aceasta este o metodă de lucru foarte avantajoasă. Pe lângă uşurinţa manevrării obiectelor în cadrul programului, apare şi posibilitatea ca, o dată ce un obiect a fost pus la punct, el să fie stocat în biblioteci de tip fişiere antet (header, cu extensia .h) de unde să poată fi extras prin instrucţiunea #include. În programarea orientată pe obiecte folosită în WINDOWS, această tehnică este folosită cu preponderenţă şi, mai mult, chiar limbaje necompilate cum este Visual BASIC prezent în mediile de dezvoltare integrate din diferite aplicaţii, prin convenţiile limbajului reproduc procedeele acestei tehnici.

Fig.10.11.1.

Page 244: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 232

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL

§11.1. Generalităţi privind lucrul în EXCEL

11.1.1. Structura documentelor EXCEL EXCEL este un program de calcul

tabelar destinat elaborării documentelor interactive.

Un document EXCEL, denumit mapă de lucru, este un fişier cu numele nume.XLS compus dintr-un număr de foi de lucru.

O foaie de lucru este o arie de celule organizate pe rânduri şi pe coloane.

În funcţie de formatul paginii imprimantei, aria de celule determinată de dreptunghiul de încadrare al celulelor nevide extreme se extinde pe un anumit număr de pagini de imprimare. Aşadar, noţiunile de foaie de lucru şi pagină de imprimare sunt distincte şi nu trebuie confundate (a se vedea figura 11.1.1).

Un rând este identificabil prin antetul de rând care poartă un număr între 1 şi 65536.

Fig.11.1.1.

O coloană este identificabilă prin antetul de coloană care poartă un simbol literal A...Z, AA...AZ, BA...BZ,...IV (în total 256 coloane).

Celula este situată la intersecţia dintre o coloană şi un rând şi este identificată prin referinţă. Referinţa celulei este combinaţia indicatorilor de rând şi de coloană care se intersectează

în celulă. Stilul referinţei este modul în care se simbolizează referinţa. Deosebim următoarele stiluri: • Stilul A1, în care celula se indică prin combinaţia: simbol_coloană indice_rând De exemplu: $C$5 este celula de la intersecţia coloanei C cu rândul 5; • Stilul R1C1, foloseşte combinaţia: indice_rând indice_coloană. De exemplu, celula C5 apare în acest stil cu notaţia R5C3 (rândul 5 coloana 3); Tipul referinţei poate fi: • Absolut, când este indicată poziţia celulei în foaia de lucru. De exemplu: $C$5 sau R5C3; • Relativ, când este indicată poziţia unei celule în raport cu celula curentă. De exemplu:

celula D3 în raport cu celula C5, în stilul R1C1 relativ, are simbolizarea R[-2]C[1]; • Mixt. De exemplu, aceeaşi celulă D3 în raport tot cu celula C5 poate fi simbolizată în

forma R[-2]C4.

11.1.2. Conţinutul celulelor O celulă poate conţine următoarele tipuri de date: • Şir de text, adică o combinaţie de maxim 255 de caractere tipăribile; • Număr, alcătuit din cifre şi caractere speciale ca:

+ sau - pentru semn; separator zecimal (. sau , în funcţie de setarea regională a sistemului WINDOWS 9X);

Page 245: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 233

/ pentru fracţii; $ pentru stilul monetar; % pentru procent; E sau e pentru exponentul zecimal din notaţia ştiinţifică.

Formatele pentru numere pot fi: întreg, zecimal fracţionar şi zecimal ştiinţific; • Dată calendaristică şi marcă de timp; • Valori logice: TRUE sau FALSE; • Coduri de eroare:

#DIV/0! Împărţire cu zero; #N/A Valoare lipsă; #NAME? Nume invalid al unei celule referită prin nume; #NULL! Intersecţie de domenii vidă; #REF! Referinţă invalidă; #VALUE! Valoare incorectă; ###....## Spaţiu insuficient pentru afişare;

• Referinţă, caz în care celula gazdă a conţinutului afişează conţinutul celulei referite; • Formule şi funcţii, caz în care celula gazdă afişează rezultatul evaluării formulei sau

funcţiilor. 11.1.3. Utilizarea formulelor şi funcţiilor 11.1.3.1. Formule O formulă este constituită din operatori şi operanzi şi începe întotdeauna cu caracterul “=”. • Operatorii pot fi: • Operatori aritmetici: + pentru adunare, - pentru scădere, * pentru înmulţire, / pentru

împărţire, % pentru procent (după o valoare), ^ pentru ridicare la putere; • operatorul de concatenare de texte: &. De exemplu, formula =”Tasta”&”tura” are ca

rezultat şirul de text “Tastatura”; • Operatori de referinţe la celule:

: se foloseşte pentru a indica un domeniu. De exemplu, A2:C4 reprezintă celulele cu tentă gri din figura 11.1.2;

spaţiul este folosit pentru a indica o interscţie de domenii. De exemplu, A3:C2 B2:C4 reprezintă celula B3 din figura 11.1.3;

, se foloseşte pentru la enumerarea elementelor dintr-o uniune. De exemplu, A2:A4,C2:C4 reprezintă uniunea domeniilor marcate cu gri din figura 11.1.4.

Fig.11.1.2. Fig.3. Fig.11.1.4.

• Operanzii pot fi:

Fig.11.1.5.

• valori constante; • referinţe la celule sau domenii de celule; • funcţii predefinite sau definite de utilizator.

Formulele pot conţine paranteze rotunde ( ) pentru separarea grupurilor de operaţii.

Page 246: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 234

11.1.3.2. Exemplu de utilizare a formulelor. Calculul perimetrului şi suprafeţei cercului Pentru a construi un tabel de calcul al perimetrului şi suprafaţei unui cerc (figura 11.1.5) se

procedează astfel: În celula B1 se scrie valoarea razei, în acest caz 10; În celula B2 se scrie formula =3.14*B1*2 În celula B3 se scrie formula =3.14*B1^2

Ca urmare, celulele B2 şi B3 vor afişa rezultatul calculelor.

Orice modificare a valorii din celula B1 se reflectă imediat prin reafişarea automată a celulelor implicate care vor conţine noul rezultat.

Atenţie! Nu scrieţi din greşeală altceva în celulele B2 şi B3 pentru că formulele conţinute în ele vor fi şterse.

Observaţie: referinţa B1 nu trebuie scrisă de la tastatură ci este suficient să fie selectată printr-un clic pe celula B1. EXCEL va scrie singur în formulă referinţa celulei selectate. Acest lucru este de mare ajutor pentru că scuteşte utilizatorul de a urmări indicii de rând şi de coloană în scopul aflării simbolizării referinţei. De asemenea,

procedeul este valabil şi pentru formule mai complexe ca şi pentru funcţii care necesită indicarea ca argumente a unor domenii. Selectarea unui domeniu se face prin “tragere” peste domeniul dorit.

Fig.11.1.6.

11.1.3.3. Funcţii EXCEL predefinite EXCEL conţine o varietate mare de funcţii predefinite sau native, organizate pe

categorii. Accesul la funcţiile predefinite EXCEL se face prin apăsarea butonului fx. Acesta se

găseşte pe bara de scule Standard. La apăsarea acestui buton se deschide cutia de dialog Paste Function, figura 11.1.6.

Din cutia de listare Function Category se selectează categoria de funcţii dorită. Din cutia de listare Function Name se selectează funcţia dorită şi apoi se apasă pe butonul Next. Ca urmare, se deschide o cutia de dialog ulterioară al cărei aspect depinde de funcţia selectată. Se furnizează parametrii ceruţi de funcţie şi apoi se apasă pe butonul OK.

11.1.4. Formatarea celulelor Formatul este modalitatea de afişare a rezultatelor (conţinutului) celulelor. Pentru stabilirea

formatului unor celule care, în prealabil, trebuie selectate, din meniul Format se selectează articolul Cells. Ca urmare se deschide cutia de dialog Format Cells care conţine 6 pagini:

• Number. Această pagină conţine controale de formatare a categoriilor de conţinut următoare: - General (conţinut general); - Number (conţinut numeric); - Currency (afişare în stil monetar în funcţie de setările regionale ale sistemului WINDOWS); - ... - Percentage (afişare în procente); - Fraction (afişare în formă de fracţie); - Scientific (afişare în format ştiinţific - este utilă pentru numere foarte mari);

Page 247: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 235

- Text (este ignorat caracterul conţinutului care este tratat ca un simplu text). • Alignment. Această pagină conţine controale de aliniere a afişării rezultatului evaluării

conţinutului celulei. • Font. Această pagină conţine controale de stabilire a tipului de caracter folosit, mărime

culoare şi stil de scriere. • Border. Această pagină conţine controale de stabilire a trasării chenarului celulei. • Patterns. Această pagină conţine controale de stabilire a modelului de umplere a celulei. • Protection. Această pagină conţine controale de protejare a celulei, controale care au

efect numai dacă şi foaia de lucru este protejată. Pentru operare rapidă, pe bara de scule Formatting există butoane care asigură o parte

dintre operaţiile de formatare accesibile din cutia de dialog Format Cells fără a mai fi necesară deschiderea acesteia.

O combinaţie de atribute de formatare constituie un stil. Stilul poate fi memorat cu o denumire, folosind cutia de dialog Style care se deschide din meniul Format, articolul Style. O dată memorat, stilul poate fi aplicat altor celule.

11.1.5. Macro comenzi şi macro funcţii Un macro este un grup de acţiuni sau de operaţii, identificate printr-un nume. Acţiunile

şi operaţiile conţinute de macro sunt scrise în limbajul Visual Basic într-o anexă specială a documentului, denumită modul, gestionată de editorul de macrocomenzi.

Macro-urile sunt de două tipuri: • macro-comandă, constând dintr-o secvenţă de operaţii înregistrate cu ajutorul

înregistratorului de macro-uri. Acesta scrie operaţiile înregistrate sub forma unei subrutine în limbaj Visual Basic. Macro-comenzile pot consta chiar din subrutine scrise direct de către utilizator;

• macro-funcţie, constând dintr-o funcţie în limbaj Visual Basic scrisă de către utilizator.

11.1.5.1. Înregistrarea macro-comenzilor Înregistratorul de macrocomenzi este o facilitate EXCEL care permite: • declanşarea înregistrării, din meniul Tools > Macro > Record New Macro; • înregistrarea oricărei acţiuni efectuată de utilizator pe durata cât înregistratorul este activ: • oprirea înregistrării, din meniul Tools > Macro > Stop Recording; Ca rezultat, este creată acea anexă specială a documentului care conţine module de Visual

Basic. Ca structură, anexa pentru module apare ca un container denumit Modules, în care sunt conţinute modulele denumite “Modulej”, j=1,2,3,..., în care EXCEL scrie automat o subrutină conţinând secvenţa de instrucţiuni în limbaj Visual Basic corespunzătoare acţiunilor înregistrate. Macro-ul scris are structura următoare:

'Linii de 'comentariu Sub nume_de_macro() secventa de instructiuni End Sub

Numele nume_de_macro este numele introdus de utilizator în câmpul de editare din cutia de dialog Record New Macro, sau atribuit automat de EXCEL sub forma “Macroj”, j=1,2,3...

Accesul la editorul de Visual Basic se face din meniul Tools>Macro>Visual Basic Editor. 11.1.5.2. Execuţia unei macro-comenzi O macro-comandă poate fi executată în două moduri: • Prin declanşare explicită din meniul Tools > Macro >Macros ⇒ cutia de dialog

Page 248: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 236

Macro. De aici, din cutia de listare Macro Name se selectează numele macro-comenzii dorite şi se apasă butonul Run;

• Prin asociere cu un element de interacţiune grafică (meniu sau buton) definit de utilizator.

11.1.5.3. Definirea unei macro-funcţii Vom explica acest subiect printr-o aplicaţie, relativ la figura 11.1.5, conform următoarelor etape: • Ne situăm într-un modul de Visual Basic, în care scriem funcţia:

Function Supraf_cerc(Raza) Supraf_cerc=3.1418*Raza^2

End Function

• Se revine într-o foaie de lucru; • Într-o celulă, de exemplu în celula B1, scriem valoarea 10; • Într-o altă celulă, de exemplu în celula B3, se face un clic pentru a o selecta; • Se scrie caracterul = • Se apasă butonul fx. Ca urmare, se deschide cutia de dialog Paste Function; • Din cutia de listare Function Category se selectează categoria User Defined, iar din

cutia de listare Function Name se selectează funcţia Supraf_cerc şi se apasă butonul OK. Se deschide cutia de dialog Supraf_cerc;

• Se introduce argumentul Raza prin selectarea celulei B1 şi se apasă butonul OK; • Ca urmare, în celula B3 apare afişat rezultatul evaluării ariei cercului cu raza având

mărimea conţinută în celula B1.

11.1.5.4. Asocierea unei macro-comenzi cu un element de interacţiune O macro-comandă poate fi asociată cu un element de interacţiune cu utilizatorul în două moduri: • Prin asociere cu un obiect grafic de comandă sau cu un buton de comandă creat

într-o foaie de lucru. Sunt necesare următoarele etape de lucru: • Crearea obiectului grafic de comandă:

- Se apasă butonul Drawings din bara de scule Standard. Ca urmare, se deschide bara cu scule Drawings; - Din bara cu scule Drawings se foloseşte o sculă pentru desenarea unui obiect grafic mărginit de un contur închis (dreptunghi sau elipsă); - Se aplică obiectului creat formate de aspectualizare (culoare, contur, etc), eventual este grupat cu o cutie de text prin care i se asociază şi o denumire; - Se selectează obiectul (grupul) grafic cu ajutorul butonului dreapta al mouse-ului. Ca urmare se deschide meniul contextual care conţine articolul Assign Macro.

• Crearea obiectului grafic de comandă: - Din meniul View>Toolbars>Forms ⇒ se deschide cutia cu scule Forms; - Se selectează scula Button şi se desenează butonul de comandă; - Se selectează butonul existent cu ajutorul butonului dreapta al mouse-ului. Ca urmare se deschide meniul contextual care conţine articolul Assign Macro.

• Asocierea butonului cu macro-comanda: - Prin selectarea articolului Assign Macro, se deschide cutia de dialog Assign Macro. Din cutia de listare Macro Name se selectează numele macrocomenzii dorite apoi se apasă butonul OK. În acest moment asocierea este stabilită şi orice apăsare a butonului asociat va declanşa macro-comanda asociată cu el.

Page 249: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 237

Sau: - Dacă macrocomanda nu există în momentul încercării de asociere, ea poate fi creată. Pentru aceasta, în câmpul de editare Macro Name din cutia de dialog Assign Macro, se scrie numele noii macro-comenzi şi apoi se apasă butonul Record. În continuare se execută operaţia de înregistrare a acţiunilor utilizatorului. La terminarea acesteia butonul este asociat cu macro-comanda înregistrată.

• Prin asociere cu un articol de meniu definit de utilizator. Pentru a crea un meniu nou, se procedează astfel: - se selectează o foaie pentru module; - din meniul Tools > Customize. Se deschide cutia de dialog Customize; - se operează în cutia de dialog Customize (cum anume, se va vedea la aplicaţii). Un meniu EXCEL este o structură arborescentă pe mai multe nivele. El se compune dintr-

un nume de meniu, submeniuri şi articole. Articolele meniului pot fi asociate cu macro-comenzi.

§11.2. Utilizarea programului EXCEL pentru crearea unui document de

calcul simplu: calculul variaţiilor unor funcţii şi crearea unei diagrame centralizatoare

11.2.1. Intrarea în program Din butonul Start, se selectează articolul de lansare a programului Excel, conform

configurării specifice a calculatorului pe care se lucrează. Ca urmare, apare fereastra EXCEL din fig.11.2.1.

Fig.11.2.1.

11.2.2. Operaţii elementare frecvente 11.2.2.1. Operaţii de selectare - Selectare de foaie de lucru unică: clic simplu cu butonul stânga mouse pe eticheta de foaie;

Page 250: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 238

- Selectarea unui sir de foi consecutive (de exemplu, foile din şirul Sheet3,4,5,6): = se face clic pe eticheta primei foi din şir (Sheet3); = se apasă tasta SHIFT şi se menţine apăsată; = se face clic pe eticheta ultimei foi din şir (Sheet6); = se eliberează tasta SHIFT. - Selectarea unui şir de foi neconsecutive (de exemplu şirul Sheet3,5,7,9): = se face clic pe eticheta primei foi din sir (Sheet3); = se apasă tasta CTRL şi se menţine apăsată; = se face clic pe eticheta următoarei foi din sir (Sheet5), apoi Sheet7, etc; = se eliberează tasta CTRL. - Selectarea unui domeniu de celule: regulile sunt asemănatoare cu cele pentru selectarea foilor; - Selectarea unui domeniu rectangular de celule: se face clic pe un colţ al domeniului, se menţine

apăsat butonul stânga mouse, se trage în diagonală pâna la colţul opus şi se eliberează butonul. - Selectarea unui întreg rând sau coloană de celule: se face clic pe antetul de rând sau de coloană; - Selectarea unui şir de rânduri sau coloane: asemanator ca la etichetele de foi, dar pe antete. 11.2.2.2. Operaţia de mutare a unei entităţi (foaie, celulă, rând, coloană) - Se selectează entitatea; - Se poziţioneaza cursorul pe chenarul selecţiei până la apariţia formei de săgeată; - Se trage în noua poziţie. Sau: - Se selectează entitatea de mutat; - Cu cursorul poziţionat pe entitatea selectată, se selectează articolul Cut din meniul

contextual, - sau din meniul Edit, se selectează articolul Cut. Efectul obţinut este de a şterge entitatea

din fişier transferând-o în memoria tampon (Clipboard); - Se selectează entitatea în faţa căreia se va face inplantarea entităţii transferate în memoria

tampon; - Cu ajutorul articolului Paste din meniul Edit sau din meniul contextual se face implantarea. 11.2.2.3. Operaţia de copiere a unei entităţi Se face analog cu mutarea, dar cu tasta CTRL apăsată în timpul operaţiei de tragere, sau

folosind articolul Copy în locul articolului Cut. 11.2.2.4. Operaţia de inserare a unei entităţi - Se face selectarea entităţii în faţa căreia se va introduce noua entitate (de acelaşi tip); - Din meniul Insert se selectează articolul Cells, Rows, sau Columns. 11.2.2.5. Operaţia de ştergere a unei entităţi - se selectează entitatea de şters; - se apasă tasta Delete, sau se selectează articolul articolul Delete din meniul Edit sau din

meniul contextual. 11.2.2.6. Intrarea în regimul de editare intracelulară - Se selectează celula vizată prin simplu sau dublu clic şi se începe editarea. - editarea poate fi facută direct în celulă sau pe bara pentru formule. 11.2.3. Aranjarea convenabilă a documentului Deoarece în această aplicaţie este necesară o singură foaie tabelară, vom păstra numai foaia

Page 251: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 239

de lucru Sheet1. Celelalte foi, Sheet2, Sheet3 (şi eventual altele) vor fi şterse. Pentru aceasta se face selectarea şirului de foi consecutive Sheet2,..., etc (vezi punctul 11.2.2.1), după care se operează ştergerea şirului (vezi punctul 11.2.2.5).

11.2.4. Crearea tabelului Tabelul conţine valorile de calcul pentru funcţiile şi ( )f x 1 e x= − − ( ) ( )g x 1 e x= − ⋅ −cos x- Se selectează domeniul dreptunghiular de celule de la C3 la E14 (vezi punctul 11.2.2.1); - Se aplică formatele de chenar necesare pentru a desena tabelul din figura 11.2.2, cu

ajutorul butonului sculă Borders de pe bara de scule Formatting; - Se completează capul de tabel; - Se completează celulele de tabel de la C4 la C14 cu valorile de la 0 la 10 ale coordonatei x; - Celulele de la D4 la D14 conţin formulele de calcul pentru f(x). De exemplu, celula D4

va conţine formula =1-EXP(-C4). Funcţia EXP se obţine prin apăsarea butonului fx de pe bara cu scule Standard sau de pe bara de editare, cu care se deschide cutia de dialog Function Wizard. De aici, din categoria Math&Trig se selectează funcţia EXP. Argumentele funcţiilor se introduc prin punctare pe celulele argumente. Formulele celorlalte celule se completează asemănător.

- Celulele de la E4 la E14 conţin formulele de calcul pentru g(x). De exemplu, celula D4 va conţine formula =1-COS(X)*EXP(-C4). Completarea se face la fel ca mai înainte.

Fig.11.2.2.

11.2.5. Crearea diagramei centralizatoare O diagramă este reprezentarea grafică a unor dependenţe reciproce ale unor mărimi. În

acest caz, ne propunem să reprezentăm grafic dependenţa mărimilor x, f(x), şi g(x). Etapele de lucru sunt următoarele: - Pe rând, se selectează: domeniul de valori al abscisei x (inclusiv capul de tabel) adică

domeniul $C$3:$C$14, apoi domeniul de valori al funcţiei f adică domeniul $D$3:$D$14 şi

Page 252: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 240

apoi domeniul de valori al funcţiei g adică domeniul $D$3:$D$14. La selectare se foloseşte tehnica de "tragere" separat pentru fiecare şir vertical de celule. Înainte de a se trece la al doilea şir de celule se apasă tasta CTRL şi se ţine apăsată cât timp durează selecţia (la fel şi pentru al treilea şir de celule pentru valorile funcţiei g).

Fig.11.2.3. Fig.11.2.4.

- Din meniul Insert > Chart > As New Sheet, se declanşează procedura de creare a unei diagrame într-o foaie distinctă (nouă), care va conţine numai diagrama. Această procedură foloseşte setul de cutii de dialog Chart Wizard Step n of 4, unde n=1...4;

- Este foarte probabil că EXCEL îşi va alege singur tipul de diagramă Column. În cazul nostru este necesară alegerea tipulu Scatter şi deci se va face un clic pe acest tip, pentru a-l selecta (fig.3.). Ca subtip de diagramă se va alege tipul cu curbă continuă. După aceasta se apasă butonul Next. Ca urmare se deschide cutia de dialog Chart Wizard Step 2 of 4 (figura 11.2.4);

- De aici se selectează opţiunea Series in Columns. După ce se apasă butonul Next se deschide cutia Chart Wizard Step 3 of 4 (figura 11.2.5). Aici se scriu şirurile de text

care vor apare ca inscripţii pentru titlul diagramei (Diagrame functii), denumirea abscisei x şi denumirile funcţiilor f,g.

Fig.11.2.5.

- După ce se apasă din nou butonul Next este afişată cutia de dialog Chart Wizard Step 4 of 4 unde se selectează opţiunea As new sheet pentru a se realiza o diagramă în foaie separată.

Dacă ne aflăm la prima încercare reuşită de construcţie a diagramei, foaia cu diagrama capătă automat numele Chart1 şi va avea aspectul din figura 11.2.6.

Page 253: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 241

Fig.11.2.6.

11.2.6. Crearea de macrocomenzi prin înregistrare EXCEL dispune de o tehnică de mare ajutor, atât pentru utilizatori cât şi pentru

programatori, care constă din scrierea automată de programe în limbaj Visual BASIC prin simpla înregistrare a acţiunilor utilizatorului, fără ca acesta să aibă nevoie să cunoască limbajul.

Un macro, sau macrocomanda, este o succesiune de acţiuni care pot fi executate printr-o singura activare. EXCEL are posibilitatea de inregistra acţiunile efectuate de utilizator între o pornire şi o oprire a inregistrarii. Trebuie să fiti atenti pentru ca EXCEL inregistreaza absolut tot, inclusiv greselile.

Vom înregistra următoarele acţiuni: 11.2.6.1. Comutare de la foaie de lucru la foaie de diagramă

Fig.11.2.7.

Fig.11.2.8.

Pentru comutare între foaia Sheet1 şi foaia Chart1, etapele de lucru sunt următoarele:

- Se selectează meniul Tools > Macro > Record New Macro. Ca urmare, se deschide cutia de dialog Record Macro, figura 11.2.7.

În câmpul Macro Name, în loc de numele de macrocomandă atribuit automat Macro1, se scrie numele PrezDiag şi se apasă butonul OK.

- Ca urmare, apare bara cu scule Stop Recording, figura 11.2.8, conţinând butonul de

Page 254: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 242

oprire a înregistrării (cel cu pictograma de forma unui pătrat negru). Înregistrarea poate fi oprită şi cu meniul Tools > Macro > Stop Recording. Toate acţiunile efectuate de utilizator până la oprirea înregistrării vor fi transpuse în limbaj Visual BASIC într-o foaie specială (foaie de module de program) care, dacă ne aflăm la prima înregistrare va purta numele de Module1. Este nevoie de multă atenţie pentru a înregistra strict ceea ce este necesar şi pentru a nu uita să fie oprită înregistrarea;

- Din foaia de lucru Sheet1 se apasă eticheta de foaie Chart1; - Se opreşte înregistrarea. Ca urmare, în foaia Module1 va apare scris următorul modul de

program: Sub PrezDiag() Sheets("Chart1").Select End Sub Se observă că modulul scris este de tip subrutină şi conţine numai instrucţiunea de

selectare a foii Chart1. 11.2.6.2. Comutarea de la foaia de diagramă la foaia de lucru Procedeul de lucru este asemănător. Trebuie să ne găsim în foaia Chart1, să pornim

înregistratorul de macrocomenzi, să selectăm eticheta Sheet1 şi să oprim înregistratorul. Vom atribui macrocomenzii numele PrezFoaie. Modulul de program scris va fi următorul:

Sub PrezFoaie() Sheets("Sheet1").Select End Sub Macrocomenzile înregistrate pot fi activate cu meniul Tools > Macro, sau pot fi asociate

ulterior cu un obiect de interacţiune grafică. 11.2.7. Crearea de obiecte de interacţiune grafică 11.2.7.1. Crearea unui buton de comutare din foaia de lucru în foaia cu diagrama Dacă priviţi din nou figura 11.2.2 veţi observa un buton mare cu inscripţia “Diagrama”. Pentru a crea un buton se procedează astfel: - Se selectează meniul View>Toolbars>Forms. Ca urmare se deschide bara cu

instrumente Forms (fig.11.2.11.); - Se desenează butonul prin tehnica "drag and drop"; - Imediat ce desenarea s-a terminat se deschide cutia de dialog Assign Macro (fig. 11.2.9.)

- Se selectează macrocomanda PrezDiag şi se apasă butonul OK;

Fig.11.2.9.

- Butonul rămâne selectat (marcat cu mânere), sau poate fi selectat pentru modificare, folosind butonul dreapta al mouse-ului. Se intră prin clic cu butonul stânga şi se schimbă numele atribuit automat (Button1) cu numele Diagrama.

11.2.7.2. Crearea unui buton de comutare din foaia cu diagrama în foaia de lucru

Procedura de lucru este identică: se selectează foaia Chart1, se generează butonul Revenire (vezi figura 11.2.6), şi se asociază acest buton cu macrocomanda PrezFoaie.

Page 255: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 243

Folosind butoanele Diagrama şi Revenire, un utilizator care nu cunoaşte modul de lucru în EXCEL se poate plimba uşor şi sigur din foaia cu tabela în foaia cu diagrama.

11.2.7.3. Crearea unei cutii de dialog pentru comutarea de la tabel la diagramă Macrocomenzile pot fi asociate şi cu alte obiecte de interacţiune grafică, cum ar fi cutiile

de dialog. O cutie de dialog este o resursă de interacţiune specială care se crează într-o foaie specială, numită foaie de dialog. Aceasta este o facilitate mai veche a Excel-ului, în prezent tolerată, dar foarte accesibilă programatorului începător prin simplitatea sa mult mai mare decât noua tehnică de creare de resurse în mediul integrat Visual BASIC.

În continuare este prezentată o aplicaţie simplă care realizează acelaşi lucru cu butonul intitulat Diagrama bilantului, având în plus şi posibilitatea de a renunţa la procedura de comutare.

Etapele de lucru sunt următoarele: 1. Se plasează cursorul mouse-ului pe eticheta de foaie de lucru curentă şi se face clic pe

butonul dreapta; Din meniul contextual deschis acum articolul Insert, după care, din cutia de dialog Insert,

din pagina General se selectează pictograma MS Excel 5.0 Dialog. Ca urmare este creată o foaie nouă, specială,

denumită Dialog1.

Fig.11.2.10.

În această foaie este plasată automat o cutie de dialog sumară (figura 11.2.10). Elementele ei sunt: un cadru cu bară de titlu (Dialog Frame), şi două butoane (Button) cu inscripţiile OK şi Cancel.

Aceste obiecte pot fi: - selectate printr-un clic în cuprinsul lor; - apucate şi trase (mutate); - apucate şi derivate ca mărime;

- cele care posedă inscripţii, prin dublu clic pe inscripţie, pot fi aduse în faza de editare (modificare) a inscripţiei;

- selectate şi şterse (cu tasta Del); - selectate şi supuse operaţiilor Cut, Copy şi Paste; - selectate şi formatate (cu meniul Format, articolul Object, sau cu meniul contextual,

articolul Format Object). Alăturat cutiei de dialog în construcţie, se găseşte o cutie cu butoane denumite scule. Cutia

are titlul Forms iar butoanele au destinaţiile notate în figura 11.2.11. 2. Se face dublu clic în bara de titlu a cutiei de dialog şi se schimbă titlul din Dialog

Caption în Afisare Diagrama; 3. Se redenumeşte butonul OK cu numele Da şi butonul Cancel cu numele Nu; 4. Se redimensionează cutia de dialog şi se reamplasează butoanele Da şi Nu conform

dispunerii din figura 11.2.2; 5. Cu cursorul poziţionat pe butonul selectat (de exemplu pe butonul Da) se deschide

meniul contextual, din care se selectează articolul Format Control sau se selectează meniul Format, articolul Control. Ca urmare, se deschide cutia de dialog Format Control care, pentru butonul Da (fostul buton OK), are conţinutul paginii Control conform figurii 11.2.12.

6. În câmpul Accelerator Key se scrie caracterul D. Aceasta va apare subliniat pe inscripţia butonului Da şi, ca urmare, va face ca tasta D să devină tastă acceleratoare, adică se va putea acţiona butonul Da nu numai prin apăsare cu cursorul dirijat de mouse ci şi prin apăsarea tastei D;

Page 256: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 244

7. Se procedează la fel pentru butonul Nu, atribuindu-i-se ca tastă acceleratoare caracterul N;

Observaţie: nu operaţi alte modificări în cutia Format Object, pentru că se poate altera specificul de acţiune al butonului selectat.

8. Se selectează meniul Tools > Record Macro > Record New Macro. În cutia de dialog Record New

Macro se atribuie numele PrezDialog macrocomenzii a cărei înregistrare se va efectua. Ca urmare, înregistratorul de macrocomenzi este pornit;

Fig.11.2.11.

9. Se apasă butonul Run Dialog de pe bara cu scule Forms. Cutia de dialog este afişată aşa cum apare ea când este folosită în dialogul cu utilizatorul;

10. Se apasă butonul Nu al cutiei de dialog definită de utilizator;

11. Se opreşte înregistrarea macrocomenzii. Ca urmare, în foaia de module apare modulul de program următor:

Fig.11.2.12.

Sub PrezDialog() DialogSheets("Dialog1").Show End Sub

12. Se selectează butonul Da; 13. Se selectează meniul Tools, articolul Assign Macro, sau, din meniul contextual se

selectează articolul Assign Macro; 14. Din cutia de dialog Assign Macro se selectează macrocomanda PrezDiag pentru a fi

asociată butonului Da. Prin aceste procedee a fost creată cutia de dialog. Dacă ea este activă (afişată), apăsarea pe

butonul Da produce comutarea pe foaia cu diagrama. Totuşi, a mai rămas de rezolvat o problemă: cum să fie afişată însăşi cutia de dialog creată? Există o posibilitate şi anume, selectarea meniului Tools, articolul Macro. Se deschide

cutia de dialog Macro din care se selectează macrocomanda PrezDialog. Această posibilitate este utilizabilă numai pentru testare, în practică fiind necesară încă o asociere, de data aceasta între macrocomanda PrezDialog şi un obiect grafic. Acest obiect grafic poate fi un buton creat de utilizator (ca butonul Diagrama de mai înainte).

11.2.8. Salvarea fişierului Din meniul File, se selectează articolul Save As şi se atribuie numele, de exemplu

Diagfunc.

Page 257: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 245

§11.3. Folosirea înregistrărilor de macrocomenzi în construirea aplicaţiilor

11.3.1. Fazele de realizare a unei aplicaţii prin folosirea înregistratorului de macrocomenzi

Construirea unei aplicaţii "de la zero", înţelegând prin aceasta scrierea programelor necesare instrucţiune cu instrucţiune, este o tehnică laborioasă, mare consumatoare de timp şi efort din partea programatorului, acesta fiind solicitat să reţină în memorie un mare volum de denumiri de obiecte, metode şi proprietăţi ale obiectelor. Pe de altă parte, programatorul trebuie să conceapă şi schemele de acţiune cu obiectele, lucru care se reflectă printr-o anumită succesiune a instrucţiunilor de scris în program, succesiune care, dacă nu este corectă, conduce la obţinerea altor efecte decât cele urmărite.

Pentru aceste motive, în practica construirii aplicaţiilor în Visual BASIC pentru EXCEL, se foloseşte o metodă combinată. Baza conceptuală a tehnicii de lucru este tot metoda top-down, aplicată în următoarea succesiune de faze:

1. Se analizează aplicaţia de programat şi se elaborează o listă a procedurilor (subrutinelor) componente;

2. Dintre procedurile stabilite mai sus se selectează acelea care pot fi rezolvate total sau parţial folosind tehnicile de lucru manuale (neprogramate);

3. Se foloseşte tehnica de înregistrare a macrocomenzilor pentru a realiza subrutine scrise automat de către înregistratorul de macrocomenzi pentru procedurile de la punctul 2;

4. Subrutinele realizate la punctul 3 se modifică folosind mediul Visual BASIC, pentru a se realiza acele funcţionalităţi care nu pot fi create prin înregistrarea de macrocomenzi şi pentru a se mări gradul de generalitate şi aplicabilitate;

5. Se scriu manual procedurile care nu fi create prin tehnica de înregistrare de macrocomenzi;

6. Se asamblează întreaga aplicaţie prin armonizarea (punerea de acord) a diferitelor proceduri între ele.

Succesiunea de mai sus ar fi incompletă dacă nu ar fi luată în considerare şi interdependenţa evenimentelor.

În realitate, faţă de programarea procedurală care "vede" un program ca pe o succesiune prestabilită de evenimente, programarea orientată pe obiecte "vede" o aplicaţie ca pe un "univers" de obiecte, univers în care au loc evenimente într-o ordine destul de liberă şi la care obiectele participă prin acţiunile pe care le pot efectua. Stările pe care obiectele le pot căpăta în urma evenimentelor din universul lor trebuie bine analizate şi luate în considerare la realizarea componentelor aplicaţiei (fazele 1...5), precum şi la asamblarea ei în faza 6.

În continuare vom exemplifica cele expuse mai sus printr-o aplicaţie de construire a diagramei unei funcţii definite prin puncte.

11.3.2. Definirea problemei Fie o funcţie y=f(x) definită prin 5 puncte: Pi(xi,yi), i=1,...,5. Punctele pot fi date la întâmplare, urmând ca apoi să fie sortate în ordinea crescătoare a

valorilor abscisei x. Se cere să se genereze diagrama funcţiei y, a derivatei ei dy/dx şi a integralei pe domeniul

de definiţie dintre xmin şi xmax. 11.3.3. Rezolvarea neprogramată Pentru început, vom rezolva problema prin mijloacele obişnuite ale EXCEL-ului, fără a

face uz de facilităţile de programare.

Page 258: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 246

Etapele de lucru sunt următoarele:

Fig.11.3.1.

- Se crează liniatura tabelelor din figura 11.3.1, în foaia de lucru Sheet1;

- Se completează tabelele astfel:

= Se completează capelele de tabel cu inscripţiile din figura 11.3.1;

= În celulele A2:A6 se scriu valorile absciselor x (0.5, 1.0, 1.5, 2.0, 3.0);

= În celulele B2:B6 se scriu valorile ordonatelor y (0.7, 1.0, 1.5, 2.5, 2.0);

Fig. 11.3.2.

= În celula D3 se introduce formula =A3-A2 (adică x2-x1);

= Se selectează celula D3 şi, prin tragere de mânerul de extindere al celulei, se extinde formula din celulă pe domeniul celulelor D4...D6;

= În celula E3 se introduce formula =B3-B2 (adică f(x2)-f(x1));

= Se selectează celula E3 şi, prin tragere de mânerul de extindere al celulei, se extinde formula din celulă pe domeniul celulelor E4...E6;

= În celula F3 se introduce formula =E3/D3 (adică (f(x2)-f(x1))/ (x2-x1) care constituie formula aproximativă de derivare laterală la stânga);

= Se selectează celula F3 şi, prin tragere de mânerul de extindere al celulei, se extinde formula din celulă pe domeniul celulelor F4...F6;

= În celula G3 se introduce formula =0.5*(B3+B2) (adică 0.5*[f(xi+1)-f(xi)]); = Se selectează celula G3 şi, prin tragere de mânerul de extindere al celulei, se extinde

formula din celulă pe domeniul celulelor G4..G6; = În celula H2 se introduce valoarea 0 (adică se iniţializează formula de integrare prin

însumare a metodei trapezelor); = În celula H3 se introduce formula =H2+G3*D3 (adică formula de integrare prin

metoda trapezelor); = Se selectează celula H3 şi, prin tragere de mânerul de extindere al celulei, se extinde

formula din celulă pe domeniul celulelor H4..H6; - Se crează diagramele y=f(x), ∫ydx şi dy/dx astfel:

= Se selectează domeniul de celule A2:B6; = Se apasă tasta CTRL şi, menţinând-o apăsată, se selectează domeniul de celule

H2:H6;

Page 259: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 247

Fig.11.3.3.

= De pe bara de instrumente Standard a foii de lucru, se apasă butonul Chart Wizard. Se procedează ca la lucrarea de laborator 11.2: diagramă de tip Scatter (perechi x,y dispersate), dar specificând subtipul Scatter with data points connected by lines;

= La pasul 2 (Step 2 of 4 - figura 11.3.2) se comută în pagina Series a cutiei de dialog Chart Wizard şi:

~ se schimbă denumirea seriei 1 de date din Series1 în y=f(x) prin scrierea noului nume în câmpul Name;

~ se aplică un clic pe articolul Series2 şi se schimbă denumirea seriei 2 de date din Series2 în integrala, la fel ca mai sus;

~ se aplică un clic pe butonul Add pentru a se crea o serie nouă de date. Aceasta se denumeşte derivata;

~ la seria nou creată se aplică un clic în câmpul X values (eventual se şterge conţinutul acestuia dacă există vreunul) apoi, din foaia de lucru cu datele diagramei, se selectează domeniul de celule A3:A6;

~ se aplică un clic în câmpul Y values (eventual se şterge conţinutul acestuia dacă există vreunul) apoi, din foaia de lucru cu datele diagramei, se selectează domeniul de celule F3:F6; = Restul operaţiilor de construire a diagramelor decurge după cum se cunoaşte de la

lucrarea 11.2, cu efectul final de creare a unei diagrame în foaie separată (Chart1), având aspectul din figura 11.3.3 (după unele ajustări).

11.3.4. Rezolvarea programată. Automatizarea aplicaţiei O automatizare completă, în sensul generării în întregime a tabelului, implantării

formulelor de calcul, şi generării diagramei, în condiţiile unui număr variabil de perechi de puncte x,y este mult mai laborioasă.

De aceea, în continuare, ne vom mulţumi cu o automatizare parţială a aplicaţiei în sensul introducerii datelor şi a sortării lor în ordinea crescătoare a valorilor coordonatelor x.

Pentru a se putea vedea datele introduse anterior, trebuie realizată comutarea în foaia de lucru Sheet1. Pentru aceasta, ca la lucrarea anterioară, se va comuta în foaia pentru diagramă Chart1 şi se va înregistra comutarea în foaia de lucru Sheet1. Va fi creată subrutina Afisare_date, cu componenţa de mai jos:

Page 260: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 248

Sub Afisare_date() Sheets("Sheet1").Select End Sub Pentru a se putea vizualiza diagrama, analog, se înregistrează comutarea în foaia Chart1.

Va fi creată subrutina Afisare_diagrama cu componenţa de mai jos: Sub Afisare_diagrama() Sheets("Chart1").Select End Sub

Pentru a se putea sorta datele introduse nesortate se va opera procedeul următor:

Fig.11.3.4.

- În tabelul din foaia Sheet1 se inversează primele două perechi de puncte (sau oricare altele);

- Se porneşte înregistratorul de macrocomenzi (Tools>Macro>Record New Macro) indicând ca nume de macro denumirea Sortare_tabel;

- Se selectează o celulă din tabelul x,y (fie aceasta chiar A1);

- Din meniul Data, se activează articolul Sort...; - Ca urmare, datele de sub capul de tabel vor apare

selectate şi va fi afişată cutia de dialog Sort (figura 4); - Se verifică dacă în câmpul Sort by este selectat

criteriul x (aspectul cutiei trebuie să fie cel din figura 11.3.4);

- Se apasă butonul OK; - Se opreşte înregistratorul de macrocomenzi. Acum tabelul redevine ordonat după valorile crescătoare ale lui x. În plus, este creată

subrutina Sortare_tabel, cu componenţa de mai jos: Sub Sortare_Tabel() Range("A1").Select Selection.Sort Key1:=Range("A2"), Order1:=xlAscending, Header:=xlGuess, _ OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom End Sub Pentru introducerea valorilor putem folosi o cutie de dialog ca aceea din figura 11.3.5. Deoarece

operaţiile de introducere sunt simple, putem folosi o cutie de dialog de tip vechi, din categoria MS Excel 5.0 Dialog (vezi lucrarea 11.2.2, punctul 11.2.7.3). Va fi creată foaia de dialog Dialog1.

În această cutie de dialog facem următoarele operaţii: - Se redenumeşte butonul OK cu denumirea Acceptare şi i se atribuie tasta acceleratoare A; - Se redenumeşte butonul Cancel cu denumirea Revocare şi i se atribuie tasta acceleratoare R; - Folosind instrumentul Label din cutia cu instrumente Forms se crează etichetele x1...x5 şi y1...y5; - Folosind instrumentul Edit Box din cutia cu instrumente Forms se crează câmpurile de

editare alăturate etichetelor. La creare aceste obiecte primesc denumiri automate de tipul Edit Box j, unde j are o valoare numerică oarecare. Deoarece este incomod (neintuitiv) să se folosească aceste denumiri, le putem schimba astfel: printr-un clic se selectează câmpul de editare dorit; se aplică un clic pe câmpul Name Box din partea stânga-sus a ferestrei cutiei de dialog - ca efect denumirea existentă va fi selectată şi afişată în video negativ; se scrie noua denumire. Vom folosi denumiri identice cu inscripţiile etichetelor;

Pentru a se putea folosi cutia de dialog creată se va utiliza înregistratorul de macrocomenzi pentru crearea unei subrutine de afişare a cutiei de dialog. Aceasta se realizează la fel ca la §.11.2, punctul 11.2.7.3. se va obţine subrutina de mai jos:

Page 261: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 249

Sub Afisare_dialog_date()

Fig.11.3.5.

DialogSheets("Dialog1").Show End Sub Din acest moment posibilităţile de interfaţare folosind

macrorecorderul au fost epuizate. Pentru a se putea opera efectiv cu cutia de dialog Dialog1, trebuie elaborate subrutine de gestiune prin scrierea manuală a instrucţiunilor necesare.

Se vor scrie următoarele subrutine în foaia de module Module1:

- Subrutină de preluare a coordonatelor unui punct din foaia de lucru Sheet1 în câmpul de editare corespunzător al cutiei de dialog Dialog1:

Sub Prelevare_punct(celx, cely, rand) DialogSheets("Dialog1").EditBoxes(celx).Text = _ Application.Worksheets("Sheet1").Cells(rand, 1) DialogSheets("Dialog1").EditBoxes(cely).Text = _ Application.Worksheets("Sheet1").Cells(rand, 2) End Sub - Subrutină de iniţializare a coordonatelor punctelor afişate de cutia de dialog Dialog1: Sub Initializare_coordonate() Prelevare_punct "x1", "y1", 2 Prelevare_punct "x2", "y2", 3 Prelevare_punct "x3", "y3", 4 Prelevare_punct "x4", "y4", 5 Prelevare_punct "x5", "y5", 6 End Sub - Subrutină de introducere în foaia de lucru Sheet1 a coordonatelor unui punct preluate din

câmpurile corespunzătoare ale cutiei de dialog Dialog1: Sub Introducere_punct(celx, cely, rand) Application.Worksheets("Sheet1").Cells(rand, 1) = _ Val(DialogSheets("Dialog1").EditBoxes(celx).Text) Application.Worksheets("Sheet1").Cells(rand, 2) = _ Val(DialogSheets("Dialog1").EditBoxes(cely).Text) End Sub - Subrutină de introducere în foaia de lucru Sheet1 a coordonatelor celor 5 puncte preluate

din câmpurile cutiei de dialog Dialog1: Sub Introducere_coordonate() Introducere_punct "x1", "y1", 2 Introducere_punct "x2", "y2", 3 Introducere_punct "x3", "y3", 4 Introducere_punct "x4", "y4", 5 Introducere_punct "x5", "y5", 6 End Sub - Subrutina de introducere a datelor în foaia de lucru Sheet1. Este apelabilă când cutia de

dialog Dialog1 este afişată în foaia de lucru Sheet1. Apelează subrutina Introducere_coordonate şi apoi sortează tabelul prin apelul subrutinei Sortare_Tabel:

Sub Introducere_date() Introducere_coordonate Sortare_Tabel End Sub

Page 262: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 250

- Subrutină de introducere a datelor. Produce comutarea în foaia de lucru Sheet1, apelează afişarea cutiei de dialog Dialog1, apoi comută înapoi în foaia pentru diagramă Chart1.

Sub Introd_coord() Afisare_date Afisare_dialog_date Afisare_diagrama End Sub De asemenea, se modifică subrutina Afişare_dialog_date, astfel: Sub Afisare_dialog_date() Initializare_coordonate DialogSheets("Dialog1").Show End Sub În final, folosind comanda Assign Macro, se fac următoarele asocieri buton-

macrocomandă: - butonul Introducere date noi din foaia Sheet1 se asociază cu subrutina

Afisare_dialog_date; - butonul Afişare Diagramă din foaia Sheet1 se asociază cu subrutina Afisare_diagrama; - butonul Introducere date noi din foaia Chart1 se asociază cu subrutina Introd_coord; - butonul Vedere date din foaia Chart1 se asociază cu subrutina Afisare_date. §11.4. Folosirea funcţiilor definite de utilizator sub EXCEL Ca aplicaţie se va realiza calculul volumului de apă dislocat de navă. 11.4.1. Baze teoretice Metoda de calcul tradiţională este foarte simplă. Ea constă în aplicarea metodei de

integrare numerică aşa numită "a trapezelor".

Fig.11.4.1. Fig.11.4.2.

Conform figurii 11.4.1, integrala funcţiei f pe domeniul a-b poate fi scrisă sub forma

aproximativă a formulei trapezelor:

(∫ ∑−

=−+

++=

b

a

n

iixixififdxxf

1

112

1)( ) (11.4.1)

Această valoare reprezintă mărimea ariei dintre curba funcţiei f şi axa ox. Se observă că

prin acest procedeu această arie este divizată în arii elementare cuprinse între axa x şi arcul de curbă S dintre verticalele de mărime fi şi fi+1. La rândul lor aceste arii sunt înlocuite de ariile

Page 263: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 251

trapezelor formate prin înlocuirea arcului de curbă S cu coarda C a curbei. Eroarea metodei este dată de mica arie cuprinsă între arcul de curbă S şi coarda C.

Cu cât diviziunea intervalului a-b este mai fină, cu atât eroarea este mai mică. Pentru a calcula volumul de apă dislocuit de navă se procedează în următorii paşi: - Se consideră volumul de sub apă al navei tăiat în "felii" verticale denumite "cuple"

(figura 11.4.2), la anumite intervale pe lungimea navei, lungime măsurată pe axa x orientată de la prova către pupa. Fiecare dintre aceste cuple are un contur curb definit prin "semilăţimi" măsurate pe o axă y orientată de la planul longitudinal vertical central (numit plan diametral) către bord. Abscisa curbei cuplei este măsurată după o axă z orientată pe verticală de la fundul navei către punte;

- Se calculează ariile cuplelor prin integrarea funcţiei contur a fiecărie cuple în parte. Astfel, rezultă o serie de suprafeţe Ai, i=1,...,n ale cuplelor. Aceste valori Ai pot fi considerate ca descriind o "funcţie a ariilor imerse" (scufundate) de variabilă x;

- Se calculează volumul de sub apă al navei prin integrarea pe lungimea x a ariilor imerse. 11.4.2. Realizarea aplicaţiei sub EXCEL Se vor parcurge următoarele etape de lucru: - Se deschide un document EXCEL în care se desenează tabelul din figura 3. În celulele

marcate cu culoarea gri se vor introduce formule, restul celulelor fiind folosite pentru scrierea datelor şi a inscripţiilor;

- După introducerea datelor în domeniile de celule C4:N10 şi D12:N12 se generează diagrama din figura 11.4.4, numită "transversal al planului de forme al navei". Procedura de lucru pentru crearea acestei diagrame este următoarea:

= Se selectează domeniul de celule C4:D10; = Se apasă butonul Chart Wizard de pe bara de instrumente Standard; = Din cutia de dialog Chart Wizard Step 1 of 4 se selectează tipul Scatter, subtipul

Scatter with data points connected by lines without markers; = Din cutia de dialog Chart Wizard Step 2 of 4 se selectează pagina Data Range în

care se bifează Series in Columns. Apoi se comută în pagina Series. Dacă am lăsa datele aşa cum le acceptă automat Excel, cuplele navei ar apare culcate pe orizontală. De aceea, trebuie inversate seriile de valori x şi y între ele. Pentru aceasta, se selectează referinţele de celule din câmpul X Values şi se mută cursorul, selectând domeniul de celule D4:D10. Apoi se selectează referinţele de celule din câmpul Y Values şi se reselectează celulele din domeniul C4:C10. Pentru ca numele de identificare a diagramei astfel construite să nu fie cel acordat automat (adică Series1) se introduce cursorul în câmpul Name şi se scrie C0;

= Se pot introduce acum serii noi de date folosind butonul Add şi procedând la introducerea datelor în câmpurile X Values, Y Values şi Name la fel ca mai sus;

= Se apasă butonul Next pentru a se trece la pasul 3 al cutiei de dialog Chart Wizard. Aici, dacă se doreşte se pot introduce inscripţii de identificare a diagramei. În figura 11.4.4 aceste facilităţi nu au fost folosite aşa încât se poate trece la pasul 4 unde se alege opţiunea As new Sheet. - Se aplică comanda Tools>Macro>Visual Basic Editor pentru a se deschide editorul

Visual Basic; - În editorul Visual Basic se crează o foaie de module în care se scriu funcţiile de mai jos: - O funcţie pentru calculul ariei imerse a unei cuple. Această funcţie preia valorile de diviziune

ale axei z prin introducerea domeniului de celule care conţine aceste valori şi, analog, valorile semilăţimilor. Deoarece aceste valori sunt situate pe coloane, se foloseşte proprietatea Count a subobiectului Rows a obiectului Range pentru a se determina numărul de rânduri ale domeniului.

Page 264: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 252

Fig.11.4.3.

Fig.11.4.4.

Se compară egalitatea lungimii domeniilor abscise - valori ale funcţiei contur al cuplei. Dacă aceste lungimi nu sunt egale (ca o consecinţă a unei selectări greşite), funcţia

returnează ca rezultat şirul de caractere "Eroare". Dacă lungimile sunt egale se efectuează calculul integralei într-un ciclu For. Deoarece aria

astfel calculată este numai jumătate din aria efectivă (considerând şi partea din bordul simetric) valoarea obţinută este multiplicată cu 2 şi este returnată de funcţie ca rezultat.

Function Arie_cupla(Dom_z As Range, Dom_y As Range) lungz = Dom_z.Rows.Count lungy = Dom_y.Rows.Count If lungz = lungy Then Arie_cupla = 0 For i = 1 To lungz - 1 z1 = Dom_z(i, 1)

Page 265: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 253

z2 = Dom_z(i + 1, 1) y1 = Dom_y(i, 1) y2 = Dom_y(i + 1, 1) Arie_cupla = Arie_cupla + 0.5 * (y2 + y1) * (z2 - z1) Next i Arie_cupla = 2 * Arie_cupla Else Arie_cupla = "Eroare" End If End Function

- O funcţie pentru calculul volumului de apă dislocuit. Această funcţie este concepută

similar, cu următoarele deosebiri: = Datele sunt preluate din domenii de celule organizate pe rânduri, motiv pentru care

este folosită proprietatea Count a subobiectului Columns a obiectului Range; = Nu se mai face multiplicare cu 2 deoarece volumul imers rezultă direct din calcul.

Function Volum_imers(Dom_x As Range, Dom_Arii As Range) lungx = Dom_x.Columns.Count lungar = Dom_Arii.Columns.Count If lungx = lungar Then Volum_intre_cuple = 0 For i = 1 To lungar - 1 x1 = Dom_x(1, i) x2 = Dom_x(1, i + 1) ar1 = Dom_Arii(1, i) ar2 = Dom_Arii(1, i + 1) Volum_ imers = Volum_ imers + 0.5 * (ar2 + ar1) * (x2 - x1) Next i Else Volum_imers = "Eroare" End If End Function Pentru a se putea folosi aceste funcţii se procedează astfel: - Mai întâi se selectează domeniul de celule C4:C10; - Se aplică comanda Insert>Name>Define; - În cutia de dialog Define Name se va observa: existenţa în câmpul Refers to a referinţei

de câmp care ar putea să apară sub forma =Sheet1!$C$4:$C$10. Dacă referinţa este incorectă se va selecta şirul de caractere al referinţei şi se va repeta selecţia câmpului referit din foaia de lucru; existenţa în câmpul Names in Workbook a unei denumiri - în cazul de faţă notaţia z culeasă automat de către EXCEL din prima celulă de deasupra câmpului selectat. Vom şterge această denumire şi vom scrie în locul ei domz;

Folosirea formulei de calcul a unei arii imerse se face astfel: - Se plantează cursorul în celula D11; - Se apasă butonul fx de pe bara de scule Standard; - După deschiderea cutiei de dialog Paste function se selectează categoria de funcţii User

Defined iar din lista de funcţii se selctează funcţia Arie_cupla; - După ce se apasă pe butonul OK şi este afişată cutia de dialog Arie_cupla se introduc,

prin selecţie cu mouse-ul, domeniile de celule pentru valorile z (Dom_z) şi pentru valorile semilăţimilor (Dom_y);

Page 266: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 254

- O dată ce prima celulă pentru funcţia de arie a fost completată, celelalte celule se autocompletează folosind metoda extinderii prin tragere, astfel: se selectează celula completată (D11), se "apucă" cu cursorul mouse de "mânerul de extindere" (din partea din dreapta-jos a celulei) şi se "trage" peste celulele E1:N11;

- În sfârşit, pentru a calcula volumul imers, se selectează cursorul în celula N13 şi se apasă pe butonul fx de unde se selectează funcţia Volum_imers;

- În cutia de dialog a funcţiei Volum_imers se introduc domeniile de celule D12:N12 pentru abscisele x şi D11:N11 pentru mărimile ariilor transversale imerse.

Observaţie: În aplicaţia de mai sus valorile au fost exprimate în m pentru lungimi, m2

pentru arii şi m3 pentru volum. Din acest motiv deplasamentul navei rezultă imediat în tone din înmulţirea volumului cu greutatea specifică a apei.

§11.5. Folosirea obiectelor simple de interacţiune grafică din EXCEL În cele ce urmează vom exemplifica modul de utilizare al obiectelor de interacţiune din

EXCEL.

Fig.11.5.1.

Pentru a oferi un suport practic, concret, vom considera funcţia parametrică de gradul 2 următoare:

( ) pxbxaxf +⋅+⋅= 2 unde p este un parametru variabil, iar pentru constantele a şi b vom considera valorile a=5

şi b=2. Se cere construirea diagramei acestei funcţii pe intervalul x=0...3 şi crearea unei modalităţi

de interfaţare care să permită variaţia interactivă a parametrului p, altfel decât prin scriere în celula de depozitare a parametrului.

Lucrarea va decurge în etapele descrise mai jos. 11.5.1. Crearea tabelului funcţiei - Se selectează foaia Sheet2; - Se desenează tabelul din figura 11.5.1 şi se completează inscripţiile acestuia (parametru, x, f(x));

Page 267: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 255

- În celula C4 se scrie o valoare oarecare a parametrului p; - Se completează domeniul de celule C5:I5 cu valorile variabilei x; - Folosind comanda Insert>Name>Define se denumeşte celula C4 cu numele param; - În celula C6 se introduce formula =5*C5^2+2*C5+param - Se extinde formula din celula C6 la restul celulelor domeniului valorilor funcţiilor (D6:I6). 11.5.2. Generarea diagramei funcţiei - Se selectează domeniile de celule C5:I5; - cu comanda Insert>Chart se generează diagrama folosind tipul Scatter, subtipul Scatter

with data points connected by smoothed lines without markers. În pasul al 4-lea se va folosi opţiunea As object in Sheet1.

Diagrama va rezulta cu aspectul din figura 11.5.1. 11.5.3. Crearea unui duplicat al tabelului funcţiei prin metoda referinţelor Deoarece dorim să realizăm o aplicaţie sigură, protejată contra erorilor de manevrare,

trebuie interzis accesul direct al utilizatorului la formulele din celulele tabelului, oferind totuşi posibilitatea vizualizării conţinutului lui.

Pentru aceasta se procedează astfel: - Se selectează celula B4 din foaia Sheet1; - Se scrie caracterul = - Se selectează foaia Sheet2 şi se aplică un clic pe celula B4 a acestei foi, după care se

apasă tasta ENTER. În mod automat are loc revenirea la foaia Sheet1, iar in celula B4 din această foaie va apare formula de referire sub forma =Sheet2!B4. Această formulă este vizibilă în bara de editare a formulelor atunci când se selectează celula B4 iar în celulă se va vedea conţinutul celulei referite, în cazul de faţă textul parametru;

- Se procedează la fel pentru celelalte celule ale tabelului. Mai simplu este să se procedeze prin extinderea prin tragere a formulei deja introduse. Se completează operaţia prin formatarea chenarelor celulelor tabelului duplicat;

- Se aplică comanda Tools>Protection>Protect Sheet. Va avea loc deschiderea cutiei de dialog Protect Sheet unde se aplică doar un clic pe butonul OK, fără a scrie nici o parolă şi fără a modifica opţiunile existente;

- La finalul acestei etape se selectează foaia Sheet2 şi se aplică comanda Format>Sheet>Hide. Prin aceasta foaia este ascunsă, adică eticheta de foaie dispare de pe bara de etichete şi foaia nu mai poate fi selectată decât dacă se dezascunde cu comanda Format>Sheet>Unhide.

În urma acestei proceduri, până la deprotejarea foii Sheet1, orice încercare de a modifica o celulă oarecare din cuprinsul foii va fi respinsă de către EXCEL, concomitent fiind afişat un mesaj de avertisment.

Nu s-a aplicat acest procedeu direct asupra foii Sheet2 deoarece acolo există celule pe care programul va trebui să le modifice, iar protejarea foii ar fi interzis şi programului accesul la celule.

11.5.4. Crearea unei cutii de dialog pentru interacţiune Pentru a putea modifica interactiv parametrul funcţiei trebuie construită o cutie de dialog

cu acest rol. În acest scop vom folosi o facilitate mai veche de creare a cutiilor de dialog introdusă de la EXCEL 5.0.

Acestea au avantajul de a fi mai uşor de manipulat şi de programat, dar şi dezavantajul de a oferi o gamă de posibilităţi de interfaţare mai redusă decât omoloagele lor introduse de la versiunea EXCEL 97.

Page 268: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 256

Cutia de dialog care trebuie creată va avea aspectul din figura 11.5.2 şi va conţine următoarele instrumente de control:

- O etichetă (Label) cu inscripţia Valoare= - O cutie de editare (EditBox) în care se va scrie

valoarea parametrului; - O casetă de opţiune neexclusivă (Check Box) cu inscripţia

Variaţie dinamică. Rolul ei este de a activa modificarea valorii parametrului direct în foaia de lucru Sheet2, efect vizibil prin referinţă şi în foaia Sheet1. Când această casetă este nebifată orice variaţie incrementală/decrementală determinată de apăsări pe butoanele Creste şi Descreste nu va fi vizibilă decât în cutia de editare;

- Butonul incremental Creste, care produce majorarea parametrului cu o unitate;

Fig.11.5.2.

- Butonul decremental Descreste care produce micşorarea parametrului cu o unitate; - Butonul Aplicare provenit din modificarea butonului prestabilit OK. Când acest buton este

apăsat valoarea scrisă pentru parametru este aplicată în celula corespunzătoare din foaia Sheet2; - Butonul Iesire provenit din modificarea butonului Cancel, al cărui rol este de a închide

cutia de dialog făra a mai efectua nici o altă acţiune. Crearea cutiei de dialog se face, ca şi în lucrările anterioare, prin inserarea unei foi de

dialog MS Excel 5.0 Dialog (vezi lucrarea 11.2, punctul 11.2.7.3). Deoarece cutia de editare şi caseta de opţiune vor trebui să fie accesate de macrocomenzile care

se vor scrie, este indicat să li se schimbe denumirile acordate automat la creare cu denumiri noi. Pentru aceasta se selectează cu un clic obiectul dorit, apoi se aplică un clic în câmpul

Name Box din stânga/sus a ferestrei foii de dialog, după care se scrie numele dorit. De asemenea, se poate face uz de meniul Insert>Name>Define, de o manieră similară cu cea folosită într-o foaie de calcul tabelar.

Se vor denumi: cutia de editare cu numele ValParam, iar caseta de opţiune cu numele vardin. La creare, obiectele din cuprinsul cutiei de dialog au o serie de atribute prestabilite care le

determină comportamentul. Unele dintre ele vor trebui modificate astfel: - Se selectează obiectul în cauză; - Se aplică comanda Format>Control; - După deschiderea cutiei de dialog Format Control se selectează pagina Control. Obiectele şi atributele de modificat sunt următoarele - Pentru cutia de editare ValParam, din grupul Edit Validation se bifează opţiunea Number; - Pentru caseta de opţiune vardin, în câmpul Accelerator Key se scrie litera V; - Pentru butonul cu inscripţia Aplicare (iniţial denumit OK) se dezactivează opţiunea

Dismiss (butonul nu va mai închide cutia de dialog) şi se lasă activă numai opţiunea Default. De acemenea, se atribuie ca tastă acceleratoare litera A (în câmpul Accelerator Key);

- Pentru butonul cu inscripţia Ieşire (iniţial denumit Cancel) se atribuie ca tastă acceleratoare litera I;

- Pentru butonul nou creat cu inscripţia Creste nu se activează nici unul din atributele Default, Cancel, Dismiss, Help, şi se atribuie tasta acceleratoare C;

- Pentru butonul nou creat cu inscripţia Descreste nu se activează nici unul din atributele de buton şi se atribuie tasta acceleratoare D;

11.5.5. Crearea macrocomenzilor de interacţiune Instrumentele de interacţiune create mai sus vor rămâne inactive dacă ele nu declanşează

acţiuni. Aceste acţiuni au loc ca urmare a unor macrocomenzi care trebuie scrise într-o foaie pentru module de program.

Page 269: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 257

Pentru a se crea o astfel de foaie trebuie mai întâi să se deschidă editorul de Visual Basic folosind comanda Tools>Macro>Visual Basic Editor.

Deoarece nu a fost folosit înregistratorul de macrocomenzi, aplicaţia (fişierul EXCEL) nu conţine nici o foaie de module. Ea se ataşează folosind comanda Insert>Module aplicată din fereastra editorului.

O dată foaia de module creată (Module1), în ea se vor scrie următoarele macrocomenzi: Sub Afisare_Dialog() DialogSheets("Dialog1").CheckBoxes("vardin").Value = Unchecked DialogSheets("Dialog1").EditBoxes("ValParam").Text = _ Application.Worksheets("Sheet2").Range("param") DialogSheets("Dialog1").Show End Sub Această subrutină realizează următoarele acţiuni: - Indiferent care ar fi fost starea anterioară a casetei de opţiune vardin (bifată sau nu) ea

este debifată; - Se preia conţinutul din celula C4 a foii Sheet2 - cea denumită param (cu valoarea

parametrului p) şi este atribuit ca text în cutia de editare ValParam; - Se afişează cutia de dialog Parametru. Sub Accept_parametru() valparam = DialogSheets("Dialog1").EditBoxes("ValParam").Text If Not IsNumeric(valparam) Then MsgBox "Introducere gresita!", vbCritical, "Atentie!" Exit Sub End If valparam = Val(valparam) Application.Worksheets("Sheet2").Range("param") = valparam End Sub Această subrutină realizează următoarele acţiuni: - Variabila de tip Variant valparam preia textul din cutia de editare ValParam; - Dacă textul este neconvertibil la valoare numerică este afişată o cutie cu un mesaj de

avertisment şi orice acţiune este abandonată; - Dacă textul are semnificaţie numerică valoarea de tip text este convertită în valoare

numerică folosind funcţie Val a limbajului Visual Basic pentru EXCEL; - Celula C4 din foaia Sheet2 capătă valoarea numerică a variabilei valparam. Sub Creste_parametru() valparam = DialogSheets("Dialog1").EditBoxes("ValParam").Text If Not IsNumeric(valparam) Then MsgBox "Introducere gresita!", vbCritical, "Atentie!" Exit Sub End If valparam = Val(valparam) + 1 DialogSheets("Dialog1").EditBoxes("ValParam").Text = CStr(valparam) If DialogSheets("Dialog1").CheckBoxes("vardin").Value = Checked Then Application.Worksheets("Sheet2").Range("param") = valparam End If End Sub Această subrutină realizează următoarele acţiuni: - Variabila de tip Variant valparam preia textul din cutia de editare ValParam;

Page 270: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 258

- Dacă textul este neconvertibil la valoare numerică este afişată o cutie cu un mesaj de avertisment şi orice acţiune este abandonată;

- Dacă textul are semnificaţie numerică valoarea de tip text este convertită în valoare numerică folosind funcţie Val a limbajului Visual Basic pentru EXCEL şi apoi este incrementată;

- Cutia de editare ValParam primeşte ca valoare de tip text valoarea curentă a variabilei valparam convertită la forma text;

- Dacă caseta de opţiune vardin este bifată (Checked) atunci celula param din foaia Sheet2 primeşte valoarea parametrului.

Sub Descreste_parametru() valparam = DialogSheets("Dialog1").EditBoxes("ValParam").Text If Not IsNumeric(valparam) Then MsgBox "Introducere gresita!", vbCritical, "Atentie!" Exit Sub End If valparam = Val(valparam) - 1 DialogSheets("Dialog1").EditBoxes("ValParam").Text = CStr(valparam) If DialogSheets("Dialog1").CheckBoxes("vardin").Value = Checked Then Application.Worksheets("Sheet2").Range("param") = valparam End If End Sub Această subrutină realizează următoarele acţiuni: - Variabila de tip Variant valparam preia textul din cutia de editare ValParam; - Dacă textul este neconvertibil la valoare numerică este afişată o cutie cu un mesaj de

avertisment şi orice acţiune este abandonată; - Dacă textul are semnificaţie numerică valoarea de tip text este convertită în valoare numerică

folosind funcţie Val a limbajului Visual Basic pentru EXCEL şi apoi este decrementată; - Cutia de editare ValParam primeşte ca valoare de tip text valoarea curentă a variabilei

valparam convertită la forma text; - Dacă caseta de opţiune vardin este bifată (Checked) atunci celula param din foaia

Sheet2 primeşte valoarea parametrului. 11.5.6. Realizarea legăturilor de interacţiune Toate macrocomenzile de mai sus trebuie să trateze evenimentele create prin apăsarea

instrumentelor de control ale cutiei de dialog. De aceea, între ele şi aceste instrumente de control trebuie realizate legături. Acest lucru se obţine pe următoarea cale generală:

- Se selectează instrumentul de control în cauză; - Se aplică un clic pe butonul dreapta al mouse-ului; - Din meniul contextual deschis astfel, se selectează articolul Assign Macro, ceea ce

deschide cutia de dialog Assign Macro; - În cutia de dialog Assign Macro, din lista Macros in, se selectează This Workbook; - Din lista de macrocomenzi de sub câmpul Macro Name se selectează macrocomanda de

asociat: Ca urmare, aceasta va apare în câmpul Macro Name; - Se apasă butonul OK. Înainte de a se proceda la realizarea legăturilor mai trebuie creat un instrument de interacţiune. Acesta este butonul Variatie Parametru de deasupra tabelului vizibil în figura 11.5.1 în

foaia Sheet1. Acest lucru trebuie realizat cu foaia deprotejată, folosind cutia cu instrumente Forms care se deschide folosind comanda View>Toolbars>Forms.

Legăturile (asignările de macrocomenzi) de realizat sunt următoarele:

Page 271: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 259

- Butonul Variatie Parametru din foaia Sheet1 se asociază cu macrocomanda Afisare_Dialog;

- Butonul Aplicare din cutia de dialog se asociază cu macrocomanda Accept_parametru; - Butonul Creste din cutia de dialog se asociază cu macrocomanda Creste_parametru; - Butonul Descreste din cutia de dialog se asociază cu macrocomanda

Descreste_parametru; Cu aceasta aplicaţia este completă şi poate fi folosită. §11.6. Folosirea obiectelor de interacţiune grafică programabile din EXCEL În cele ce urmează vom exemplifica modul de utilizare al obiectelor de interacţiune

programabile din EXCEL, nou introduse în editorul de Visual BASIC de la versiunea EXCEL 97. 11.6.1. Definirea temei Fie funcţia de gradul al 2-lea

( ) cxbxaxfy +⋅+⋅== 2 Se pune problema determinării coeficienţilor a, b şi c. Deoarece aceştia apar ca trei

necunoscute, sunt necesare trei ecuaţii pentru a-i putea determina. Aceste trei ecuaţii se pot obţine dacă se consideră trei puncte prin care trece curba funcţiei P1(x1,y1), P2(x2,y2) şi P3(x3,y3).

Se poate scrie sistemul de trei ecuaţii cu trei necunoscute a, b şi c:

3323

2222

1121

ycbxax

ycbxax

ycbxax

=++

=++

=++

Se pot scrie determinanţii:

3323

2222

1121

1323

1222

1121

133

122

111

1323

1222

1121

yxx

yxx

yxx

c

yx

yx

yx

bxyxyxy

a

xx

xx

xx

=∆=∆=∆=∆

ceea ce conduce la soluţiile sistemului sub forma:

∆∆

=∆∆

=∆∆

=ccbbaa , evident cu condiţia 0≠∆

Considerând acum setul de funcţii fi(x) definite prin setul de puncte P1i(x1,y1i), P2i(x2,y2i), P3i(x3,y3i), i=1,...,n, se cere să se construiască o aplicaţie care să afişeze la cerere diagrama unei funcţii oarecare de indice i şi, mai mult, ca valorile y1, y2, y3 ale unei funcţii oarecare din set să poată fi modificate.

11.6.2. Construirea foii de calcul Se construieşte foaia de calcul Sheet1, incluzând în ea următoarele elemente, vizibile în

figura 11.6.1. Se parcurg următoarele etape: 11.6.2.1. Atribuiri de nume pentru domenii de celule - celula F2 capătă denumirea indice; - celula C3 capătă denumirea crtf1; - celula D3 capătă denumirea crtf2; - celula E3 capătă denumirea crtf3;

Page 272: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 260

- domeniul B7:E18 capătă denumirea tabel; - domeniul C7:C18 capătă denumirea fun1; - domeniul D7:D18 capătă denumirea fun2; - domeniul E7:E18 capătă denumirea fun3; - celula M6 capătă denumirea coef_a; - celula M10 capătă denumirea coef_b; - celula M14 capătă denumirea coef_c;

Fig.11.6.1.

Aceste denumiri ajută la o mai bună gestionare a celulelor prin programul care se va construi în Visual BASIC şi, totodată, evitând lucrul cu adrese de celulă efective, face programul insensibil la eventuale modificări ale foii de lucru (adăugări/suprimări de rânduri/coloane).

11.6.2.2. Completarea conţinutului celulelor Cu excepţia capetelor de tabel (domeniile B2:B3, C6:E6 şi B7:B18) şi a celulelor cu date

(domeniile C2:E2, C7:E18) care se scriu aşa cum se văd în figura 11.6.1, pentru celelalte celule se procedează astfel:

- În celula F2 se scrie o valoare oarecare (de exemplu 2, dar nu mai mare de 11) - În celula C3 se introduce formula =INDEX(fun1,indice+1) - În celula D3 se introduce formula =INDEX(fun2,indice+1) - În celula E3 se introduce formula =INDEX(fun3,indice+1) - În celula G2 se scrie formula =C2^2 - În celula G3 se scrie formula =D2^2 - În celula G4 se scrie formula =E2^2 - În celula H2 se scrie formula =C2 - În celula H3 se scrie formula =D2 - În celula H4 se scrie formula =E2 - În celulele I2:I4 se scrie valoarea 1 - În celula J2 se scrie formula =C3

Page 273: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 261

- În celula J3 se scrie formula =D3 - În celula J4 se scrie formula =E3 - În celula G6 se scrie formula de referire =G2 - Se extinde celula G6 prin tragere peste domeniul G6:I6 pe orizontală; - Cu domeniul G6:I6 selectat se operează extinderea lui peste domeniul G6:I8 pe verticală; - Se procedează la fel pornind de la celula G10 şi apoi G14, obţinându-se astfel duplicate

prin referire ale matricii coeficienţilor sistemului de ecuaţii din domeniul G2:I4; Se înlocuiesc pe rând coloanele 1, 2 şi 3 ale duplicatelor matriciale, astfel încât ele să

refere vectorul termenilor liberi, după cum urmează: - În celula G6 se introduce formula de referire =J2, apoi se extinde pe verticală peste

domeniul G6:G8; - În celula H10 se introduce formula de referire =J2, apoi se extinde pe verticală peste

domeniul H10:H12; - În celula I14 se introduce formula de referire =J2, apoi se extinde pe verticală peste

domeniul I14:I16; Se calculează determinanţii matricilor: - În celula L2 se introduce formula =MDETERM(G2:I4) - În celula L6 se introduce formula =MDETERM(G6:I8) - În celula L10 se introduce formula =MDETERM(G10:I12) - În celula L14 se introduce formula =MDETERM(G14:I16) Se calculează soluţiile sistemului: - În celula M6 se introduce formula =L6/L2 - În celula M10 se introduce formula =L10/L2 - În celula M14 se introduce formula =L14/L2 11.6.3. Construirea diagramei funcţiei Diagrama funcţiei va avea la bază datele din domeniile C2:E2 pentru x şi C3:E3 pentru y.

Construcţia diagramei de tip Scatter, subtipul Compares pairs of values decurge întocmai ca şi la aplicaţiile anterioare. Ea va fi creată ca obiect în foaia Chart1, şi va conţine numai reprezentarea celor trei puncte date.

În continuare, pentru a se obţine cu adevărat o diagramă de funcţie pătratică se procedează astfel: - Se aplică un clic pe unul dintre punctele diagramei; - Se aplică comanda Chart>Add Trendline, ceea ce are ca efect deschiderea cutiei de

dialog Add Trendline; - În pagina Type a cutiei de dialog Add Trendline, din grupul Trend/Regression type se

selectează tipul Polynomial şi Order=2; - Se comută în pagina Options unde se bifează opţiunea Display equation on chart şi se

apasă butonul OK. - Folosind instrumentele de formatare se ajustează diagrama astfel încât să aibă aspectul

din figura 11.6.2.

11.6.4. Construirea cutiei de dialog De această dată vom face uz de posibilităţile de construire a dialogurilor implementate în

editorul de Visual BASIC din EXCEL. Pentru aceasta, din editorul de Visual BASIC, în fereastra Project-VBA Project, se aplică un

clic pe nodul VBA Project (nume_fisier.xls) şi apoi se lansează comanda Insert>Userform. Ca urmare la acest nod este conectat un nod nou, denumit Forms cu obiectul subordonat UserForm1 ca în figura 11.6.3, iar în fereastra din dreapta apare un cadru de cutie de dialog şi cutia cu instrumente ToolBox (figura 11.6.4) pentru crearea componentelor de dialog.

Page 274: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 262

Fig.11.6.2.

Fig.11.6.3. Fig.11.6.4. Fig.11.6.5.

Folosind aceste instrumente se vor crea elementele vizibile în figura 11.6.5, şi anume: - eticheta (Label) cu inscripţia Coeficienţii funcţiei; - un rând orizontal de trei etichete cu inscripţii stabilite prin program care vor afişa a=, b=, c= urmate

de valorile coeficienţilor funcţiei calculaţi în foaia Sheet1 în celulele denumite coef_a, coef_b, coef_c; - o cutie de listare (ListBox) care va afişa denumirile funcţiilor şi coordonatele y ale celor

trei puncte prin care trec curbele lor; - un cadru de grup (Frame) cu inscripţia Set de valori pentru functie; - trei etichete cu inscripţiile y1=, y2=, y3=; - trei cutii de editare (TextBox) cu rolul afişării/introducerii coordonatelor y1, y2 şi y3 ale

funcţiei selectate din cutia de listare; - butonul Aplicare cu rolul modificării coordonatelor y1, y2 şi y3 ale funcţiei selectate; - butonul Terminare, cu rolul închiderii cutiei de dialog. După crearea acestor elemente se trece la stabilirea proprietăţilor lor în fereastra

Properties de sub fereastra Project-VBA Project. În tabelul de mai jos sunt indicate stabilirile de proprietăţi necesare.

Page 275: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 263

Tip de obiect Denumire (Name)

Proprietăţi şi observaţii (Proprietăţile nemenţionate rămân la valorile

prestabilite) Cutia de dialog (Userform) UserForm1 Caption=Functii, Height=210, Width=275 Etichetă (Label) la partea superioară a cutiei de dialog

Label1 Font=Tahoma, Bold, 10

Etichete (Label) - prima din setul de trei de sus - a doua - a treia

Coef_a Coef_b Coef_c

Font=Tahoma, Bold, 12, Height=20, Width=80

Cutia de listare (ListBox)

valori_functii ColumnCount=4, ColumnHeads=True, Height=72, Width=260

Chenar de grup (Frame) Frame1 Caption=Set de valori pentru functie Etichete (Label) - prima din setul de trei din grupul Frame1 - a doua - a treia

Label5

Label6 Label7

Caption: y1=, Height=13, Width=18 Caption: y2= , Height=13, Width=18 Caption: y3= , Height=13, Width=18

Cutii de editare (TextBox) - prima din setul de trei din grupul Frame1 - a doua - a treia

valy1

valy2 valy3

Height=17, Width=60

Butoane de comandă (CommandButton) - din stânga - din dreapta

Aplicare Terminare

Accelerator=A, Height=25, Width=110 Accelerator=T, Height=25, Width=110

11.6.5. Crearea subrutinelor de comandă ale instrumentelor de dialog La acest tip de instrumente de comandă subrutinele asociate sunt destinate tratării

evenimentelor ocazionate de acţiunile asupra lor, evenimente de tip Click (clic pe un element de control) sau Change (modificarea prin editare a cutiilor de editare).

Aceste subrutine sunt create într-o foaie de modul privat ataşată direct obiectului container UserForm1.

În general, pentru crearea unei astfel de subrutine se procedează astfel: - Printr-un clic, se selectează componenta de dialog al cărui eveniment trebuie tratat; - Cu componenta selectată, se aplică comanda View>Code. Ca urmare vor fi create două

instrucţiuni de forma: Private Sub Numecomponenta_EvenimentDeTratat () End Sub

fără nici un alt conţinut. Programatorul va trebui să scrie el însuşi instrucţiunile care

descriu modul de tratare al evenimentului. Urmând această procedură vor fi scrise subrutinele de mai jos. Scopul lor este explicat

după textul subrutinei.

Page 276: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 264

Private Sub valori_functii_Click() Application.Range("indice") = UserForm1.valori_functii.ListIndex vala = Application.Worksheets("Sheet1").Range("coef_a") valb = Application.Worksheets("Sheet1").Range("coef_b") valc = Application.Worksheets("Sheet1").Range("coef_c") UserForm1.Coef_a.Caption = "a=" & CStr(vala) UserForm1.Coef_b.Caption = "b=" & CStr(valb) UserForm1.Coef_c.Caption = "c=" & CStr(valc) UserForm1.valy1.Text = Application.Range("crtf1").Text UserForm1.valy2.Text = Application.Range("crtf2").Text UserForm1.valy3.Text = Application.Range("crtf3").Text End Sub

Această subrutină tratează evenimentul de clic pe unul dintre articolele afişate de cutia de listare şi efectuează următoarele acţiuni:

- Scrie în celula F2 din foaia Sheet1 valoarea indicelui de listă (numărul articolului selectat din listă). Primul indice este zero. Prin modificarea survenită în celula F2, formulele din celulele C3, D3 şi F3 din foaia Sheet1 vor afişa valorile coordonatelor y1, y2 şi y3 ale funcţiei selectată din cutia de listare;

- variabilele vala, valb şi valc preiau valorile din celulele M6, M10 şi M14 din foaia Sheet1;

- Se convertesc valorile de tip numeric vala, valb şi valc în valori de tip şir de caractere şi se concatenează (alipesc) cu şirurile de text a=, b= şi c=, după care sunt atribuite ca şiruri de afişat de către etichetele Coef_a, Coef_b şi Coef_c ale cutiei de dialog (prin preluarea şirurilor de către proprietăţile Caption ale acestor obiecte);

- Sunt preluate valorile de tip text ale celulelor C3, D3 şi F3 reprezentând valorile coordonatelor y1, y2 şi y3 ale funcţiei curente (cea selectată din listă) şi sunt atribuite ca text de afişat de către cutiile de editare ale cutiei de dialog (prin atribuirea lor ca valori pentru proprietîţile Text ale acestor obiecte).

Private Sub Aplicare_Click() y1 = UserForm1.valy1.Text y2 = UserForm1.valy2.Text y3 = UserForm1.valy3.Text If Not (IsNumeric(y1) And IsNumeric(y2) And IsNumeric(y3)) Then MsgBox "Date gresite!", vbCritical, "Eroare" Exit Sub Else indfunc = Val(Application.Range("indice")) Application.Range("fun1").Item(indfunc + 1) = y1 Application.Range("fun2").Item(indfunc + 1) = y2 Application.Range("fun3").Item(indfunc + 1) = y3 End If End Sub

Această subrutină tratează evenimentul Click pe butonul Aplicare şi efectuează următoarele acţiuni:

- Variabilele y1, y2 şi y3 preiau valorile de tip text din cutiile de editare ale cutiei de dialog;

- Se aplică un test pentru a determina dacă cel puţin una dintre aceste valori nu are semnificaţie numerică. În acest caz este afişată o cutie de mesaj cu avertismentul "Date gresite!" şi tratarea evenimentului se încheie fără alt efect;

- Dacă testul de nesemnificativitate numerică a fost negativ, variabila indfunc preia

Page 277: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 265

valoarea din celula F2 a foii Sheet1 convertită de la forma text la forma numerică folosind funcţia Val;

- Valorile variabilelor y1, y2 şi y3 prelevate din cutiile de editare sunt scrise în celulele corespunzătoare ale domeniului B7:E18 din foaia Sheet1. Valoarea variabilei indfunc este majorată cu 1 deoarece regula de numerotare a rândurilor unui domeniu presupune că primul rând al domeniului are indicele 1.

Private Sub Terminare_Click() Unload UserForm1 End Sub

Această subrutină tratează evenimentul Click pe butonul Terminare. Singura acţiune efectuată este aceea de a închide cutia de dialog descărcând-o din memorie.

Pentru ca mai sus prezentata cutie de dialog să poată fi folosită mai este necesară o subrutină care să o pregătească de afişare şi apoi să o afişeze. Spre deosebire de celelalte subrutine de mai sus, aceasta se va scrie într-o foaie de module obişnuită, foaia Module1, şi va avea următoarea componenţă:

Sub afisare_dialog() Load UserForm1 UserForm1.valori_functii.ListIndex = 0 Application.Range("indice") = 0 vala = Application.Worksheets("Sheet1").Range("coef_a") valb = Application.Worksheets("Sheet1").Range("coef_b") valc = Application.Worksheets("Sheet1").Range("coef_c") UserForm1.Coef_a.Caption = "a=" & CStr(vala) UserForm1.Coef_b.Caption = "b=" & CStr(valb) UserForm1.Coef_c.Caption = "c=" & CStr(valc) UserForm1.valy1.Text = Application.Range("crtf1").Text UserForm1.valy2.Text = Application.Range("crtf2").Text UserForm1.valy3.Text = Application.Range("crtf3").Text UserForm1.Show End Sub

Această subrutină efectuează următoarele acţiuni: - Încarcă în memorie cutia de dialog UserForm1; - Iniţializează indicele cutiei de listare la valoarea 0, astfel încât, când cutia de dialog va fi

afişată, primul ei articol să fie selectat. Acest lucru este foarte important deoarece indicele de listă este cel care, în această aplicaţie face legătura dintre datele afişate de diagrama din foaia Chart1 şi datele afişate de cutia de dialog în etichetele pentru coeficienţi şi în cutiile de editare pentru coordonatele y1, y2 şi y3;

- Variabilele vala, valb şi valc preiau valorile din celulele M6, M10 şi M14 din foaia Sheet1; - Proprietăţile Caption ale obiectelor etichete pentru coeficienţi primesc valorile

variabilelor vala, valb şi valc convertite la forma şir de caractere şi concatenate cu inscripţiile a=, b= şi c=;

- Proprietîţile Text ale obiectelor cutii de editare pentru coordonatele y1, y2 şi y3 preiau valorile de tip text ale acestor coordonate extrase din celulele C3, D3 şi E3 din foaia Sheet1;

- Este afişată cutia de dialog. 11.6.6. Finalizarea aplicaţiei Pentru ca aplicaţia să funcţioneze mai trebuie creată o legătură între foaia cu diagrama

funcţiei selectate şi cutia de dialog care serveşte la selectare. Pentru aceasta se mai execută următoarele operaţii:

Page 278: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 266

- Folosind cutia cu instrumente Forms se crează în foaia Chart1 un buton, cu dispunere la baza diagramei, ca în figura 11.6.2;

- Folosind cutia de dialog Assign Macro se asociază acest buton cu macrocomanda afisare_dialog;

- Se scrie pe buton inscripţia Selectare. Din acest moment aplicaţia este utilizabilă. Dacă se doreşte şi protecţia datelor şi formulelor din foaia Sheet1, se poate proceda la

ascunderea acestei foi folosind comanda Format>Sheet>Hide. Nu se va folosi protecţia foii deoarece există celule în foaia Sheet1 pe care programul trebuie să le modifice iar protecţia foii, prin blocarea modificărilor în foaie, ar bloca la rândul ei programul.

§11.7. Aplicaţie de folosire programată a instrumentelor pentru

rezolvarea şi aproximarea funcţiilor

În cele ce urmează vom exemplifica modul de folosire a instrumentului de rezolvare a funcţiilor de o variabilă, Goal Seek, şi a facilităţilor de aproximare a funcţiilor date prin puncte.

11.7.1. Definirea temei Fie funcţia de gradul 3 de forma:

( ) dxcxbxaxf +⋅+⋅+⋅= 23 Se cere aflarea soluţiilor ecuaţiei f(x)=0 pe un interval dat [xin, xfin]. Dea semenea, se cere

automatizarea rezolvării prin crearea unor instrumente de interfaţare care să permită: - Modificarea coeficienţilor a, b, c şi d; - Modificarea valorilor limitelor intervalului [xin, xfin]; - Reprezentarea diagramei funcţiei conform valorilor modificate. 11.7.2. Rezolvarea neprogramată Într-o primă fază vom efectua lucrarea cu mijloacele simple ale programului EXCEL, în

următoarele etape:

11.7.2.1. Crearea fişierului

Fig.11.7.1.

- Se crează un fişier nou din care se reţin numei primele două foi de lucru, Sheet1 şi Sheet2, restul fiind eliminate.

- În foaia Sheet2 se crează liniatura şi capetele de tabel (cele cu litere groase), conform figurii 11.7.1.

11.7.2.2. Completarea tabelului Tabelul creat mai sus se completează astfel: - Domeniul de celule A3:A13 se completează cu

indicii valorilor de discretizare a intervalului [xin, xfin]; - Folosind comanda Insert>Name>Define celula

B3 se denumeşte xin; - Celula B13 se denumeşte xfin; - Se completează celulele xin şi xfin cu valorile -2 şi 2;

- În celula B4 se introduce formula =xin+(xfin-xin)*A4/10 - Conţinutul celulei B4 se extinde prin tragere peste domeniul B5:B12; - Celulele E2, E3, E4 şi E5 se denumesc, respectiv, coefa, coefb, coefc şi coefd; - Se completează celulele coeficienţilor cu valorile -3, -3, 4, 1;

Page 279: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 267

- În celula C3 se introduce formula: =coefa*B3^3+coefb*B3^2+coefc*B3+coefd - Conţinutul celulei C3 se extinde prin tragere peste domeniul C4:C13;

Fig.11.7.2.

11.7.2.3. Crearea diagramei funcţiei Diagrama funcţiei se crează în mod obişnuit, ca şi la celelalte aplicaţii, prin selectarea

domeniului B3:C13, lansarea comenzii Insert>Chart şi selectarea tipului Scatter, subtipul Compares pairs of values, iar la sfârşitul procedurii de creare (pasul 4), se selectează As object in Sheet1 (în loc de Sheet2 cum propune EXCEL, deoarece selecţia datelor a fost făcută în foaia Sheet2).

Aşa cum a fost creată diagrama afişează numai punctele date. Pentru a afişa şi o curbă conformă cu ecuaţia de gradul trei se procedează astfel:

- Se aplică un clic pe unul dintre punctele diagramei; - Se aplică comanda Chart>Add Trendline; - În cutia de dialog Add Trendline se selectează pagina Type în care se optează pentru

tipul Polynomial, Order=3, după care se selectează pagina Options de unde se bifează opţiunea Display equation on chart şi se apasă butonul OK.

Ca urmare, diagrama va căpăta aspectul din figura 11.7.2. 11.7.2.4. Determinarea soluţiilor din intervalul de definiţie Ca urmare a afişării curbei funcţiei, devine vizibil modul ei de variaţie şi se pot observa

locurile în care ea intersectează axa ox, deci locurile unde se găsesc soluţiile din interval. Desigur, observaţia vizuală este aproximativă şi se pune problema determinării soluţiilor cu o aproximaţie mai bună.

În acest scop se procedează astfel: - Celula E6 din foaia Sheet2 se denumeşte x0 iar celula E7 din aceeaşi foaie se denumeşte fx0; - În celula x0 se introduce o valoare oarecare, de exemplu -1; - În celula fx0 se introduce formula coefa*x0^3+coefb*x0^2+coefc*x0+coefd - Se selectează celula fx0; - Se aplică comanda Tools>Goal Seek; - În cutia de dialog Goal Seek se verifică dacă în câmpul Set Cell este înscrisă referinţa

Page 280: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 268

celulei fx0, adică E7. Dacă nu, se face un clic pe această celulă pentru a o selecta; - Se aplică un clic în câmpul To value din cutia Goal Seek, pentru a-l activa, şi apoi se

scrie valoarea 0; - Se aplică un clic de activare în câmpul By changing cell, apoi se selectează celula x0

(adică E6); - Se apasă butonul OK. După scurt timp apare cutia de dialog Goal Seek Status care

raportează găsirea (sau nu) a unei soluţii aproximative şi valoarea lui f(x) pentru acea soluţie. Pentru a accepta soluţia găsită se apasă butonul OK.

11.7.3. Automatizarea aplicaţiei prin programare 11.7.3.1. Crearea elementelor de control

Pentru început, este necesară crearea instrumentului de dialog între aplicaţie şi utilizator sub forma unei cutii de dialog, aşa cum se observă din figura 11.7.3.

Pentru aceasta, în editorul de Visual BASIC se crează obiectul UserForm1 care va conţine următoarele obiecte menţionate în ordinea creerii lor:

- un cadru de grup (Frame) cu inscripţia Coeficienti, în care se crează:

= etichetele (Label) cu inscripţiile a=, b=, c= şi d=;

= cutiile de editare (TextBox) de la dreapta etichetelor, cu rolul de a afişa/prelua la/de la operator valorile coeficienţilor ecuaţiei;

Fig.11.7.3.

= butonul de comandă (CommandButton) cu inscripţia Aplicare coeficienti, care introduce în document coeficienţii daţi de operator;

- un cadru de grup (Frame) cu inscripţia Limite, în care se crează: = etichetele (Label) cu inscripţiile X initial= şi X final=; = cutiile de editare (TextBox) de la dreapta etichetelor) cu rolul de a afişa/prelua la/de la

operator limitele intervalului [xin, xfin] al funcţiei; = butonul de comandă (CommandButton) cu inscripţia Aplicare limite, care introduce

în document limitele indicate de operator; - eticheta (Label) cu inscripţia Solutie de start (X0):; - cutia de editare (TextBox) de sub etichetă, pentru a afişa/prelua la/de la operator valoarea

soluţiei obţinute anterior/dată de operator ca valoare de pornire; - butonul de comandă (Command Button) cu inscripţia Rezolvare, care apelează procedura

de rezolvare Goal Seek; - cadrul de grup (Frame) cu inscripţia Retine solutia, care va conţine:

= butonul de opţiune (OptionButton) cu inscripţia Da; = butonul de opţiune (OptionButton) cu inscripţia Nu;

- butonul de comandă (CommandButton) cu inscripţia Iesire, cu rolul închiderii cutiei de dialog;

După crearea acestor elemente de control se trece la ajustarea proprietăţilor lor la valorile necesitate de aplicaţie, conform tabelului de mai jos:

Page 281: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 269

Tip de obiect Denumire (Name)

Proprietăţi şi observaţii (Proprietăţile nemenţionate rămân la valorile prestabilite)

Cutia de dialog (Userform)

UserForm1 Caption=Cautare solutii, Height=158, Width=276

Cadru de grup (Frame)

Frame1 Caption=Coeficienti, Height=128, Width=95

Etichete (Label) în grupul Coeficienti

Label1, Label2, Label3, Label4

Caption: a=, b=, c= şi d=, Height=14, Width=15

Cutii de editare (TextBox) în grupul Coeficienti - prima - a doua - a treia - a patra

coef_a coef_b coef_c coef_d

Height=16, Width=58

Buton de comandă (CommandButton) în grupul Coeficienti

Aplic_coef

Caption= Aplicare Coeficienti, Accelerator= C, Height=27, Width=82

Cadru de grup (Frame)

Frame2 Caption=Limite, Height=55, Width=164

Etichete (Label) în grupul Limite

Label5, Label6,

Caption: X initial= şi X final=, Height=14, Width=35

Cutii de editare (TextBox) în grupul Limite - prima - a doua

x_in x_fin

Height=16, Width=58

Buton de comandă (CommandButton) în grupul Limite

Aplic_lim

Caption=Aplicare Limite, Accelerator=L, Height=36, Width=54

Etichetă (Label) Label7 Caption=Solutie de start (X0):, Height=14, Width=80 Cutie de editare (TextBox)

x_start Height=16, Width=76

Buton de comandă (CommandButton)

Rezolvare Caption=Rezolvare, Accelerator=R, Height=25, Width=76

Cadru de grup (Frame)

Frame3 Caption=Retine solutia, Height=32, Width=76

Butoane de opţiune (OptionButton) în grupul Retine solutia - primul - al doilea

retine_da retine_ne

Caption=Da, Accelerator=D, Height=16, Width=27 Caption=Nu, Accelerator=N, Height=16, Width=27

Buton de comandă (CommandButton)

Iesire Caption=Iesire, Accelerator=e, Height=25, Width=76

Page 282: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 270

11.7.3.2. Crearea modulelor de program În foaia privată a obiectului UserForm1 se crează subrutinele private următoare. Crearea

lor se face, ca şi în §11.6 prin selectarea obiectului, aplicarea comenzii View>Code, şi completarea cu instrucţiunile necesare a intrării de subrutină creată automat. Face excepţie subrutina următoare care trebuie scrisă manual în foaia privată:

Private Sub userform_Initialize() coef_a.Text = Range("coefa").Text coef_b.Text = Range("coefb").Text coef_c.Text = Range("coefc").Text coef_d.Text = Range("coefd").Text x_in.Text = Range("xin").Text x_fin.Text = Range("xfin").Text x_start.Text = Range("x0").Text End Sub

Această subrutină are rolul de a pregăti cutia de dialog înainte de a fi afişată. Ea efectuează următoarele acţiuni:

- Atribuie obiectului cutie de editare coef_a valoarea de tip text culeasă din celula coefa din foaia Sheet2;

- Atribuie obiectului cutie de editare coef_b valoarea de tip text culeasă din celula coefb din foaia Sheet2;

- Atribuie obiectului cutie de editare coef_c valoarea de tip text culeasă din celula coefc din foaia Sheet2;

- Atribuie obiectului cutie de editare x_in valoarea de tip text culeasă din celula xin din foaia Sheet2;

- Atribuie obiectului cutie de editare x_fin valoarea de tip text culeasă din celula xfin din foaia Sheet2;

- Atribuie obiectului cutie de editare x_start valoarea de tip text culeasă din celula x0 din foaia Sheet2.

Private Sub Aplic_coef_Click() ca = coef_a.Text cb = coef_b.Text cc = coef_c.Text cd = coef_d.Text If Not (IsNumeric(ca) And IsNumeric(cb) And IsNumeric(cc) And IsNumeric(cd)) Then MsgBox "Coeficienti gresiti!", vbExclamation, "Eroare" Exit Sub End If Range("coefa").Value = Val(ca) Range("coefb").Value = Val(cb) Range("coefc").Value = Val(cc) Range("coefd").Value = Val(cd) End Sub

Această subrutină tratează evenimentul produs prin clic pe butonul cu inscripţia Aplicare Coeficienti şi efectuează următoarele acţiuni:

- Atribuie variabilelor de tip Variant ca, cb, cc şi cd valorile de tip text extrase din cutiile de editare coef_a, coef_b, coef_c şi coef_d;

- Testează dacă nu toate textele preluate au semnificaţie numerică şi în acest caz afişează un mesaj de eroare şi forţează ieşirea din subrutină fără alte efecte;

- Dacă toate textele preluate au semnificaţie numerică ele sunt convertite în valori numerice

Page 283: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 271

(prin funcţia Val) şi sunt introduse în celulele coefa, coefb, coefc şi coefd din foaia Sheet2. Private Sub Aplic_lim_Click() xi = x_in.Text xf = x_fin.Text If Not (IsNumeric(xi) And IsNumeric(xf)) Then MsgBox "Limite gresite!", vbExclamation, "Eroare" Exit Sub Else xi=Val(xi) xf=Val(xf) If (xi > xf) Or (xi = xf) Then MsgBox "Limite gresite!", vbExclamation, "Eroare" Exit Sub End If End If Range("xin").Value = xi Range("xfin").Value = xf Range("x0").Value = 0.5 * (xi + xf) x_start.Text = CStr(Range("x0").Value) End Sub

Această subrutină tratează evenimentul produs prin clic pe butonul cu inscripţia Aplicare Limite şi efectuează următoarele acţiuni:

- Atribuie variabilelor de tip Variant xi şi xf valorile de tip text preluate din cutiile de editare x_in şi x_fin;

- Testează dacă nu toate textele preluate au semnificaţie numerică şi în acest caz afişează un mesaj de eroare şi forţează ieşirea din subrutină fără alte efecte;

- Dacă toate textele preluate au semnificaţie numerică, ele sunt convertite la valoare numerică şi se testează dacă nu cumva, din greşeală, s-a introdus xi > xf, situaţie în care este afişat un mesaj de eroare şi se forţează ieşirea din subrutină fără alte efecte;

- Dacă nu s-a detectat nici una dintre erorile de mai sus, valorile preluate sunt introduse în celulele xin, şi xfin din foaia Sheet2;

- Se calculează media valorilor introduse ca limite şi rezultatul este introdus în celula x0 din foaia Sheet2;

- Valoarea din celula x0 din foaia Sheet2 este atribuită prin convertire la forma text cutiei de editare x_start. Private Sub Rezolvare_Click() If Not (IsNumeric(x_start.Text)) Then MsgBox "Valoare gresita!", vbExclamation, "Eroare" x_start.Text = CStr(Range("x0").Value) Exit Sub End If sol_anter = Range("x0").Value preciz = Application.MaxChange Range("x0").Value = Val(x_start.Text) Range("fx0").GoalSeek Goal:=0, ChangingCell:=Range("x0") rezult = Abs(Range("fx0").Value) If (rezult > preciz) Then MsgBox "Nu s-a gasit solutia!", vbExclamation, "Atentie!" Else MsgBox ("Solutia gasita este x=" & Range("x0")), vbOKOnly, "Raport"

Page 284: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 272

If retine_nu.Value = True Then Range("x0").Value = sol_anter Else x_start.Text = Range("x0").Value End If End If End Sub

Această subrutină tratează evenimentul clic pe butonul cu inscripţia Rezolvare şi efectuează următoarele acţiuni:

- Se testează dacă textul din cutia de editare x_start este lipsit de semnificaţie numerică şi, în acest caz, este afişată o cutie de dialog cu un mesaj de eroare, textul scris de utilizator este înlocuit cu valoarea numerică din celula x0 a foii Sheet2 convertită la forma text şi se forţează ieşirea din subrutină fără alte efecte;

Dacă textul din cutia de editare are semnificaţie numerică urmează următoarele acţiuni: - Variabila sol_anter preia valoarea din celula x0 a foii Sheet2; - Variabila preciz ia valoarea setării Maximum Change din cutia de dialog Options,

pagina Calculation a programului EXCEL, stabilită ca nivel de precizie a calculelor; - Celula x0 a foii Sheet2 primeşte valoarea de conversie la forma numerică a textului

extras din cutia de editare x_start; - Se declanşează procedura Goal Seek descrisă mai înainte, prin instrucţiunea

corespunzătoare; - Variabila rezult primeşte valoarea absolută din celula fx0 a foii Sheet2, rezultată din

procedura Goal Seek; - Rezultatul obţinut se compară cu precizia impusă. Dacă el este mai mare se afişează o

utie de mesaj care avertizează că nu a fost găsită soluţia; - Dacă rezultatul obţinut este mai mic decât precizia impusă, se afişează o cutie cu un

mesaj care anunţă găsirea soluţiei şi valoarea ei; - Dacă valoarea butonului de opţiune pentru nereţinerea soluţiei (retine_nu) este 1 (a fost

bifat), atunci celula x0 din foaia Sheet2 îşi recapătă conţinutul dinaintea rezolvării, altfel îl primeşte pe cel provenit din rezolvare. Private Sub Iesire_Click() Unload UserForm1 End Sub

Această subrutină produce numai închiderea cutiei de dialog. În foaia de module generale Module1 se scrie subrutina necesară afişării cutiei de dialog:

Sub Afisare_Dialog() Load UserForm1 UserForm1.Show End Sub

11.7.4. Asamblarea aplicaţiei În sfârşit, în foaia Sheet1 se crează butonul Rezolvare folosind cutia cu instrumente

Forms şi se asociază cu subrutina Afisare_Dialog.

11.7.5. Protecţia aplicaţiei Pentru protejarea datelor şi formulelor din foaia Sheet2, aceasta se va ascunde (Hide), iar

pentru protejarea formulelor de referire din foaia Sheet1 aceasta se va proteja (Protect Sheet). Aplicaţia este acum gata de utilizare.

Page 285: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 273

Fig.11.7.4. 11.7.6. Observaţii finale Aşa cum a fost definită funcţia ca una analitică sub forma unui polinom de gradul al

treilea, funcţia aproximată prin facilitatea Trend Line coincide cu cea originală şi, ca urmare, curba funcţiei aproximate trece prin punctele funcţiei original.

Într-un caz oarecare, când funcţia originală este definită printr-un set de puncte luate la întâmplare, sau provenite din măsurători efectuate asupra unei mărimi fizice care, fie nu este modelabilă printr-un polinom de gradul trei, fie este marcată de erori de măsurare, curba funcţiei aproximate trece printre punctele funcţiei originale aşa cum se vede din figura 11.7.4.

§11.8. Aplicaţie la integrarea ecuaţiilor diferenţiale prin metode Euler

11.8.1. Obiectivul lucrării În cele ce urmează vom exemplifica metodele Euler simplă şi Euler predictor-corector.

Pentru a putea compara cele două metode se va crea o diagramă comună pentru cele două rezultate.

De asemenea, pentru o şi mai bună comparaţie, pe diagramă se va reprezenta şi ecuaţia analitică a funcţiei integrale.

Să presupunem funcţia: având soluţiile xxxy ⋅−= 431=-2, x2=0 şi x3=2. Derivata

funcţiei este:

( ) 423, −⋅==′ xyxfy Pentru început să presupunem că nu se cunoaşte y şi se doreşte determinarea lui folosind o

metodă de integrare aproximativă pe un interval dat. Această metodă va determina un set de valori aproximative y asupra cărora vom aplica o metodă de aproximare pentru a determina expresia funcţiei integrate şi a o putea compara cu funcţia analitică.

Se reamintesc formulele de integrare: - Formula Euler simplă: ( )1,11 −−⋅+−= iyixfhiyiy , 1−−= ixixh

Page 286: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 274

- Formula Euler predictor-corector: ( )

−+−−⋅+−= 1,1,15.01

jiyixfiyixfhiy

jiy

unde i este indicele punctului curent iar j este indicele iteraţiei curente. Deoarece funcţia dată f nu depinde de y, procedeul iterativ se rezumă la un singur pas iar

formulele de integrare devin: - Formula Euler simplă: 11 −′⋅+−= iyhiyiy , 1−−= ixixh

- Formula Euler predictor-corector: , [ ]iyiyhiyjiy ′+−′⋅+−= 15.01 1−−= ixixh

Mersul lucrării este dat mai jos.

11.8.2. Crearea aplicaţiei În foaia de calcul Sheet1 se crează tabelul din figura 11.8.1.

Fig.11.8.1.

11.8.2.1. Completarea tabelului - Se completează inscripţiile tabelului; - În domeniul C3:K3 se scriu valorile de discretizare a intervalului de definiţie adoptat

(între -2 şi 2); - În celula C4 se introduce formula =3*C3^2-4 care, apoi, se extinde prin tragere peste

domeniul C4:K4; - În celula C5 se introduce valoarea dată de condiţia iniţială Cauchy, adică 0; - În celula D5 se introduce formula de intgrare Euler simplă =C5+(D3-C3)*D4 şi apoi se

extinde prin tragere peste tot domeniul D5:K5; - În celula C6 se introduce valoarea dată de condiţia iniţială Cauchy, adică 0; - În celula D6 se introduce formula de integrare Euler predictor-corector =C6+0.5*(D3-

C3)*(C4+D4) care se extinde apoi prin tragere peste tot domeniul D6:K6; - În celula C7 se introduce formula pentru y analitic, adică =C3^3-4*C3, care se extinde

apoi prin tragere peste tot domeniul C7:K7; - În celula L7 se introduce formula =ABS(MAX(C7:K7)) pentru extragerea celei mai mari

valori din interval a funcţiei analitice, în valoare absolută; - Folosind comanda Insert>Name>Define se atribuie celulei L7 numele maxy; - În celula C8 se introduce formula =ABS(C5-C7)/maxy şi se extinde apoi peste tot

domeniul C8:K8; - În celula L8 se introduce formula =MAX(C8:K8); - În celula C9 se introduce formula =ABS(C6-C7)/maxy şi apoi se extinde peste tot

domeniul C9:K9;

Page 287: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 275

- În celula L9 se introduce formula =MAX(C9:K9); - În celula M8 se introduce formula =L8/L7. Se denumeşte această celulă ereul0; - În celula M9 se introduce formula =L9/L7. Se denumeşte această celulă ereul1; - Se selectează celulele M8 şi M9. De pe bara de instrumente Formatting se acţionează

butonul Percent Style şi apoi se apasă de două ori butonul Increase Decimal pentru a se produce afişarea sub forma procentuală cu două zecimale:

Fig.11.8.2.

11.8.2.2. Crearea diagramei

Fig.11.8.3.

Diagrama se crează cu comanda Insert>Chart, folosind ca serii de date domeniile C3:K3 pentru x, C5:K5 pentru y obţinut prin Euler simplu, C6:K6 pentru y obţinut prin Euler predictor-corector şi C7:K7 pentru y analitic.

Tipul folosit este Scatter cu subtipul Compares pairs of values.

După crearea diagramei, se foloseşte comanda Add Trendline pentru a se crea aproximări polinomiale de ordinul trei ale funcţiilor din diagramă, cu opţiunea de afişare a ecuaţiilor pe diagramă.

Cu aceşti parametri se crează diagrama din figura 11.8.2, ca foaie de diagramă distinctă, cu numele Chart1.

11.8.3. Crearea unui instrument de informare Pentru a se obţine o posibilitate de selectare a informaţiilor afişate de diagramă se

procedează în următoarele etape: 11.8.3.1. Crearea unei cutii de dialog - În editorul de Visual Basic se crează obiectul UserForm1 cu inscripţia Afisare ecuatii, care conţine:

Page 288: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 276

= un chenar de grup (Frame) cu inscripţia Ecuatii; = un buton de opţiune (OptionButton) cu inscripţia Euler simplu; = un buton de opţiune (OptionButton) cu inscripţia Euler predictor-corector; = o etichetă (Label) în care se va afişa ecuaţia curbei de integralei de aproximare selectate; = o etichetă (Label) în care se va afişa eroarea integralei de aproximare selectate; = un buton (CommandButton) cu inscripţia Terminare, pentru închiderea cutiei de dialog. După creare, aspectul cutie de dialog în rulare poate fi, la un moment dat, cel din figura 11.8.3. Proprietăţile componentelor cutiei de dialog sunt prezentate în tabelul următor.

Tip de obiect Denumire (Name)

Proprietăţi şi observaţii (Proprietăţile nemenţionate rămân la valorile

prestabilite) Cutia de dialog (Userform) UserForm1 Caption=Afisare ecuatii, Height=194, Width=221 Cadru de grup (Frame) Frame1 Caption=Ecuatii, Height=133, Width=206 Buton de opţiune (OptionButton)

Euler_simp Caption=Euler simplu, Accelerator=s, Height=17, Width=62

Buton de opţiune (OptionButton)

Euler_predcor Caption=Euler predictor-corector, Accelerator=p, Height=17, Width=108

Etichete (Label) în grupul Ecuatii: - prima - a doua

Ecuatie Eroare

Caption=şir vid (se şterge conţinutul iniţial), Font=Tahoma, Regular, 12, Height=24, Width=188

Buton de comandă (CommandButton)

Terminare Caption= Terminare, Accelerator= T, Height=27, Width=92

11.8.4. Crearea subrutinelor obiectelor de interacţiune Prin metoda de selectare a obiectului de interacţiune vizat şi de acţionare a comenzii

View>Code, se crează intrările pentru subrutinele private de tratare a evenimentelor şi apoi se completează prin scrierea acţiunilor, conform listei de mai jos (excepţie face subrutina de initializare care se scrie complet manual):

Private Sub UserForm_Initialize() Euler_simp.Value = True With Application.Charts("Chart1") .SeriesCollection(1).Trendlines(1).Border.Weight = xlThick .SeriesCollection(2).Trendlines(1).Border.Weight = xlThin .SeriesCollection(1).Trendlines(1).DataLabel.Font.Bold = True .SeriesCollection(2).Trendlines(1).DataLabel.Font.Bold = False End With Ecuatie.Caption = _ Application.Charts("Chart1").SeriesCollection(1).Trendlines(1).DataLabel.Text Eroare.Caption = "Eroare=" & Application.Worksheets("Sheet1").Range("ereul0").Text End Sub

Această subrutină pregăteşte cutia de dialog în vederea afişării şi efectuează următoarele acţiuni:

- Activează în starea bifat butonul de opţiune Euler_simp; - Afişează cu linie groasă curba de aproximare prin metoda Euler simplă din diagrama

Chart1; - Afişează cu linie subţire curba de aproximare prin metoda Euler predictor-corector din

diagrama Chart1;

Page 289: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 277

- Afişează cu caractere îngroşate ecuaţia curbei de aproximare prin metoda Euler simplă; - Afişează cu caractere obişnuite ecuaţia curbei de aproximare prin metoda Euler predictor-

corector; - Atribuie şirul de text al ecuaţiei curbei Euler simplă din diagrama Chart1 ca valoare a

proprietăţii inscripţie (Caption) a etichetei Ecuatie; - Atribuie şirul de text al celulei ereul0 din foaia Sheet1 ca valoare a proprietăţii inscripţie

(Caption) a etichetei Eroare; Observaţie: numele de obiect ale curbelor pot fi aflate în două moduri: - prin clic pe curba vizată în foaia de diagramă şi inspectarea conţinutului câmpului de

afişare Name Box din stânga sus a ferestrei diagramei; - efectuând o înregistrare de macrocomandă în care se aplică un clic de selecţie pe curba

vizată şi, eventual, se operează modificări de atribute de afişare, după care se inspectează textul sursă al macrocomenzii în editorul de Visual Basic. Private Sub Euler_simp_Click() With Application.Charts("Chart1") .SeriesCollection(1).Trendlines(1).Border.Weight = xlThick .SeriesCollection(2).Trendlines(1).Border.Weight = xlThin .SeriesCollection(1).Trendlines(1).DataLabel.Font.Bold = True .SeriesCollection(2).Trendlines(1).DataLabel.Font.Bold = False End With Ecuatie.Caption = _ Application.Charts("Chart1").SeriesCollection(1).Trendlines(1).DataLabel.Text Eroare.Caption = "Eroare=" & Application.Worksheets("Sheet1").Range("ereul0").Text End Sub

Această subrutină tratează evenimentul clic pe butonul de opţiune Euler_simp efecuând acţiunile următoare:

- Afişează cu linie groasă curba de aproximare prin metoda Euler simplă din diagrama Chart1;

- Afişează cu linie subţire curba de aproximare prin metoda Euler predictor-corector din diagrama Chart1;

- Afişează cu caractere îngroşate ecuaţia curbei de aproximare prin metoda Euler simplă; - Afişează cu caractere obişnuite ecuaţia curbei de aproximare prin metoda Euler predictor-

corector; - Atribuie şirul de text al ecuaţiei curbei Euler simplă din diagrama Chart1 ca valoare a

proprietăţii inscripţie (Caption) a etichetei Ecuatie; - Atribuie şirul de text al celulei ereul0 din foaia Sheet1 ca valoare a proprietăţii inscripţie

(Caption) a etichetei Eroare; Private Sub Euler_predcor_Click() With Application.Charts("Chart1") .SeriesCollection(2).Trendlines(1).Border.Weight = xlThick .SeriesCollection(1).Trendlines(1).Border.Weight = xlThin .SeriesCollection(2).Trendlines(1).DataLabel.Font.Bold = True .SeriesCollection(1).Trendlines(1).DataLabel.Font.Bold = False End With Ecuatie.Caption = _ Application.Charts("Chart1").SeriesCollection(2).Trendlines(1).DataLabel.Text Eroare.Caption = "Eroare=" & Application.Worksheets("Sheet1").Range("ereul1").Text End Sub

Această subrutină tratează evenimentul clic pe butonul de opţiune Euler_predcor efecuând acţiunile următoare:

Page 290: Programarea Calculatoarelor si Limbaje de Programare

Cap.11. Aplicaţii în mediul de programare Visual Basic sub EXCEL 278

- Afişează cu linie subţire curba de aproximare prin metoda Euler simplă din diagrama Chart1;

- Afişează cu linie groasă curba de aproximare prin metoda Euler predictor-corector din diagrama Chart1;

- Afişează cu caractere obişnuite ecuaţia curbei de aproximare prin metoda Euler simplă; - Afişează cu caractere îngroşate ecuaţia curbei de aproximare prin metoda Euler predictor-

corector; - Atribuie şirul de text al ecuaţiei curbei Euler predictor-corecctor din diagrama Chart1 ca

valoare a proprietăţii inscripţie (Caption) a etichetei Ecuatie; - Atribuie şirul de text al celulei ereul1 din foaia Sheet1 ca valoare a proprietăţii inscripţie

(Caption) a etichetei Eroare; Private Sub Terminare_Click() With Application.Charts("Chart1") .SeriesCollection(1).Trendlines(1).Border.Weight = xlThin .SeriesCollection(2).Trendlines(1).Border.Weight = xlThin .SeriesCollection(1).Trendlines(1).DataLabel.Font.Bold = False .SeriesCollection(2).Trendlines(1).DataLabel.Font.Bold = False End With Unload UserForm1 End Sub

Această subrutină tratează evenimentul clic pe butonul de comandă Terminare efecuând acţiunile următoare:

- Afişează cu linie subţire curba de aproximare prin metoda Euler simplă din diagrama Chart1; - Afişează cu linie subţire curba de aproximare prin metoda Euler predictor-corector din

diagrama Chart1; - Afişează cu caractere obişnuite ecuaţia curbei de aproximare prin metoda Euler simplă; - Afişează cu caractere obişnuite ecuaţia curbei de aproximare prin metoda Euler predictor-

corector; - Închide cutia de dialog. De asemenea, în vederea integrării aplicaţiei, în foaia de module Module1 se scriu

subrutina de apel a cutiei de dialog, şi cele de comutare dintr-o foaie în alta (acestea din urmă pot fi şi înregistrate):

Sub Afisare_Dialog() Load UserForm1 UserForm1.Show End Sub Sub Selectare_Foaie() Sheets("Sheet1").Select End Sub Sub Selectare_Diagrama() Sheets("Chart1").Select End Sub 11.8.5. Integrarea aplicaţiei Pentru integrarea aplicaţiei, cu ajutorul cutiei cu instrumente Forms se crează butoanele

Afisare ecuatii (care se asociază cu subrutina Afisare_Dialog), Comutare la diagramă (asociat cu Selectare_Foaie) şi Comutare la tabel (asociată cu Selectare_Foaie).

Dacă se doreşte protecţia datelor, se va renunţa la butoanele de comutare, şi se va crea un singur buton Afisare ecuatii în foaia de diagramă Chart1, iar foaia Sheet1 se va ascunde.

Page 291: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 279

Cap.12. Aplicaţii în FORTRAN §12.1. Calculul unei plutiri drepte folosind FORTRAN

12.1.1. Definirea temei

Fig.12.1.1. Fig.12.1.2

O plutire dreaptă este linia de intersecţie dintre un plan orizontal şi carena navei. Mărimile de calculat sunt:

Aria suprafeţei plutirii: ; Centrul de greutate al plutirii: A w 2 ydxL

= ∫ xF2

A wxydx

L= ∫

Momentele de inerţie: ∫=L

dx3y32

xI şi Iy 2 x2ydxL

= ∫

Metoda de calcul a unei integrale prin însumare succesivă se bazează pe formula:

( ) i

1i

1jj

x

x

∆A∆Adxxf1i

1

+=∑∫−

=

+

12.1.2. Etape de lucru 1. Se va folosi mediul FORTRAN Salford PLATO în care se scrie următorul program în

format liber (free format) f95: PROGRAM PLUTIRI IMPLICIT NONE INTEGER n, i REAL, DIMENSION(100) :: x, y, f CHARACTER(LEN=16) :: s1="Punctul: ", s2=" Abscisa x(", & s3=" Semilatimea y(", s4=")=" REAL aw, xf, ix, iy, INTEGRARE WRITE(*,"(A)",ADVANCE="NO") "Introduceti numarul de puncte al plutirii " READ(*,*) n WRITE(*,*) "Introduceti abscisele si semilatimile" DO i=1,n WRITE(*,100,ADVANCE="NO") s1, i, s2, i, s4 READ(*,*) x(i) WRITE(*,100,ADVANCE="NO") s1, i, s3, i, s4 READ(*,*) y(i) END DO DO i=1,n f(i)=y(i) END DO aw=2*INTEGRARE(n,x,f)

Page 292: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 280

DO i=1,n; f(i)=y(i)*x(i); END DO xf=2*INTEGRARE(n,x,f)/aw DO i=1,n; f(i)=y(i)*y(i)*y(i); END DO ix=2*INTEGRARE(n,x,f)/3 DO i=1,n; f(i)=y(i)*x(i)*x(i); END DO iy=2*INTEGRARE(n,x,f) WRITE(*,*)"Aria plutirii A=", aw WRITE(*,*)"Abscisa centrului plutirii Xf=", xf WRITE(*,*)"Momentul de inertie Ix=", ix WRITE(*,*)"Momentul de inertie Iy=", iy 100 FORMAT(A9,I3,A16,I3,A2) END PROGRAM PLUTIRI

REAL FUNCTION INTEGRARE(n, x, f) INTEGER n REAL, DIMENSION(n) :: x,f INTEGRARE=0 DO i=2,n INTEGRARE=INTEGRARE+(x(i)-x(i-1))*(f(i)+f(i-1))/2 END DO END FUNCTION INTEGRARE

După cum se observă, programul este scris integral într-un singur fişier. Vom salva acest

fişier sub numele de Plutiri.f95 După comenzile de compilare (Compile) şi construcţie (Build) se aplică comanda de rulare

(Start Run) şi se obţine afişarea de mai jos (unde sunt cuprinse şi răspunsurile operatorului): Introduceti numarul de puncte al plutirii 7 Introduceti abscisele si semilatimile Punctul: 1 Abscisa x( 1)=0 Punctul: 1 Semilatimea y( 1)=0 Punctul: 2 Abscisa x( 2)=10 Punctul: 2 Semilatimea y( 2)=10 Punctul: 3 Abscisa x( 3)=20 Punctul: 3 Semilatimea y( 3)=10 Punctul: 4 Abscisa x( 4)=30 Punctul: 4 Semilatimea y( 4)=10 Punctul: 5 Abscisa x( 5)=40 Punctul: 5 Semilatimea y( 5)=10 Punctul: 6 Abscisa x( 6)=50 Punctul: 6 Semilatimea y( 6)=10 Punctul: 7 Abscisa x( 7)=60 Punctul: 7 Semilatimea y( 7)=0 Aria plutirii A= 1000.00 Abscisa centrului plutirii Xf= 30.0000 Momentul de inertie Ix= 33333.3 Momentul de inertie Iy= 1.100000E+06

Press RETURN to close window ...

2. În a doua parte a lucrării rescriem programul astfel încât să folosim şi o procedură SUBROUTINE, astfel: PROGRAM PLUTIRI IMPLICIT NONE

Page 293: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 281

INTEGER n, i REAL, DIMENSION(100) :: x, y CHARACTER(LEN=16) :: s1="Punctul: ", s2=" Abscisa x(", & s3=" Semilatimea y(", s4=")=" REAL aw, xf, ix, iy WRITE(*,"(A)",ADVANCE="NO") "Introduceti numarul de puncte al plutirii " READ(*,*) n WRITE(*,*) "Introduceti abscisele si semilatimile" DO i=1,n WRITE(*,100,ADVANCE="NO") s1, i, s2, i, s4 READ(*,*) x(i) WRITE(*,100,ADVANCE="NO") s1, i, s3, i, s4 READ(*,*) y(i) END DO CALL CALCUL(n,x,y,aw,xf,ix,iy) WRITE(*,*)"Aria plutirii A=", aw WRITE(*,*)"Abscisa centrului plutirii Xf=", xf WRITE(*,*)"Momentul de inertie Ix=", ix WRITE(*,*)"Momentul de inertie Iy=", iy 100 FORMAT(A9,I3,A16,I3,A2) END PROGRAM PLUTIRI

SUBROUTINE CALCUL(n,x,y,aw,xf,ix,iy) INTEGER n REAL, DIMENSION(n) :: x, y, f REAL aw, xf, ix, iy, INTEGRARE DO i=1,n f(i)=y(i) END DO aw=2*INTEGRARE(n,x,f) DO i=1,n; f(i)=y(i)*x(i); END DO xf=2*INTEGRARE(n,x,f)/aw DO i=1,n; f(i)=y(i)*y(i)*y(i); END DO ix=2*INTEGRARE(n,x,f)/3 DO i=1,n; f(i)=y(i)*x(i)*x(i); END DO iy=2*INTEGRARE(n,x,f) END SUBROUTINE CALCUL

REAL FUNCTION INTEGRARE(n, x, f) INTEGER n REAL, DIMENSION(n) :: x,f INTEGRARE=0 DO i=2,n INTEGRARE=INTEGRARE+(x(i)-x(i-1))*(f(i)+f(i-1))/2 END DO END FUNCTION INTEGRARE

Acest fişier îl vom salva sub numele de Plutiri_1.f95 3. În a treia parte a lucrării vom transforma prima aplicaţie Plutiri.f95, restructurând-o ca un

proiect. Rostul acestei modificări este de a face disponibil modulul de calcul de integrare şi pentru alte aplicaţii. Acest proiect numit Calc_Plut.ftn95p va conţine două fişiere:

Fişierul program principal Plutiri_2.f95, cu componenţa de mai jos: PROGRAM PLUTIRI USE CALCUL

Page 294: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 282

IMPLICIT NONE INTEGER n, i REAL, DIMENSION(100) :: x, y, f CHARACTER(LEN=16) :: s1="Punctul: ", s2=" Abscisa x(", & s3=" Semilatimea y(", s4=")=" REAL aw, xf, ix, iy WRITE(*,"(A)",ADVANCE="NO") "Introduceti numarul de puncte al plutirii " READ(*,*) n WRITE(*,*) "Introduceti abscisele si semilatimile" DO i=1,n WRITE(*,100,ADVANCE="NO") s1, i, s2, i, s4 READ(*,*) x(i) WRITE(*,100,ADVANCE="NO") s1, i, s3, i, s4 READ(*,*) y(i) END DO DO i=1,n f(i)=y(i) END DO aw=2*INTEGRARE(n,x,f) DO i=1,n; f(i)=y(i)*x(i); END DO xf=2*INTEGRARE(n,x,f)/aw DO i=1,n; f(i)=y(i)*y(i)*y(i); END DO ix=2*INTEGRARE(n,x,f)/3 DO i=1,n; f(i)=y(i)*x(i)*x(i); END DO iy=2*INTEGRARE(n,x,f) WRITE(*,*)"Aria plutirii A=", aw WRITE(*,*)"Abscisa centrului plutirii Xf=", xf WRITE(*,*)"Momentul de inertie Ix=", ix WRITE(*,*)"Momentul de inertie Iy=", iy 100 FORMAT(A9,I3,A16,I3,A2) END PROGRAM PLUTIRI

şi fişierul de modul Calc_intg.f95, cu componenţa următoare: MODULE CALCUL IMPLICIT NONE CONTAINS REAL FUNCTION INTEGRARE(n, x, f) INTEGER n REAL, DIMENSION(n) :: x,f INTEGRARE=0 DO i=2,n INTEGRARE=INTEGRARE+(x(i)-x(i-1))*(f(i)+f(i-1))/2 END DO END FUNCTION INTEGRARE END MODULE CALCUL

4. O altă îmbunătăţire posibilă a proiectului este includerea datelor de intrare într-un fişier de includere care să poată fi modificat separat de restul aplicaţiei. Aceasta nu exclude fazele de recompilare şi reconstrucţie. Proiectul va conţine acum următoarele componente:

Fişierul program principal Plutiri_3.f95 care conţine: PROGRAM PLUTIRI USE CALCUL INCLUDE 'DATE_XY.inc'

Page 295: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 283

INTEGER i REAL, DIMENSION(100) :: f CHARACTER(LEN=16) :: s1="Punctul: ", s2=" Abscisa x(", & s3=" Semilatimea y(", s4=")=" REAL aw, xf, ix, iy WRITE(*,*) "Numarul de puncte al plutirii este n=",n WRITE(*,*) "Abscisele si semilatimile sunt:" DO i=1,n WRITE(*,100) s1, i, s2, i, s4, x(i) WRITE(*,100) s1, i, s3, i, s4, y(i) END DO DO i=1,n f(i)=y(i) END DO aw=2*INTEGRARE(n,x,f) DO i=1,n; f(i)=y(i)*x(i); END DO xf=2*INTEGRARE(n,x,f)/aw DO i=1,n; f(i)=y(i)*y(i)*y(i); END DO ix=2*INTEGRARE(n,x,f)/3 DO i=1,n; f(i)=y(i)*x(i)*x(i); END DO iy=2*INTEGRARE(n,x,f) WRITE(*,*)"Aria plutirii A=", aw WRITE(*,*)"Abscisa centrului plutirii Xf=", xf WRITE(*,*)"Momentul de inertie Ix=", ix WRITE(*,*)"Momentul de inertie Iy=", iy 100 FORMAT(A9,I3,A16,I3,A2,F10.3) END PROGRAM PLUTIRI

Fişierul Calc_intg.f95 nemodificat. Fişierul de includere DATE_XY.INC:

IMPLICIT NONE INTEGER :: n=7 REAL, DIMENSION(7):: x DATA x /0.0,10.0,20.0,30.0,40.0,50.0,60.0/ REAL, DIMENSION(7):: y DATA y /0.0,10.0,10.0,10.0,10.0,10.0,0.0/

§12.2. Lucrul cu fişiere în FORTRAN

12.2.1. Definirea temei Se cere preluarea valorilor numerice scrise într-un fişier, ordonarea lor în sens crescător şi

scrierea lor într-un alt fişier. Se va folosi mediul FORTRAN Salford PLATO. 12.2.2. Etape de lucru 1. Folosind Notepad se va scrie un fişier denumit Numere.txt al cărui conţinut este

următoarea succesiune de valori numerice reale: 11.2 253.45 3.456 5.021 0.12

2. În mediul Plato se crează programul Ordon_fis.f95 cu următorul conţinut:

Page 296: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 284

PROGRAM ORDONARE INTEGER :: nunit=1,NRECR,STARE,I REAL VALOARE LOGICAL :: CITIRE=.TRUE. REAL, ALLOCATABLE :: V(:) OPEN(UNIT=nunit,FILE='Numere.txt',ACTION='READ') NRECR=0 DO WHILE (CITIRE) READ(UNIT=nunit,FMT='(F20.6)',IOSTAT=STARE)VALOARE IF(STARE==-1) THEN CITIRE=.FALSE. ELSE NRECR=NRECR+1 END IF END DO ALLOCATE (V(NRECR)) REWIND(UNIT=nunit) DO I=1,NRECR READ(UNIT=nunit,FMT='(F20.6)')V(I) END DO CALL ORD_NUM(NRECR,V) OPEN(UNIT=nunit,FILE='Num_ord.txt',ACTION='WRITE') REWIND(UNIT=nunit) DO I=1,NRECR WRITE(UNIT=nunit,FMT='(F20.6)') V(I) END DO CLOSE(UNIT=nunit) DEALLOCATE(V) END PROGRAM ORDONARE

SUBROUTINE ORD_NUM(N,V) DIMENSION :: V(N) REAL A INTEGER I,J DO I=1,N-1 DO J=I+1,N IF(V(I)>V(J)) THEN A=V(I) V(I)=V(J) V(J)=A END IF END DO END DO END SUBROUTINE ORD_NUM

Semnificaţiile notaţiilor folosite în program sunt următoarele: În programul principal: nunit – număr de unitate, este un număr atribuit fişierului cu care se lucrează (1...99) NRECR – număr de înregistrări citite STARE – variabilă care preia valoarea indicatorului de intrare/ieşire IOSTAT şi care la

citirea dintr-un fişier are valoarea –1 dacă s-a atins sfârşitul fişierului I – indice de contorizare a ciclurilor DO sau indice de tablou VALOARE – variabilă care stochează valoarea numerică citită din fişier CITIRE – variabilă logică căreia i se va atribui valoarea .FALSE. în momentul atingerii

Page 297: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 285

sfârşitului de fişier V – vector (tablou unidimensional) destinat să stocheze valorile reale citite din fişier.

Iniţial dimensiunea lui este neprecizată şi este declarat alocabil. După contorizarea numărului de înregistrări citite tabloului i se alocă spaţiul necesar

În subrutină: N – dimensiunea tabloului V A – variabilă reală auxiliară necesară interschimbului de valori între valoarea anterioară şi

cea curentă atunci când se constată că V(I) este mai mare decât V(J) I, J – indici de contorizare a ciclurilor DO sau indici de tablou Acţiunile efectuate de program sunt următoarele: - se deschide fişierul Numere.txt şi este citită câte o înregistrare. De câte ori acest lucru

poate avea loc se incrementează variabila NRECR - se redeschide fişierul Numere.txt şi este citită câte o înregistrare, de data aceasta valorile

citite fiind pe rând memorate în vectorul V - se închide fişierul Numere.txt - se apelează subrutina de reordonare a vectorului V - se deschide fişierul Num_ord.txt - se scriu una câte una valorile vectorului V în acest fişier - se închide fişierul 3. Verificarea rezultatului obţinut Folosind Notepad se deschide fişierul Num_ord.txt Dacă programul a funcţionat corect trebuie să vedeţi următorul conţinut:

0.120000 3.456000 5.021000 11.200000 253.449997

Observaţie: s-a luat precauţia de a indica drept format de citire formatul F20.6 care este acoperitor pentru valorile scrise în fişierul de date de intrare. Altfel citirea ar fi fost defectuoasă.

Observaţie: Fortran nu foloseşte mecanismul de copiere a argumentelor procedurilor (funcţii şi subrutine) ci lucrează direct cu adresele de memorie ale argumentelor. Aceasta înseamnă că orice modificare a valorilor argumentelor transmise se reflectă în programul principal după revenirea din procedură. În aplicaţia de faţă acest lucru a fost favorabil deoarece ne-a permis să reordonăm valorile vectorului V şi ele să rămână reordonate la revenirea din subrutina Ord_num fără alte eforturi suplimentare. În mod normal însă această însuşire este considerată o încălcare a principiului încapsulării datelor statuat de principiile ingineriei programării şi trebuie tratată cu precauţii suplimentare dacă acest efect de vizibilitate în exterior nu este dorit. În acest scop se va proceda la efectuarea explicită de copii ale argumentelor în interiorul procedurii.

§12.3. Conversia datelor între fişiere în FORTRAN

12.3.1. Definirea temei În lucrarea anterioară fişierul de date din care se citea avea o structură foarte simplă,

fiecare înregistrare conţinând numai o singura valoare scrisă în formatul F, iar citirea din fişier se realiza cu un format acoperitor.

Page 298: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 286

Din nefericire lucrurile sunt mai complicate, în practică existând posibilitatea citirii din fişiere cu mai multe date numerice în cadrul aceleiaşi înregistrări, iar tipurile datelor numerice pot diferi între ele. Mai mult, separaţia datelor în cadrul unei înregistrări poate avea loc printr-un număr oarecare de spaţii (blank-uri).

Pentru a nu complica prea mult lucrurile vom restrânge aplicaţia la cazul preluarii de date dintr-un fişier în care sunt scrise date în format F (real) şi I (integer), şi care poate avea şi rânduri libere. Datele preluate vor fi scrise într-un nou fişier care va realiza separaţia datelor printr-un singur spaţiu şi va elimina rândurile goale. Se va folosi mediul FORTRAN Salford PLATO.

12.3.2. Etape de lucru 1. Folosind Notepad se va scrie un fişier denumit Num_div.txt al cărui conţinut este cel de

mai jos. Acolo unde apar caracterele b se va tasta câte un spaţiu pentru fiecare caracter. bbbbbbbb11bbb-235.2346bb1 1.23b253.45 bbbb3.456bbbbb0.12b0.0 -5.021 bbb0.12bb1.0

2. În mediul Plato se crează proiectul IOFile.ftn95p cu următoarea componenţă: Fişierul program principal Citire_din_fis.f95 care conţine instrucţiunile următoare:

PROGRAM CONVERSIE USE EVALUARE IMPLICIT NONE INTEGER :: nunit1=1,nunit2=2,stare,i,nval,ncr CHARACTER(LEN=100) rand,sir_frm,frm_rand,CNUM LOGICAL :: CIT_FIS=.TRUE. REAL, ALLOCATABLE :: vector(:) OPEN(UNIT=nunit1,FILE='Num_div.txt',ACTION='READ') !Obs.1 OPEN(UNIT=nunit2,FILE='Num_div.tmp',ACTION='READWRITE') REWIND(UNIT=nunit2) !Obs.2 DO WHILE (CIT_FIS) !Obs.3 READ(UNIT=nunit1,FMT='(A)',IOSTAT=stare)rand !Obs.4 IF(STARE==-1) THEN !Obs.5 CIT_FIS=.FALSE. ELSE IF (LEN_TRIM(rand)==0) THEN !Obs.6 CONTINUE ELSE CALL EVAL_RAND(rand,nval,sir_frm) !Obs.7 frm_rand="(A"//CNUM(LEN_TRIM(rand(2:))) !Obs.8 ncr=LEN_TRIM(frm_rand) frm_rand(ncr+1:)=')' WRITE(UNIT=nunit2,FMT=frm_rand)rand(2:) END IF END IF END DO CLOSE(UNIT=nunit1) !Obs.9 CLOSE(UNIT=nunit2) OPEN(UNIT=nunit1,FILE='Num_div.tmp',ACTION='READ') !Obs.10 OPEN(UNIT=nunit2,FILE='Num_noi.txt',ACTION='WRITE')

Page 299: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 287

CIT_FIS=.TRUE. !Obs.11 DO WHILE (CIT_FIS) READ(UNIT=nunit1,FMT='(A)',IOSTAT=stare)rand !Obs.12 IF(STARE==-1) THEN CIT_FIS=.FALSE. !Obs.13 ELSE CALL EVAL_RAND(rand,nval,sir_frm) !Obs.14 BACKSPACE(UNIT=nunit1) !Obs.15 ALLOCATE(vector(nval)) !Obs.16 READ(UNIT=nunit1,FMT=sir_frm,IOSTAT=stare)(vector(i),i=1,nval) WRITE(UNIT=6,FMT=sir_frm)(vector(i),i=1,nval) !Obs.17 WRITE(UNIT=nunit2,FMT=sir_frm)(vector(i),i=1,nval) DEALLOCATE(vector(nval)) !Obs.18 NULLIFY(vector) END IF END DO CLOSE(UNIT=nunit1) !Obs.19 CLOSE(UNIT=nunit2) END PROGRAM CONVERSIE

Fişierul modul Evaluare.f95 care conţine instrucţiunile următoare: MODULE EVALUARE IMPLICIT NONE CONTAINS SUBROUTINE EVAL_RAND(rand,nval,sir_frm) CHARACTER(LEN=100) TRIM@,TRIM,rand,rezerva,sir,sir_frm CHARACTER(LEN=10) frm CHARACTER c CHARACTER(LEN=2) CNUM LOGICAL prim INTEGER i,ip,lsir,nval,ncar,nct,ncarrand sir_frm="(" !Obs.20 rand=TRIM@(rand) rand=TRIM(rand) lsir=LEN_TRIM(rand) rand(lsir+1:)=' ' !Obs.21 sir="" !Obs.22 ncarrand=LEN_TRIM(rand)+1 i=0 nval=0 DO WHILE (ncarrand>0) !Obs.23 i=i+1 c=rand(1:1) IF(c==' ') THEN !Obs.24 nval=nval+1 rand=TRIM@(rand) ncarrand=LEN_TRIM(rand) ELSE sir(1:i+1)=sir(1:i)//c rand(1:)=rand(2:) ncarrand=LEN_TRIM(rand)+1 END IF END DO rand=sir !Obs.25

Page 300: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 288

rezerva=sir rand=TRIM@(rand) sir="" !Obs.26 ncarrand=LEN_TRIM(rand) ncar=0 i=0 prim=.TRUE. DO WHILE (ncarrand>0) !Obs.27 i=i+1 c=rand(1:1) IF(c==' ') THEN !Obs.28 ip=SCAN(sir,'.') !Obs.29 IF(ip==0) THEN !Obs.30 lsir=LEN_TRIM(sir) ip=lsir+1 sir(1:lsir+1)=sir(1:lsir)//'.' ncar=ncar+1 END IF IF(prim) THEN !Obs.31 nct=ncar ELSE nct=ncar+1 END IF frm='F'//CNUM(nct)//'.'//CNUM(ncar-ip+1) !Obs.32 lsir=LEN_TRIM(sir_frm) sir_frm(lsir+1:)=frm//',' !Obs.33 prim=.FALSE. !Obs.34 sir="" !Obs.35 i=0 ncar=0 rand=TRIM(rand) ncarrand=LEN_TRIM(rand) ELSE !Obs.36 ncar=ncar+1 sir(1:i+1)=sir(1:i)//c rand(1:)=rand(2:) ncarrand=LEN_TRIM(rand)+1 END IF END DO lsir=LEN_TRIM(sir_frm) !Obs.37 sir_frm(lsir:)=')' rand=rezerva END SUBROUTINE EVAL_RAND END MODULE EVALUARE

Semnificaţiile notaţiilor folosite în program sunt următoarele: În programul principal: nunit1 – număr de unitate atribuit fişierului din care se extrag date (nunit=1, pentru

Num_div.txt); nunit2 – număr de unitate atribuit unui fişier intermediar în care se scriu datele filtrate

(nunit=2, pentru Num_div.tmp); stare – variabilă care preia valoarea indicatorului de intrare/ieşire IOSTAT şi care la citirea

dintr-un fişier are valoarea –1 dacă s-a atins sfârşitul fişierului;

Page 301: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 289

i – indice de contorizare; nval – variabilă reprezentând numărul de valori cuprinse într-o înregistrare citită; ncr – număr de caractere folosit pentru a defini formatul de scriere a unui rând în fişierul

intermediar (scrierea se face în formatul şir de caractere Ann unde nn este numărul de caractere);

rand – variabilă şir de caractere cu lungimea maximă de 100 de caractere care memorează o înregistrare (rand) extrasă din fişierul de citit şi care se va scrie în fişierul intermediar;

sir_frm – Descriptor de formate colectiv, este şirul de caractere care descrie formatul datelor numerice ale înregistrării extrase;

frm_rand – şirul de caractere care descrie formatul în care înregistrarea extrasă va scrisă în fişierul intermediar;

CNUM – numele funcţiei Fortran Salford de conversie a unui număr întreg în şir de caractere;

CIT_FIS – variabilă logică descriind starea de citire din fişier şi care poate fi .TRUE. când poate avea loc citirea şi .FALSE. când s-a atins sfârşitul de fişier şi citirea trebuie să înceteze;

vector – variabilă tablou unidimensională destinată stocării valorilor de tip real citite din fişier. Iniţial ea este declarată de lungime nedefinită dar alocabilă, dimensiunea precizându-se ulterior după citirea unei înregistrări, analiza ei şi determinarea numărului de valori numerice pe care le cuprinde;

În subrutina EVAL_RAND: TRIM@ – numele funcţiei Fortran Salford destinată să elimine spaţiile goale (blank-uri)

din faţa unui şir de caractere; TRIM – numele funcţiei Fortran Salford destinată să elimine spaţiile goale (blank-uri) din

spatele unui şir de caractere; rand – aceeaşi semnificaţie ca în programul principal. Comunicaţia în Fortran dintre

programul principal şi subrutine făcându-se prin adrese această variabilă este şi ca zonă de memorie folosită aceeaşi cu cea folosită de programul principal;

rezerva – variabilă şir de caractere destinată să păstreze o copie a unui alt şir; sir – variabilă de tip şir de caractere în care se preiau unul câte unul caracterele şirului rand

extras din fişierul original, mai puţin caracterele spaţiu excedentare, cu completarea numerelor întregi cu caracterul punct, operaţie în urma căreia toate numerele citite vor deveni de tip real;

sir_frm – aceeaşi semnificaţie ca în programul principal; frm – variabilă de tip şir de caractere de cel mult 10 caractere lungime destinată să

memoreze un subşir reprezentând formatul unei valori (dată) din rândul de date extras. Variabila sir_frm se va compune din concatenarea (alipirea) mai multor asemenea subşiruri;

c – variabilă de tip monocaracter. Este folosită pentru a memora primul caracter extras din şirul rand, după care şirul rand este reconstruit eliminând primul caracter. Astfel, rand va conţine tot mai puţine caractere, până la epuizare;

CNUM – numele funcţiei Fortran Salford de conversie a unui număr întreg în şir de caractere;

prim – variabilă logică care are valoarea .TRUE. dacă caracterul citit este primul din rand şi .FALSE. în caz contrar;

i – indice de contorizare; ip – indicele de ordine al caracterului punct în şirul sir. În a doua parte a subrutinei

EVAL_RAND sir va conţine numai subşirul corespunzător unei singure date din tot şirul rand. Dacă ip=0 înseamnă că numărul este scris fără punct zecimal (ca valoare întreagă) şi i se va adăuga punctul zecimal. Dacă ip este mai mare decât zero valoarea memorată în ip va fi folosită

Page 302: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 290

ulterior la construirea şirului descriptor de format pentru a se calcula numărul de cifre zecimale; lsir – lungimea subşirului sir. Serveşte la calculul lungimii de scriere a formatului F care va

apare în şirul descriptor de format; nval – numărul de valori (date) cuprinse de şirul rand; ncar – numărul curent de caractere prelucrate la construirea unui subşir; nct – numărul total de caractere conţinut de un subşir; ncarrand – numărul de caractere al şirului rand; Acţiunile efectuate de program sunt următoarele (vezi observaţiile marcate în textul sursă): Obs.1. Se deschide pentru citire fişierul Num_div.txt şi pentru citire/scriere fişierul

Num_div.tmp; Obs.2. Se redeschide fişierul Num_div.tmp pentru forţarea plasării indicatorului de poziţie

la începutul primei înregistrări; Obs.3. Se iniţiază un ciclu de citire din fişierul Num_div.txt; Obs.4. Se citeşte o înregistrare (rand) din fişierul Num_div.txt; Obs.5. Dacă s-a întâlnit sfârşitul de fişier se schimbă valoarea CIT_FIS pe .FALSE. Obs.6. Dacă rândul este gol sau conţine numai spaţii goale (blank-uri) se trece la următorul

pas al ciclului; Obs.7. Se apelează subrutina de evaluare a rândului extras. Ea primeşte ca argument

adresele şirului înregistrării extrase (rand) ale variabilei nval (număr de valori pe rând) şi sir_frm (şir descriptor de formate). La terminarea execuţiei subrutinei şirul rand este curăţat de spaţiile excedentare iar nval şi sir_frm conţin datele rezultate din evaluare;

Obs.8. Se formează şirul (frm_rand) descriptor de format de scriere de tip caracter a rândului în fişierul intermediar Num_div.tmp. De exemplu, dacă s-a extras înregistrarea:

bbbb3.456bbbbb0.12b0.0 variabila rand va avea, după prelucrarea cu subrutina EVAL_RAND, forma 3.456b0.12b0.0 deci va conţine 14 caractere. Ca urmare şirul descriptor de format frm_rand va fi (A14). Cu

acest format va avea loc scrierea în fişierul intermediar. Calculul lungimii şirului rand ţine cont de faptul că primul caracter din rând este un spaţiu;

Obs.9. Se închid fişierele; Obs.10. Se deschide din nou fişierul Num_div.tmp, de această dată numai pentru citire. Se

deschide un nou fişier Num_noi.txt pentru scriere. În acesta vor fi scrise aceleaşi valori ca şi pe ecran;

Obs.11. Se pune din nou variabila CIT_FIS pe .TRUE. şi se iniţiază un nou ciclu de citire din fişierul Num_div.tmp;

Obs.12. Se citeşte un rând din fişierul Num_div.tmp; Obs.13. Se constată terminarea citirii fişierului; Obs.14. Se apelează subrutina de evaluare a rândului extras. De această dată, apelul este

necesar pentru a se extrage numărul de valori de pe rand; Obs.15. Se revine pe înregistrarea anterioară (după fiecare operaţie de citire indicatorul de

poziţie în fişier avansează automat la rândul următor aşa încât este necesară revenirea); Obs.16. Se alocă spaţiul de memorie pentru nval poziţii în tabloul unidimensional vector.

Se citeşte din nou rândul de această dată nu în format şir de caractere ci în formatul F determinat de subrutina EVAL_RAND şi stocat în variabila sir_frm;

Obs.17. Se scriu pe ecran (UNIT=6) cele nval valori ale vectorului. La această instrucţiune s-a folosit UNIT=6 şi nu notaţia * deoarece aceasta din urmă are înţelesul de unitate prestabilită care, în acest caz este unitatea nunit1. Notaţia * semnifică ecranul sau tastatura numai la începutul rulării unui program care încă nu a făcut uz de operaţii de intrare/ieşire cu

Page 303: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 291

fişiere. Pentru tastatură se foloseşte UNIT=5. Aceleaşi valori sunt scrise şi în fişierul rezultat Num_noi.txt;

Obs.18. Se dezalocă spaţiile alocate elementelor tabloului vector ca şi adresa de pointer a tabloului vector;

Obs.19. Se închide fişierul intermediar Num_div.tmp şi fişierul rezultant Num_noi.txt; Acţiunile efectuate de subrutina EVAL_RAND sunt următoarele: Obs.20. Se iniţiază şirul descriptor de format sir_frm; Obs.21. Se curăţă şirul rand de spaţiile goale de la început şi de la sfârşit şi i se adaugă un

singur spaţiu gol la capăt. Acest spaţiu gol va semnaliza terminarea unui subşir corespunzător unei valori numerice;

Obs.22. Se iniţiază o variabilă sir în care se vor transfera pe rând caractere din şirul rand. Se determină ncarrand care reprezintă numărul de caractere al rândului rand. Se iniţiază i=0 indicele de parcurgere a citirii caracterelor şi nval=0 numărul de valori detectate;

Obs.23. Se iniţiază un ciclu care va dura cât timp vor mai fi caractere neparcurse în şirul rand, ciclu în cuprinsul căruia se analizează tot timpul primul caracter din şirul rand;

Obs.24. Dacă a fost întâlnit caracterul spaţiu înseamnă că s-a terminat un subşir de caractere care reprezintă o valoare numerică, deci nval va fi incrementat, apoi se vor elimina caracterele spaţiu de la începutul lui rand şi se redetermină ncarrand. Dacă nu, caracterul întâlnit se va include în sir pe poziţia i+1 iar din rand se elimină primul caracter. După această etapă sir nu va mai conţine caractere spaţiu excedentare (două valori numerice vor fi separate printr-un singur şir) şi se va cunoaşte numărul de valori din şir, nval;

Obs.25. Se transferă şirul sir în şirul rand şi în şirul rezerva. Se elimină spaţiile goale de la începutul lui rand (dacă mai există);

Obs.26. Şirul sir este iniţializat din nou. Se determină numărul de caractere din şirul rand. Se iniţializează ncar=0 şi i=0. Variabila care indică citirea primului număr de pe rand se iniţializează la valoarea .TRUE.

Obs.27. Se iniţiază un ciclu de citire a şirului rand, citindu-se mereu primul caracter al rândului până la epuizarea tuturor caracterelor. Indicele i este destinat să memoreze numărul caracterului curent la citire. Caracterul c este primul caracter al lui rand;

Obs.28. Dacă c este un spaţiu înseamnă că s-a terminat un subşir numeric; Obs.29. Indicele ip redă poziţia în care se găseşte caracterul punct în subşirul numeric; Obs.30. Dacă ip=0 subşirul numeric nu conţine caracterul punct şi el va fi adăugat subşirului; Obs.31. Dacă are loc citirea primului subşir numeric numărul total de caractere nct este cel

citit adică ncar, altefel este cu 1 mai mare. Această convenţie este destinată să producă un şir descriptor de formate care să includă spaţiul separator în descriptoarele de formate ale subşirurilor numerice cu excepţia primului subşir;

Obs.32. Instrucţiune de formare a unui descriptor de format F. CNUM(nct) produce lungimea câmpului de format iar CNUM(ncar-ip+1) produce lungimea câmpului rezervat zecimalelor;

Obs.33. Descriptorul de formate colectiv sir_frm este completat cu şirul descriptor de format individual şi virgula separatoare de formate;

Obs.34. O dată ce acţiunea de adăugare a unui descriptor de format individual a avut loc, s-a depăşit situaţia de citire a primului subşir numeric;

Obs.35. Se reiniţiază sir (un nou subşir numeric va fi prelucrat), i=0 şi ncar=0, din rand se eleimină spaţiul separator şi se recalculează ncarrand;

Obs.36. Dacă caracterul prim extras din rand nu este un spaţiu, deci este un caracter numeric, se incrementează numărul de caractere ncar al subşirului sir, se adaugă caracterul c la subşirul sir, se elimină primul caracter din rand şi se recalculează numărul ncarrand de caractere rămase în rand;

Page 304: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 292

Obs.37. Se calculează lungimea totală lsir a şirului descriptor colectiv de formate sir_frm, se adaugă paranteza de închidere a descriptorului colectiv de formate. Deoarece rand a suferit transformări se readuce la starea de la citirea din fişierul intermediar prin preluarea conţinutului de la şirul rezerva.

3. Verificarea rezultatului obţinut Folosind Notepad se deschide fişierul Num_div.tmp Dacă programul a funcţionat corect trebuie să vedeţi următorul conţinut:

11 -235.2346 1 1.23 253.45 3.456 -0.12 0.0 -5.021 0.12 1.0

Folosind Notepad se deschide fişierul Num_noi.txt Dacă programul a funcţionat corect trebuie să vedeţi următorul conţinut:

11. -235.2346 1. 1.23 253.45 3.456 -0.12 0.0 -5.021 0.12 1.0

§12.4. Aplicaţii interactive sub Windows în FORTRAN 12.4.1. Definirea temei Se va folosi mediul FORTRAN Salford PLATO. În acest mediu se află integrată o bibliotecă

de funcţii şi subrutine numită ClearWin+ destinată pentru a se crea aplicaţii rulabile sub Windows. Ca intenţie, ea este destinată să ajute programatorul lipsit de timp în a crea aplicaţii Windows mai uşor decât cu instrumentele Windows API oferite de MicroSoft. Deşi până la un punct ClearWin satisface bine această cerinţă, ca orice instrument destinat să lucreze în condiţii complexe şi această bibliotecă este relativ complexă şi studierea tehnicilor de lucru şi a resurselor oferite de ea cere un timp apreciabil. Din acest motiv prezentăm mai jos o aplicaţie dintre cele mai simple, cu scopul de a facilita un prim contact cu acest instrument.

Aplicaţia constă în desenarea unei diagrame a unei funcţii polinomiale pătratice de forma: y=ax2+bx+c pe baza unor parametri constând din: domeniul variabilei x şi coeficienţii a, b şi c ai

polinomului. Valorile acestor parametri vor putea fi modificate într-o cutie de dialog după care se va

comanda afişarea diagramei funcţiei. 12.4.2. Etape de lucru 1. În mediul Plato se scrie programul cu următoarea componenţă:

WINAPP PROGRAM GRAFIC INCLUDE <windows.ins> EXTERNAL afisare INTEGER N, i, col, x0, x1, pas, a, b, c REAL xin, xfin COMMON /PARAM/ N,x0,x1,a,b,c !Obs.1 pas=1 N=101 xin=0

Page 305: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 293

xfin=10 x0=int(xin) x1=int(xfin) a=1 b=1 c=1 col=RGB@(225,125,0) !Obs.2 i=winio@('%ca[Parametri]%bg&',col) !Obs.3 i=winio@('%mn[&Comenzi[I&esire]]&','EXIT') !Obs.4 i=winio@('%fn[COURIER NEW]&') !Obs.5 i=winio@('%nlx0=%dd%il%10rd&',pas,-32000,x1-1,x0) !Obs.6 i=winio@('%nl%nlx1=%dd%il%10rd&',pas,x0+1,32000,x1) !Obs.7 i=winio@('%nl%nl a=%dd%il%10rd&',pas,-32000,32000,a) !Obs.8 i=winio@('%nl%nl b=%dd%il%10rd&',pas,-32000,32000,b) !Obs.9 i=winio@('%nl%nl c=%dd%il%10rd&',pas,-32000,32000,c) !Obs.10 i=winio@('%nl%cn%^bt[&Afisare]',afisare) !Obs.11 END PROGRAM GRAFIC

INTEGER FUNCTION afisare() INCLUDE <windows.ins> INTEGER N, i, col, x0, x1, a, b, c DOUBLE PRECISION x(N),y(N) REAL xin, xfin,dx COMMON /PARAM/ N,x0,x1,a,b,c !Obs.12 xin=real(x0) !Obs.13 xfin=real(x1) dx=(xfin-xin)/(N-1) DO i=1,N x(i)=xin+dx*(i-1) y(i)=a*x(i)*x(i)+b*x(i)+c END DO col=RGB@(0,225,225) !Obs.14 i=winio@('%ca[Grafic polinom patratic]%bg&',col) !Obs.15 i=winio@('%pl[x_array]&',400,250,N,x,y) !Obs.16 i=winio@('%ff%nl%cn%bt[I&esire]') !Obs.17 afisare=1 END FUNCTION afisare

Semnificaţiile notaţiilor folosite în program sunt următoarele: În programul principal: N – număr de puncte cu care se va trasa diagrama funcţiei. A fost stabilit la 101 pentru a se putea

genera o curbă din 100 de segmente liniare, număr suficient pentru a asigura o calitate bună imaginii; i – variabilă întreagă în care se stochează răspunsul returnat de funcţie winio@. Acest

răspuns nu este necesar în această aplicaţie, dar sintaxa de apel a funcţiei trebuie respectată; col – variabilă întreagă în care se stochează răspunsul funcţiei de culoare RGB@; x0 – limita inferioară (întreagă) a domeniului de variaţie al variabilei x; x1 – limita superioară (întreagă) a domeniului de variaţie al variabilei x; a, b, c – coeficienţii polinomului (valori întregi); pas – pasul (întreg) de variaţie al valorilor x0, x1, a, b şi c; xin – limita inferioară (reală) a domeniului de variaţie al variabilei x; xfin – limita superioară (reală) a domeniului de variaţie al variabilei x; RGB@ – funcţia din biblioteca ClearWin+ care generează codul de culoare din

Page 306: Programarea Calculatoarelor si Limbaje de Programare

Cap.12. Aplicaţii în FORTRAN 294

componentele de culoare RED, GREEN, BLUE variind fiecare în intervalul 0...255; winio@ – funcţia din biblioteca ClearWin+ care controlează o mare parte dintre resursele

grafice Windows; În funcţia afisare: N, col, x0, x1, a, b, c, xin, xfin – aceleaşi semnificaţii ca în programul principal; i – indice de contorizare; x(N), y(N) – vectorii valorilor (reale) x şi y pentru fiecare punct al diagramei; dx – pasul (real) de generare a valorilor x(i); col – indice de culoere returnat de funcţia RGB@. RGB@ şi winio@ – aceleaşi semnificaţii ca în programul principal; Acţiunile efectuate de program sunt următoarele (vezi observaţiile marcate în textul sursă): În programul principal: Obs.1. Se declară blocul de de date comune PARAM; Obs.2. Se generează culoarea de fond col a cutiei de dialog pentru controlul parametrilor; Obs.3. Se generează o cutie de dialog. Codul de control %ca determină titlul Parametri iar

codul %bg determină fondul de culoare dat de variabila col; Obs.4. Se generează un meniu (codul de control %mn) cu numele Comenzi şi având

articolul Iesire care produce terminarea programului; Obs.5. Se declară că fontul (codul %fn) va fi Courier New. Acesta a fost ales deoarece

toate caracterele lui au aceeaşi lăţime şi se aliniază perfect pe verticală, uşurându-se astfel alinierea mai uşoară a componentelor diferite ale ferestrei;

Obs.6. Se operează un salt la linie nouă (codul %nl) şi se scrie textul x0=. Se ataşează un spiner (dispozitiv de incrementare/decrementare – codul %dd) ataşat unei cutii de editare cu lungimea de 10 caractere pentru numere întregi (codul 10rd%) şi căreia i s-au impus ca limite valorice inferioară şi superioară (codul %il) valorile –32000 şi x1-1. Spinerul poate produce variaţia lui x0 cu raţia pas;

Obs.7. Se lasă un rând gol (două salturi new line %nl%nl) se scrie textul x1= şi se crează o cutie de editare cu variator între limitele x0+1 şi 32000 pentru variabila x1;

Obs.8. Idem pentru a între limitele –32000 şi 32000; Obs.9. Idem pentru b între limitele –32000 şi 32000; Obs.10. Idem pentru c între limitele –32000 şi 32000; Obs.11. Se operează saltul la linei nouă, se comandă centrarea elementelor (codul %cn) şi

se crează un buton standard (codul %^bt) cu inscripţia Afisare. Prefixul ^ arată că apăsarea butonului produce apelul unei funcţii şi anume funcţia afisare.

În funcţia afisare: Obs.12. Se declară că funcţia vede variabilele din blocul de date comune PARAM; Obs.13. Se calculează xin, xfin, dx x(i) şi y(i); Obs.14. Se generează codul de culoare col; Obs.15. Se crează cutia de dialog cu titlul Grafic polinom patratic cu culoarea de fond col; Obs.16. Se generează o diagramă de tip x_array (cu variaţia după axa x) cu 400 pixeli

lungime şi 200 pixeli înălţime, cu N puncte având coordonatele conţinute în vectorii x şi y; Obs.17. Codul %ff (form feed) produce plasarea următorului element sub aria diagramei.

Codul %nl produce saltul la o linie nouă pentru a lăsa un rând liber. Se centrează (%cn) şi se generează un buton cu inscripţia Ieşire care, dat fiind că nu mai au loc şi alte acţiuni, la apăsare poduce închiderea ferestrei;

Page 307: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 295

Fig.12.4.1. Fig.12.4.2.

2. Testarea funcţionării aplicaţiei După etapele de compilare şi legare se lansează programul. Dacă s-a lucrat corect rularea lui decurge astfel: La lansare se deschide cutia de dialog Parametri din figura 12.4.1. Se pot ajusta valorile din câmpurile (cutiile) de editare manual sau folosind variatorul de

incrementare/decrementare. Câmpurile de editare trebuie să nu permită ieşirea din limitele de variaţie impuse prin program.

La apăsarea butonului Afişare se deschide fereastra Grafic polinom patratic din figura 12.4.2 care se închide cu butonul Iesire, revenindu-se în cutia de dialog Parametri.

Din cutia de dialog Parametri se iese (şi aplicaţia ia sfârşit) accesând meniul Comenzi şi apoi submeniul Iesire.

Page 308: Programarea Calculatoarelor si Limbaje de Programare

Cap.13. Aplicaţii în AutoLISP 296

Cap.13. Aplicaţii în AutoLISP Limbajul AutoLISP este implementat în AutoCAD cu scopul de a permite utilizatorului să

îşi creeze instrumente de lucru proprii. De aceea în continuare vom descrie câteva asemenea utilitare simple.

§13.1. Desenarea unor drapele folosind AutoLISP

13.1.1. Scrierea programului AutoLISP Programul constă în definirea unei funcţii care va fi recunoscută ca o comandă nouă. Începând de la AutoCAD 2000, mediul de lucru conţine un mediu de editare în care se

intră cu comanda de meniu Tools/AutoLISP/Visual Lisp Editor. Programul se va salva sub numele Drapele.Lsp şi componenţa lui este dată mai jos:

(defun c:drapel (/ oldfill ok) (command "ERASE" "ALL" "") ; Obs.1 (setq lstnat (list "ROM" "FRA" "ITA") ; Obs.2 rom (list "BLUE" "YELLOW" "RED") fra (list "BLUE" "WHITE" "RED") ita (list "GREEN" "WHITE" "RED") drapele (list rom fra ita) ) (command "LIMITS" '(0 0) '(8 5)) (command "ZOOM" "A") ; Obs.3 (command "COLOR" "WHITE") ; Obs.4 (setq sband (ssadd)) ; Obs.5 (command "SOLID" '(1 1) '(1 4) '(3 1) '(3 4)) (ssadd (entlast) sband) ; Obs.6 (command '(5 1) '(5 4)) (ssadd (entlast) sband) (command '(7 1) '(7 4) "") (ssadd (entlast) sband) (setq oldfill (getvar "FILLMODE") ok nil) ; Obs.7 (setvar "FILLMODE" 1) ; Obs.8 (while (not ok) ; Obs.9 (setq natiune (strcase (getstring "\nNatiunea ROMana/FRAnceza/ITAliana:"))) ; Obs.10 (if (setq ltrunc (member natiune (reverse lstnat))) (setq ok t)) ; Obs.11 ) (setq drapel (nth (1- (length ltrunc)) drapele) i 0) ; Obs.12 (while (< i 3) ; Obs.13 (command "CHANGE" (ssname sband i) "" "p" "c" (nth i drapel) "") (setq i (1+ i)) ) (setvar "FILLMODE" oldfill) ; Obs.14 (setq sband nil) ; Obs.15 (terpri) ; Obs.16 )

13.1.2. Explicaţii privind funcţionarea programului Entităţile folosite în program sunt următoarele: lstnat este o listă de şiruri de caractere reprezentând prescurtările denumirilor naţiunilor ale

căror drapele vor fi desenate; rom, fra şi ita sunt liste de şiruri de caractere recunoscute de AutoCAD ca denumiri de

culori standard; drapele este o listă ale cărei elemente sunt listele de culori pentru drapele; sband este un set de selecţie conţinând benzile (solidele) ale căror culori se modifică;

Page 309: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 297

oldfill este un atom care memorează starea variabilei de sistem FILLMODE; ok este un indicator de stare cu valoare iniţială nil care indică corectitudinea răspunsului

utilizatorului la cererea de specificare a numelui naţiunii; natiune este raspunsul operatorului la cererea de specificare a numelui naţiunii; Operaţiile efectuate de program sunt cele menţionate în observaţiile însoţitoare: Obs.1. Ştergerea tuturor entităţilor din desen; Obs.2. Se crează listele lstnat, rom, fra, ita şi drapele; Obs.3. Se declară limitele desenului şi încadrarea în fereastră a câmpului definit de aceste limite; Obs.4. Se declară culoarea curentă de desenare; Obs.5. Se iniţiază setul de selecţie nou sband; Obs.6. Se desenează benzile de culoare ale drapelelor, toate având culoarea albă; Obs.7. Se memorează vechea stare a variabilei de umplere FILLMODE şi se iniţiază ok la

valoarea nil; Obs.8. Se schimbă valoarea variabilei FILLMODE la 1 (afişarea umplerii este activată); Obs.9. Se rulează un ciclu de cerere din partea utilizatorului a specificării numelui naţiunii; Obs.10. Funcţia getstring preia de la utilizator răspunsul la cerere. Funcţia strcase

converteşte răspunsul în litere mari. Atomul natiune memorează răspunsul; Obs.11. Funcţia reverse inversează lista lstnat. Funcţia member returnează lista inversată

lstnat începând cu prima apariţie a unui element identic cu răspunsul natiune. Lista ltrunc memorează lista trunchiată. Dacă lista ltrunc nu este vidă ok ia valoarea t şi ciclul se încheie;

Obs.12. Funcţia (1- (length ltrunc)) produce indicele de ordine al lui natiune în lista lstnat. Ca urmare, funcţia nth extrage din lista drapele sublista cu culorile drapelului corespunzător şi o atribuie simbolului drapel;

Obs.13. Se rulează un ciclu de schimbare a culorilor benzilor de culoare; Obs.14. Se atribuie variabilei FILLMODE valoarea avută înainte de schimbare; Obs.15. Se anulează setul de selecţie sband; Obs.16. Se efectuează o ieşire ”tăcută”, funcţia terpri returnând valoarea nil are ca efect

evitarea scrierii în ultima linie de comandă a efectului ultimei evaluări. 13.1.3. Încărcarea şi utilizarea programului Pentru a se folosi programul acesta trebuie mai întâi încărcat. Încărcarea se face cu

comanda de meniu Tools/Load Application. După încărcare, în linia de comandă AutoCAD se poartă următorul dialog: Command: drapel Command: Natiunea ROMana/FRAnceza/ITAliana: fra După aceasta drapelul francez este desenat. §13.2. Calculul aproximativ al soluţiilor unei ecuaţii

13.2.1. Scrierea programului AutoLISP Şi aici vom genera o funcţie de comandă. În acest caz se cere găsirea soluţiilor ecuaţiei: y=sin x – e-x cos x = 0 Se cunoaşte faptul că această ecuaţie are o infinitate de soluţii şi că rezolvarea ei analitică

nu este posibilă. De aceea, ştiind că o putem rescrie sub forma: sin x = e-x cos x vom face uz de procedee grafice de determinare a punctelor de intersecţie a graficelor

funcţiilor: f(x)=sin x şi g(x)=e-x cos x

Page 310: Programarea Calculatoarelor si Limbaje de Programare

Cap.13. Aplicaţii în AutoLISP 298

Programul AutoLISP necesar este următorul: (defun fx (x /) (sin x)) ; Obs.1 (defun gx (x /) (* (exp (* -1 x))(cos x))) ; Obs.2 (defun det_solutii (ns / pa1 pa2 pb1 pb2 pint oldcol lsol) ; Obs.3 (setq oldcol (getvar "COLOR" )) (command "COLOR" "RED") ; Obs.4 (setq lsol nil x1 0 dx 0.1 x2 dx) ; Obs.5 (while (< (length lsol) ns) ; Obs.6 (setq pa1 (list x1 (fx x1)) pa2 (list x2 (fx x2)) ; Obs.7 pb1 (list x1 (gx x1)) pb2 (list x2 (gx x2)) x1 (+ x1 dx) x2 (+ x2 dx) ) (command "LINE" pa1 pa2 "") (command "LINE" pb1 pb2 "") ; Obs.8 (if (setq pint (inters pa1 pa2 pb1 pb2)) ; Obs.9 (setq lsol (adent (car pint) lsol)) ; Obs.10 ) ) lsol ; Obs.11 ) (defun adent (nou lst /) (reverse (append (list nou) (reverse lst)))) ; Obs.12 (defun c:solutii (/ nsol lsol i) ; Obs.13 (command "ERASE" "ALL" "") ; Obs.14 (initget 7) ; Obs.15 (setq nsol (getint "\nCate solutii doriti:")) ; Obs.16 (setq lsol (det_solutii nsol) i 0) ; Obs.17 (write-line "\n") ; Obs.18 (while (< i (length lsol)) ; Obs.19 (write-line (strcat "Solutia " (itoa (1+ i)) "=" (rtos (nth i lsol) 2 4 ))) (setq i (1+ i)) ) (terpri) )

13.2.2. Explicaţii privind funcţionarea programului Principiul de funcţionare al programului este simplu: considerând două valori ale variabilei

x, şi anume x1 şi x2, se calculează valorile funcţiilor f(x) şi g(x) în aceste puncte şi se generează câte un segment de dreaptă ca aproximare geometrică pentru fiecare dintre cele două funcţii. Punctele pa1 şi pa2 delimitează segmentul de aproximare a funcţiei f(x) iar punctele pb1 şi pb2 pe cel al funcţiei g(x). Funcţia AutoLISP inters returnează punctul de intersecţie al celor două segmente sau nil dacă segmentele nu se intersectează.

Derularea programului are loc conform observaţiilor însoţitoare, comentate mai jos. Obs.1. Definirea funcţiei f(x)=sin x; Obs.2. Definirea funcţiei g(x)=e-x cos x; Obs.3. Definirea funcţiei de determinare a soluţiilor. Parametrul primit de funcţie este

numărul de soluţii cerut ns; Obs.4. Salvarea stării variabilei de sistem COLOR (culoarea curentă de desenare) şi

schimbarea valorii ei pe RED; Obs.5. Iniţializare: lista de soluţii este vidă, x1=0, dx=0.1 şi x2=dx; Obs.6. Se rulează un ciclu de determinare a soluţiilor. Dacă se va încerca determinarea

soluţiilor cu unei ecuaţii cu număr de soluţii finit şi ns cerut va fi mai mare decât numărul maxim de soluţii pe intervalul x=0 ... x=infinit, programul va intra în buclă infinită;

Obs.7. Se crează listele de coordonate pentru punctele pa1, pa2, pb1 şi pb2, se

Page 311: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 299

incrementează x1 şi x2 cu dx; Obs.8. Se trasează segmentele funcţiilor; Obs.9, 10. Se determină punctul de intersecţie al segmentelor cu funcţia inters şi dacă

aceasta a detectat un asemenea punct, valoarea coordonatei x a punctului este stocată (adăugată) în coada listei de soluţii lsol folosind funcţia adent;

Obs.11. Se forţează evaluarea simbolului lsol pentru ca funcţia det_solutii să returneze ca rezultat lista soluţiilor (aceasta fiind ultima evaluare din corpul funcţiei);

Obs.12. Se crează o funcţie de adăugare a unui nou element la coada unei liste; Obs.13. Se generează funcţia de comandă a calculului interactiv al soluţiilor; Obs.14. Se şterge tot desenul; Obs.15. Se limitează posibilităţile de răspuns la următoarea funcţie de tip get la

interzicerea răspunsului vid (apăsarea numai a tastei Enter), interzicerea valorii zero şi interzicerea răspunsului printr-o valoare negativă;

Obs.16. Cerere de răspuns printr-o valoare întreagă (se cere numărul de soluţii de determinat; Obs.17. Se apelează funcţia det_solutii şi i se memorează rezultatul prin asociere cu

simbolul lsol, apoi se iniţializează indicele de contor i la zero; Obs.18. Se face o tipărire vidă (rând gol); Obs.19. Se rulează un ciclu de tipărire a soluţiilor;

Fig.13.2.1. 13.2.3. Exploatarea programului Pentru a putea fi folosit programul trebuie mai întâi salvat cu numele solec.lsp. Se încarcă programul folosind comanda Tools/Load Application. În linia de comandă AutoCAD ar putea avea loc următorul dialog: Command: solutii Command: Cate solutii doriti: 4 Command: Solutia 1=0.5321 Solutia 2=3.183 Solutia 3=6.285 Solutia 4=9.4249 nil Soluţiile sunt cele tipărite de program (ca mai sus) iar desenul realizat de program este cel

din figura 13.2.1. §13.3. Desenul secţiunii printr-un arbore cu canal de pană

13.3.1. Scrierea programului AutoLISP Se va genera o funcţie de comandă care va permite desenarea secţiunii prin arbore pe baza

unor parametri ceruţi de la utilizator, între parametrii ceruţi aflându-se şi poziţia în care va fi plasată secţiunea în câmpul desenului. Programul AutoLISP este cel de mai jos:

Page 312: Programarea Calculatoarelor si Limbaje de Programare

Cap.13. Aplicaţii în AutoLISP 300

(defun c:sectarb () (desensect (defarb) (pozsect))) ; Obs.1 (defun defarb () ; Obs.2 (initget 7) (list (getreal "\nDiametrul arborelui:") (getreal "\nLatimea penei:") (getreal "\nInaltimea penei:") ) ) (defun pozsect () ; Obs.3 (initget 1) (getpoint "\nIndicati centrul sectiunii:") ) (defun desensect (lp cn / p1 p2 p3 p4 p5 p6 p7 p8 rp hp bp tp xc yc) ; Obs.4 (setq rp (/ (nth 0 lp) 2) bp (nth 1 lp) hp (nth 2 lp) ; Obs.5 tp (/ hp 2) xc (car cn) yc (cadr cn) ; Obs.6 p7 (list xc (+ yc rp)) p8 (list xc (- yc rp)) ; Obs.7 p1 (list xc (+ yc rp (- hp tp))) p2 (list (- xc (/ bp 2)) (cadr p1)) p3 (list (car p2) (- (cadr p1) hp)) p4 (list xc (cadr p3)) p5 (list (+ xc (/ bp 2)) (cadr p3)) p6 (list (car p5) (cadr p2)) ) (command "CIRCLE" cn rp) ; Obs.8 (command "PLINE" p1 p2 p3 p5 p6 "C") ; Obs.9 (command "TRIM" p7 "" p2 p6 "") ; Obs.10 (command "TRIM" p4 "" p7 "") ; Obs.11 (command "HATCH" "LINE" "" 45 p8 p4 "") ; Obs.12 )

13.3.2. Explicaţii privind funcţionarea programului

Fig.13.3.1. Fig.13.3.2.

Programul funcţionează conform observaţiilor însoţitoare comentate mai jos: Obs.1. Se defineşte funcţia de comandă. Aceasta apelează funcţia de desenare a secţiunii

prin arbore care primeşte ca argumente rezultatele returnate de funcţia de definire a parametrilor dimensionali ai secţiunii prin arbore şi pe cea de precizare a poziţiei de amplasare;

Page 313: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 301

Obs.2. Se definesc parametrii dimensionali generali: diametrul arborelui, lăţimea şi înălţimea penei prin funcţii de cerere de valori reale getreal care, conform funcţiei initget nu acceptă răspuns vid (Enter), valoare zero sau negativă;

Obs.3. Se defineşte poziţia de amplasare a centrului secţiunii. Funcţia getpoint returnează ca rezultat punctul indicat de utilizator, conform funcţiei initget nefiind acceptat un răspuns vid;

Obs.4. Funcţia de desenare a secţiunii primeşte ca parametri lista de parametri dimensionali lp care va fi returnată de funcţia defarb şi lista cn a coordonatelor centrului arborelui care va fi returnată de funcţia pozsect;

Obs.5. Se defineşte raza arborelui rp=d/2, lăţimea penei bp şi înălţimea penei hp, prin extragere din lista de parametri dimensionali lp;

Obs.6. Se defineşte adâncimea canalului de pană tp=hp/2, iar xc şi yc, coordonatele centrului arborelui sunt extrase din lista cn;

Obs.7. Se definesc punctele p1...p6 (vezi figura 11.3.1); Obs.8. Se desenează cercul de rază rp cu centrul în punctul cn; Obs.9. Se desenează conturul penei; Obs.10. Se decupează partea din conturul penei care depăşeşte conturul cercului; Obs.11. Se decupează partea din conturul cercului cuprinsă în interiorul conturului penei; Obs.12. Se haşurează interiorul secţiunii. 13.3.3. Utilizarea programului Salvarea programului se va face sub numele sectarb.Lsp. După încărcarea în AutoCAD, în linia de comandă a acestuia s-ar putea desfăşura dialogul următor: Command: sectarb Diametrul arborelui: 40 Latimea penei: 15 Inaltimea penei: 10 Indicati centrul sectiunii: se aplică un punct în câmpul de lucru Ca rezultat va fi desenată secţiunea din figura 13.3.2. §13.4. Generarea unui fişier de date

13.4.1. Scrierea programului AutoLISP Se va genera o funcţie de comandă care va permite scrierea pe disc a unui fişier de date

conţinând coordonatele graficului funcţiei y=e-x sin x. Programul AutoLISP necesar este dat mai jos:

(defun y (x /) (* (exp (* -1 x)) (sin x))) ; Obs.1 (defun scriexy (x fis /) ; Obs. 2 (write-line (strcat "X=" (rtos x 1 6) " Y=" (rtos (y x) 1 6)) fis) ) (defun c:scriefis (/ np dx ip x df) ; Obs.3 (setq np 100 dx (/ (* 2 pi) (1- np)) ip 0 x 0) ; Obs.4 (setq df (open "c:\\temp\\SINAMO.DAT" "W")) ; Obs.5 (while (< ip np) ; Obs.6 (scriexy x df) (setq x (+ x dx) ip (1+ ip)) ) (close df) ; Obs.7 )

13.4.2. Explicaţii privind funcţionarea programului Conform observaţiilor însoţitoare programul funcţionează în modul următor:

Page 314: Programarea Calculatoarelor si Limbaje de Programare

Cap.13. Aplicaţii în AutoLISP 302

Obs.1. Funcţie de calcul a valorii funcţiei y; Obs.2. Funcţie de scriere a unui rând în fişier. Funcţiile rtos convertesc o valoare reală în

şir de caractere. Parametrul 1 determină scrierea în format ştiinţific (cu exponent zecimal) iar parametrul 6 reprezintă precizia de scriere (cu 6 zecimale). Funcţia strcat concatenează şiruri de caractere iar funcţia write-line execută scrierea în fişierul care are ca descriptor de fişier parametrul fis;

Obs.3. Funcţie comandă de scriere a fişierului; Obs.4. Se definesc: np numărul de puncte de scris în fişier (100), dx pasul de calcul, ip

contorul de ciclu, x=0 valoarea de start; Obs.5. Se deschide pentru scriere fişierul SINAMO.DAT. Funcţia open returnează ca

rezultat o dată de tip special numită descriptor de fişier; Obs.6. Se rulează un ciclu de scriere în fişier afiecărui rând de date; Obs.7. Se închide fişierul. 13.4.3. Utilizarea programului După salvarea programului într-un fişier cu numele Wrsin.Lsp, se încarcă în AutoCAD cu

comanda Tools/Load Application şi se scrie comanda scriefis. Fişierul SINAMO.DAT va avea structura următoare: X=0.000000E+00 Y=0.000000E+00 X=6.346652E-02 Y=5.952370E-02 X=1.269330E-01 Y=1.115017E-01 ... X=6.219719E+00 Y=-1.262012E-04 X=6.283185E+00 Y=-3.774621E-18 §13.5. Desenarea unei diagrame cu date citite din fişier 13.5.1. Scrierea programului AutoLISP Se va genera o funcţie de comandă care va permite citirea datelor dintr-un fişier şi

reprezentarea lor sub formă de diagramă. Programul AutoLISP necesar este dat mai jos:

(defun citeste_punct (fis / rnd) ; Obs.1 (if (setq rnd (read-line fis)) ; Obs.2 (extpct rnd) ; Obs.3 ) ) (defun extpct (rnd / drnd) ; Obs.4 (setq drnd rnd cauta t contor 0) ; Obs.5 (while cauta ; Obs.6 (setq contor (1+ contor)) ; Obs.7 (if (equal (substr drnd 1 3) " Y=") ; Obs.8 (setq cauta nil) (setq drnd (substr drnd 2)) ) ) (list (atof (substr rnd 3 (- contor 2))) ; Obs.9 (atof (substr rnd (+ contor 3))) ) ) (defun c:diagrama (/ df pt) ; Obs.10 (setq df (open "c:\\temp\\SINAMO.DAT" "R")) ; Obs.11 (command "PLINE") ; Obs.12

Page 315: Programarea Calculatoarelor si Limbaje de Programare

Programarea calculatoarelor şi limbaje de programare 303

(while (setq pt (citeste_punct df)) (command pt)) ; Obs.13 (command "") ; Obs.14 )

13.5.2. Explicaţii privind funcţionarea programului Conform observaţiilor însoţitoare programul funcţionează în modul următor: Obs.1. Funcţie de citire a unui punct din fişier. Parametrul de intrare în funcţie este un

descriptor de fişier; Obs.2. Este citită o linie (rând) din fişier; Obs.3. Funcţia extpct extrage lista punctului din rândul citit; Obs.4. Funcţie de extragere a unui punct (creare de listă de punct) dintr-un rând de text citit

din fişierul de date; Obs.5. Se crează o copie (dublură) a rândului de date citit. Dublura are numele drnd şi pe

ea se vor opera o serie de prelucrări ulterioare. Se iniţializează variabila logică cauta la valoarea t şi contorul de explorare a rândului la valoarea 0;

Obs.6. Se rulează un ciclu de prelucrare a rândului; Obs.7. Se avansează contorul de caracter cu o unitate; Obs.8. Dacă rezultatul extragerii primelor trei caractere ale rândului este şirul " Y=" atunci

căutarea a luat sfârşit şi simbolul cauta devine nil. Altfel, din şirul drnd este eliminat primul caracter şi se va continua căutarea. Valoarea simbolului contor va fi indicele din şir a caracterului spaţiu care separă textele descriptoare ale coordonatelor X şi Y;

Obs.9. Se crează lista de punct extrăgându-se din şirul rnd numai părţile cu semnificaţie numerică şi, cu ajutorul funcţiei atof, convertindu-le în valori numerice reale. Funcţia extpct va returna ca rezultat lista de punct deoarece ea este ultima evaluare din corpul funcţiei;

Obs.10. Funcţie de desenare a diagramei; Obs.11. Se deschide fişierul de date; Obs.12. Se iniţiază comanda Polyline; Obs.13. Se rulează un ciclu de citire din fişier a datelor şi conversie a lor în liste de puncte

care sunt furnizate ca date comenzii de trasare a polininiei aflată în derulare; Obs.14. Se încheie comanda Polyline. 13.5.3. Utilizarea programului După salvarea programului într-un fişier cu numele Rdfunc.Lsp, se încarcă în AutoCAD cu

comanda Tools/Load Application şi se scrie comanda diagrama. Rezultatul obţinut va fi cel din figura 13.5.1.

Fig.13.5.1.

Page 316: Programarea Calculatoarelor si Limbaje de Programare

Bibliografie 304

Bibliografie

[1]. Cris H. Pappas & William H. Murray, III, "Borland C++ Handbook, Second Edition, Osborne Mc Graw-Hill, Berkeley, California, USA, 1992.

[2]. Dan Manolea, Programare în AutoLISP sub AutoCAD, Grupul MicroINFORMATICA, Cluj-Napoca, 1996.

[3]. Dan Roman, Ingineria programării obiectuale, Grupul MicroINFORMATICA, Cluj-Napoca, 1996.

[4]. Dumitru Dragomir, Îndrumar de lucrări practice pentru proiectare asistată de calculator, Editura Evrika, Brăila, 1999.

[5]. Dumitru Dragomir, Ovidiu Ionaş, Leonard Domnişoru, Ionel Gavrilescu, Lucrări de tehnici de calcul numeric în ingineria asistată de calculator, Editura Evrika, Brăila, 1999.

[6]. Dumitru Dragomir, Proiectare asistată de calculator pentru inginerie mecanică, Editura Teora, Bucureşti, 1996.

[7]. Gheorghe Curelet-Bălan, "Visual BASIC, introducere în programarea uzuaĺă a aplicaţiilor Windows", Editura DONE, Bucureşti, 1994.

[8]. Ioan Salomie, Tehnici orientate pe obiecte, Grupul MicroINFORMATICA, Cluj-Napoca, 1995.

[9]. Michael Metcalf, John Reid, Fortran 90/95 Explained, Second Edition, Oxford University Press Inc., New York, 1999.

[10]. Mihai Anton Cerghizan, "EXCEL 7.0 pentru Windows 95", Editura TEHNICĂ, Bucureşti, 1996.

[11]. Namir C. Shammas, "Curs rapid de Borland C++", Teora, Bucureşti, 1996. [12]. Octavian Catrina, Iuliana Cojocaru, Turbo C++, Editura Teora, Bucureşti, 1993. [13]. Ovidiu Ionaş, Leonard Domnişoru, Ionel Gavrilescu, Dumitru Dragomir, Tehnici de

calcul în construcţii navale, Editura Evrika, Brăila, 1999. [14]. Teodor Tiuca, Tudor Precup, Tiberiu Antal, Dezvoltarea Aplicaţiilor cu AutoCAD şi

AutoLISP, Editura ProMedia Plus, Cluj Napoca, 1995. [15]. Tom Swan, "Învăţăm C... pas cu pas", Editura Tehnică, Bucureşti, 1996. [16]. Valentin C., Cristian G., Eugenia K., Alexandru P., "Limbajul C Standard", Teora,

Bucureşti, 1992. [17]. Vasile Petrovici, Florin Goicea, Programarea în Limbajul C, Editura Tehnică,

Bucureşti, 1993.