You are on page 1of 267

PROGRAMAREA CALCULATOARELOR I LIMBAJE DE PROGRAMARE

Introducere
n epoca actual, caracterizat printr-o formidabil explozie informaional nsoit de o evoluie tehnologic pe msur, nu se mai poate concepe progresul n oricare din domeniile activitii umane, fr utilizarea calculatoarelor. Cea mai nou i cea mai important revoluie din punct de vedere al progresului omenirii este revoluia informaional. Tehnologia informaional a fost recunoscut ca principal factor pentru creterea economic i mbuntirea calitii vieii n general. Informaia o putem considera o noiune primar, o definiie fiind greu de dat. I se pot da mai multe semnificaii (uneori total diferite sau chiar contradictorii), ce sunt determinate de domeniile i contextele variate n care cuvntul este folosit. Se poate spune c informaia se constituie ntr-o reprezentare a realitii prin intermediul unui set bine precizat i structurat de simboluri - de regul accesibile simurilor i raiunii umane, dar i unora dintre dispozitive, precum cele de calcul automat (sisteme de calcul, numite pe scurt calculatoare). Informaia prelucrat de calculator, reprezentat prin date, este foarte divers, informaie numeric, text, imagine, informaie audio, semnale, etc. Calculatorul, reprezint un ansamblu de dispozitive i circuite diverse care prelucreaz datele introduse ntr-o form prestabilit, efectueaz diverse operaii asupra acestora i furnizeaz rezultatele obinute. Datele sunt prelucrate printr-o succesiune de aciuni (instruciuni), numit program. Scrierea unui program se realizeaz folosind limbaje de programare specifice. Cursul de fa urmrete familiarizarea cu un limbaj de programare. S-a optat pentru nvarea limbajelor C/C++, limbaje foarte populare, programele scrise folosind aceste limbaje acoperind o foarte mare diversitate de aplicaii. Avantajele oferite de limbajul C sunt: este un limbaj de nivel mediu, portabil, structurat, flexibil; produce programe eficiente ( lungimea codului sczut, viteza de execuie mare) de dimensiune relativ sczut; ofer un set bogat de operatori; ofer multiple faciliti de reprezentare si prelucrare a datelor; permite utilizare extensiv a apelurilor de funcii i a pointerilor; permite programarea la nivel sczut (low-level), apropiat de hardware. Obiectivele cursului Cursul Programarea calculatoarelor i limbaje de programare I urmrete pe de o parte familiarizarea cu un limbaj de programare, dar n acelai timp se dorete i formarea gndirii n spiritul scrierii unor programe ct mai bine structurate, astfel nct s se asigure claritate n transpunerea problemei n program, dar i depanare i ntreinere a programelor facile. Se are n vedere nu doar corectitudinea aplicaiilor, ci i creterea eficienei activitii de programare. Disciplina ofer studenilor noiuni de baz n domeniul programrii 3

calculatoarelor n limbaje structurate, procedurale. Tehnica programrii structurate se bazeaz pe principiul divide et impera, adaptat ca formulare n structureaz pentru a stpni o aplicaie. Trstura caracteristic a limbajelor structurate este compartimentarea datelor i a codului. Datele sunt structurate n elemente de diferite tipuri, programatorul putnd s defineasc propriile structuri de date, ceea ce permite o reprezentare adecvat a datelor prelucrate. Programele sunt alctuite din proceduri (funcii) care opereaz asupra structurilor de date. Activitile efectuate de proceduri sunt bine definite i sunt separate de exterior, comunicnd cu acesta prin seturi de parametri i eventual un rezultat returnat. Variabilele locale funciilor sunt invizibile altor funcii. Parcurgerea acestui curs: ofer noiuni de baz n domeniul programrii calculatoarelor n limbaje structurate, procedurale (tipuri de date, operatori, instruciuni). asigur studenilor cunotine de baz n construirea i exploatarea structurilor de date. urmrete ca, pe lng cunoaterea unui limbaj de programare, s se cunoasc modaliti de transpunere a unor probleme din domenii ct mai diverse n programe, realiznd implementarea unor algoritmi simpli. Noiunile referitoare la structuri de date, algoritmi i tehnici de programare vor fi dezvoltate de alte cursuri prevzute n planul de nvmnt al specializrii. Actualul curs face referire doar la aspectele care in de programarea procedural, aspecte referitoare la programarea obiectual urmnd a fi tratate ntr-un alt curs. Competene conferite Dup parcurgerea materialului, studentul va fi capabil: s descrie modul de reprezentare a datelor numerice sau alfanumerice n sistemele de calcul; s descrie algoritmul de rezolvare a unei probleme; s utilizeze a unui mediu de programare specific prin care s scrie programe surs, s-l depaneze i testeze i s genereze fiierul executabil aferent; s foloseasc funciile de intrare/ieire pentru consol i fiiere; s scrie expresii complexe i s utilizeze instruciunile specifice limbajului; s opereze cu masive de date (tablouri uni i multi-dimensionale, iruri de caractere); s defineasc i s utilizeze funcii; s defineasc propriile tipuri de date i s opereze corect cu acestea.

Cerine preliminare Pornindu-se de la premisa c, parte dintre studeni nu au deprinderi de utilizare a limbajelor de programare, cursul a fost structurat astfel nct pentru parcurgerea sa nu sunt necesare cunotine n domeniu. Pentru construirea aplicaiilor de exemplificare a aspectelor tratate se folosesc cunotine de matematic i fizic acumulate de orice absolvent al unui liceu de profil real. Discipline deservite Obiectivele de formare specifice specializrii Managementul Energiei au n vedere formarea unor competene aplicativ-practice care s permit realizarea de sisteme de achiziii i prelucrare de date n condiii industriale specifice, aplicarea metodelor computerizate n controlul msurtorilor industriale, etc., care presupun folosirea ca suport att pentru stocarea ct i pentru prelucrarea datelor, computerul. Disciplina Programarea calculatoarelor i limbaje de programare I ofer cunotine de baz n folosirea calculatoarelor, cunotine care vor fi utilizate i dezvoltate n discipline prevzute n planul de nvmnt, cum ar fi: Programarea calculatoarelor i limbaje de programare II, Grafic asistat de calculator, Metode numerice, Medii integrate de programare, Arhitectura calculatoarelor, Sisteme de achiziii de date, Informatic n energetic. Resurse i mijloace de lucru Parcurgerea unitilor de nvare necesit utilizarea unui calculator i a unui mediu de programare cum ar fi: Borland C++ v.3.1, Microsoft Visual C++ 6.0 sau Eclipse. Se vor utiliza tutoriale i programele surs puse la dispoziie la laborator sau accesate pe Internet.

Structura cursului Cursul de Programarea Calculatoarelor i Limbaje de Programare I este structurat n paisprezece uniti de nvare, primele treisprezece cuprinznd: obiective, aspecte teoretice privind tematica unitii de nvare respective, exemple, teste de autoevaluare precum i probleme propuse spre discuie i rezolvare, iar cea de a paisprezecea conine doar exemple prin care dorete fixarea noiunilor i descriere unor tehnici de programare.

Durata medie de studiu individual Parcurgerea de ctre studeni a unitilor de nvare ale cursului de Programarea Calculatoarelor i Limbaje de Programare I (att aspectele teoretice ct i rezolvarea problemelor propuse) se poate face n 2-3 ore de studiu individual pentru fiecare unitate.

Evaluarea La sfritul semestrului, fiecare student va primi o not, care va cuprinde: un test gril, ce va conine ntrebri referitoare la elementele de baz ale limbajului i la secvene de programe, test ce va deine o pondere de 20% n nota final, realizarea unei aplicaii pe calculator care va deine o pondere de 40% n nota final i media notelor testelor i temelor realizate pe parcursul semestrului, care va deine o pondere de 20%.

Cuprins

Introducere.................................................................................................................................. 3 Cuprins ....................................................................................................................................... 7 Unitatea de nvare U1. Reprezentarea informaiei n sistemele de calcul ............................. 12 Introducere .................................................................................................................... 12 Obiectivele unitii de nvare ..................................................................................... 13 U1.1. Sisteme de numeraie .......................................................................................... 13 U1.2. Conversii ntre baze de numeraie ....................................................................... 15 U1.3. Operaii aritmetice n binar ................................................................................. 16 U1.4. Operaii logice la nivel de bit. ............................................................................. 17 U1.5. Reprezentarea numerelor ntregi cu semn . ......................................................... 19 U1.6. Reprezentarea numerelor reale. ........................................................................... 20 U1.7. Coduri alfanumerice. ........................................................................................... 23 U1.8. Cantitatea de informaie. ..................................................................................... 25 Rezumat ........................................................................................................................ 26 ntrebri, exerciii i probleme ...................................................................................... 27 Unitatea de nvare U2. Structura general a sistemelor de calcul ......................................... 28 Introducere .................................................................................................................... 28 Obiectivele unitii de nvare ..................................................................................... 28 U2.1. Generaliti despre structura hardware a unui calculator .................................... 29 U2.2. Generaliti despre structura software a unui calculator ..................................... 32 U2.3. Sistemul de operare ............................................................................................. 35 Rezumat ........................................................................................................................ 39 ntrebri, exerciii i probleme ...................................................................................... 39 Unitatea de nvare U3. Noiuni introductive pentru limbajele de programare C/C++ .......... 40 Introducere .................................................................................................................... 40 Obiectivele unitii de nvare ..................................................................................... 41 U3.1. Etapele parcurse pentru obinerea unui program executabil ............................... 41 U3.2. Elementele de baz ale limbajelor C/C++........................................................... 41 U3.2.1. Identificatori ......................................................................................... 42 U3.2.2. Semne de punctuaie i caractere speciale ............................................ 44 U3.2.3. Spaii albe ............................................................................................. 44 U3.3. Structura programului C/C++ ............................................................................. 44 U3.4. Directive de preprocesare.................................................................................... 47 U3.5. Primul program C/C++ ....................................................................................... 48

U3.6. Utilizarea comentariilor ...................................................................................... 49 U3.7. Tipuri de date fundamentale ............................................................................... 50 Exemple ........................................................................................................................ 53 Rezumat ........................................................................................................................ 55 Test de autoevaluare ..................................................................................................... 56 ntrebri, exerciii i probleme ...................................................................................... 57 Unitatea de nvare U4. Constante. Variabile. ........................................................................ 58 Introducere .................................................................................................................... 58 Obiectivele unitii de nvare ..................................................................................... 58 U4.1. Constante ............................................................................................................. 59 U4.1.1. Constante ntregi ................................................................................... 59 U4.1.2. Constante n virgul mobil .................................................................. 60 U4.1.3. Constante caracter ................................................................................. 61 U4.1.4. Constante ir de caractere ..................................................................... 62 U4.2. Variabile .............................................................................................................. 63 U4.2.1. Declaraii de variabile ........................................................................... 63 U4.2.2. Atributele variabilelor........................................................................... 65 U4.2.3. Modificatori de acces ............................................................................ 69 Exemple ........................................................................................................................ 69 Rezumat ........................................................................................................................ 73 Test de autoevaluare ..................................................................................................... 74 ntrebri, exerciii i probleme ...................................................................................... 76 Unitatea de nvare U5.Operaii de intrare/ieire pentru consol ........................................... 77 Introducere .................................................................................................................... 77 Obiectivele unitii de nvare ..................................................................................... 79 U5.1. Operaii I/O la nivel de caracter .......................................................................... 79 U5.2. Funcii pentru operaii I/O pentru iruri de caractere .......................................... 80 U5.3. Operaii de citire/scriere cu formatare ................................................................ 82 Exemple ........................................................................................................................ 89 Rezumat ........................................................................................................................ 93 Test de autoevaluare ..................................................................................................... 94 ntrebri, exerciii i probleme ...................................................................................... 98 Unitatea de nvare U6.Operatori i expresii .......................................................................... 99 Introducere .................................................................................................................... 99 Obiectivele unitii de nvare ..................................................................................... 99 U6.1. Operatori .......................................................................................................... 100 U6.2. Ordinea de evaluare a expresiilor...................................................................... 111

U6.3. Conversii de tip n expresii ............................................................................... 113 Exemple ...................................................................................................................... 114 Rezumat ...................................................................................................................... 116 Test de autoevaluare ................................................................................................... 117 ntrebri, exerciii i probleme .................................................................................... 119 Unitatea de nvare U7. Instruciuni (1) ................................................................................ 121 Introducere .................................................................................................................. 121 Obiectivele unitii de nvare ................................................................................... 122 U7.1. Algoritmi ........................................................................................................... 122 U7.1.1. Generaliti ......................................................................................... 122 U7.1.2. Reprezentarea algoritmilor ................................................................. 123 U7.2. Instruciunea expresie ....................................................................................... 127 U7.3. Instruciunea compus (blocul de instruciuni) ................................................. 128 U7.4. Instruciuni de selecie (decizie) ....................................................................... 130 U7.4.1. Instruciunea de decizie if, if-else ....................................................... 130 U7.4.2. Instruciunea de selecie multipl switch ............................................ 132 Exemple ...................................................................................................................... 135 Rezumat ...................................................................................................................... 137 Test de autoevaluare ................................................................................................... 138 ntrebri, exerciii i probleme .................................................................................... 139 Unitatea de nvare U8. Instruciuni (2) ................................................................................ 140 Introducere .................................................................................................................. 140 Obiectivele unitii de nvare ................................................................................... 140 U8.1. Instruciuni de ciclare (repetitive) ..................................................................... 141 U8.1.1. Instruciunea de ciclare cu test iniial (while) ..................................... 141 U8.1.2. Instruciunea de ciclare cu test final (do-while) ................................. 143 U8.1.3. Instruciunea de ciclare cu contor (for) ............................................... 145 U8.2. Instruciuni de salt ............................................................................................. 147 U8.2.1. Instruciunea break.............................................................................. 147 U8.2.2. Instruciunea continue......................................................................... 149 U8.2.3. Instruciunea return ............................................................................. 150 U8.2.4. Funcia exit()....................................................................................... 151 U8.2.5. Instruciunea de salt necondiionat goto ............................................. 153 Exemple ...................................................................................................................... 154 Rezumat ...................................................................................................................... 156 Test de autoevaluare ................................................................................................... 157 ntrebri, exerciii i probleme .................................................................................... 159

Unitatea de nvare U9.Tablouri de date ..................................................................................... Introducere .................................................................................................................. 160 Obiectivele unitii de nvare ................................................................................... 160 U9.1. Declararea tablourilor de date ........................................................................... 161 U9.2. Tablouri unidimensionale ................................................................................. 164 U9.3. iruri de caractere ............................................................................................. 167 U9.4. Tablouri multidimensionale .............................................................................. 170 Exemple ...................................................................................................................... 172 Rezumat ...................................................................................................................... 177 Test de autoevaluare ................................................................................................... 178 ntrebri, exerciii i probleme .................................................................................... 181 Unitatea de nvare U10. Variabile pointeri. Variabile referine. ......................................... 182 Introducere .................................................................................................................. 182 Obiectivele unitii de nvare ................................................................................... 182 U10.1. Variabile pointeri ............................................................................................ 183 U10.1.1. Declararea variabilelor pointeri de date ............................................ 183 U10.1.2. Operaii de atribuire cu pointeri ........................................................ 184 U10.1.3. Referirea obiectelor prin variabile pointer ........................................ 185 U10.1.4. Pointeri generici ................................................................................ 186 U10.1.5. Operaii aritmetice cu pointeri .......................................................... 187 U10.1.6. Tablouri i pointeri ........................................................................... 188 U10.2. Variabile referin ........................................................................................... 191 Exemple ...................................................................................................................... 192 Rezumat ...................................................................................................................... 195 Test de autoevaluare ................................................................................................... 195 ntrebri, exerciii i probleme .................................................................................... 198 Unitatea de nvare U11. Alocare dinamic de memorie...................................................... 199 Introducere .................................................................................................................. 199 Obiectivele unitii de nvare ................................................................................... 200 U11.1. Alocare dinamic de memorie ........................................................................ 200 U11.2. Alocare dinamic de memorie folosind funcii specifice................................ 201 U11.3. Alocare dinamic de memorie folosind operatorii new i delete .................... 203 U11.4. Alocare dinamic de memorie pentru tablouri multidimensionale ................. 205 Exemple ...................................................................................................................... 207 Rezumat ...................................................................................................................... 211 Test de autoevaluare ................................................................................................... 212 ntrebri, exerciii i probleme .................................................................................... 215

10

Unitatea de nvare U12. Funcii C/C++............................................................................... 216 Introducere .................................................................................................................. 216 Obiectivele unitii de nvare ................................................................................... 217 U12.1. Definiii de funcii ........................................................................................... 217 U12.2. Declaraii de funcii. Prototipuri. .................................................................... 218 U12.3. Transferul parametrilor ................................................................................... 218 U12.3.1. Transferul prin valoare. Conversii de tip. ......................................... 218 U12.3.2. Transferul prin adres ....................................................................... 219 U12.3.3. Transferul prin variabile referin ..................................................... 220 U12.4. Rezultatul unei funcii. Instruciunea return. .................................................. 222 U12.5. Funcii recursive .............................................................................................. 222 U12.6. Pointeri de funcii ............................................................................................ 223 Exemple ...................................................................................................................... 224 Rezumat ...................................................................................................................... 228 Test de autoevaluare ................................................................................................... 229 ntrebri, exerciii i probleme .................................................................................... 232 Unitatea de nvare U13. Tipuri de date definite de utilizator .............................................. 233 Introducere .................................................................................................................. 233 Obiectivele unitii de nvare ................................................................................... 234 U13.1. Enumerarea .................................................................................................... 234 U13.2. Structuri de date .............................................................................................. 235 U13.3. Cmpuri de bii................................................................................................ 242 U13.4. Uniuni.............................................................................................................. 240 Exemple ...................................................................................................................... 244 Rezumat ...................................................................................................................... 248 Test de autoevaluare ................................................................................................... 249 ntrebri, exerciii i probleme .................................................................................... 252 Unitatea de nvare U14. Exemple ........................................................................................ 253 Introducere .................................................................................................................. 253 Obiectivele unitii de nvare ................................................................................... 253 Exemple ...................................................................................................................... 254 Rezolvarea testelor de autoevaluare ....................................................................................... 265 Bibliografie ............................................................................................................................. 267

11

Unitatea de nvare U1. REPREZENTAREA INFORMAIEI N SISTEMELE DE CALCUL

Cuprins Introducere .................................................................................................................... 12 Obiectivele unitii de nvare ..................................................................................... 13 U1.1. Sisteme de numeraie .......................................................................................... 13 U1.2. Conversii ntre baze de numeraie ....................................................................... 15 U1.3. Operaii aritmetice n binar ................................................................................. 16 U1.4. Operaii logice la nivel de bit. ............................................................................. 17 U1.5. Reprezentarea numerelor ntregi cu semn . ......................................................... 19 U1.6. Reprezentarea numerelor reale. ........................................................................... 20 U1.7. Coduri alfanumerice. ........................................................................................... 23 U1.8. Cantitatea de informaie. ..................................................................................... 25 Rezumat ........................................................................................................................ 26 ntrebri, exerciii i probleme ...................................................................................... 27

Introducere n calculatoarele digitale, informaia de orice fel este reprezentat, stocat i prelucrat n form numeric. Numerele se reprezint prin simboluri elementare denumite cifre. Un calculator poate fi prevzut s funcioneze n orice sistem de numeraie. n cazul reprezentrii numerelor utilizate n mod curent, adic cu reprezentate n baza 10, sunt necesare 10 simboluri distincte, cte unul pentru fiecare cifr. Fizic, aceast reprezentare este destul de dificil. Pe parcursul dezvoltrii tehnicii de calcul, s-a stabilit c cel mai avantajos este sistemul binar deoarece procesul prelucrrii sau al stocrii numerelor se face mai uor pentru dou simboluri. Sistemul de calcul trebuie s disting doar ntre dou valori: ntre un semnal de valoare joas (Low, en.) - ntre 0 i 2 voli i unul de valoare nalt (High, en.) aproximativ 5V. n acest caz, sistemului de operare va trebui s-i oferim spre operare reprezentrile binare ale numerelor zecimale folosite n mod curent. n notaiile binare sunt utilizate numai cifrele 0 i 1, spre deosebire de sistemul zecimal unde sunt folosite cifrele de la 0 la 9. Un numr binar este un ir de cifre binare cum sunt 1010 sau 100011. Deci, sistemul binar a fost preferat din urmtoarele motive:

12

simplitatea regulilor pentru operaiile aritmetice i logice; materializarea fizic relativ simpl a cifrelor. Este de subliniat aici, din nou, c sistemele de calcul nu opereaz de fapt cu numerele 0 i 1, ci cu dou stri asociate lor, respectiv semnalele Low i High, contact nchis-contact deschis, prezena sau absena de curent etc. Circuitele care trebuie s diferenieze numai dou stri sunt mai sigure n funcionare dect cele care trebuie s diferenieze 10 stri. Fizic sunt folosite elemente bistabile cu strile: conducie (+5V) blocat (0V) care sunt asociate cu valorile 0 i respectiv 1. Un astfel de element reprezint unitatea de memorie denumit bit (bit este un acronim al cuvintelor engleze binary digit - cifr binar). Evident, acest mod de reprezentare impune transformarea informaiilor de orice natur (texte, sunete, imagini, etc.) n secvene de cifre binare.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: cum se reprezint informaia n calculator; reprezentarea numerelor n diferite baze de numeraie; transformarea numerelor dintr-o baz de numeraie n alta; modul de reprezentare a valorilor numerice, ntregi sau reale i a informaiei alfanumerice. Definirea competenelor specifice unitii de nvare curente, utiliznd verbe cuantificabile similare cu cele aplicate pentru descrierea competenelor generale ale cursului.

Durata medie de parcurgere a primei uniti de nvare este de 2 ore.

U1.1. Sisteme de numeraie n calculatoarele digitale, informaia de orice fel este reprezentat, stocat i prelucrat n form numeric. Numerele se reprezint prin simboluri elementare denumite cifre. Un calculator poate fi prevzut s funcioneze n orice sistem de numeraie. n cazul reprezentrii numerelor utilizate n mod curent, adic cu reprezentate n baza 10, sunt

13

necesare 10 simboluri distincte, cte unul pentru fiecare cifr. Fizic, aceast reprezentare este destul de dificil. Pe parcursul dezvoltrii tehnicii de calcul, s-a stabilit c cel mai avantajos este sistemul binar deoarece procesul prelucrrii sau al stocrii numerelor se face mai uor pentru dou simboluri. Sistemul de calcul trebuie s disting doar ntre dou valori: ntre un semnal de valoare joas (Low, en.) - ntre 0 i 2 voli i unul de valoare nalt (High, en.) aproximativ 5V. n acest caz, sistemului de operare va trebui s-i oferim spre operare reprezentrile binare ale numerelor zecimale folosite n mod curent. n notaiile binare sunt utilizate numai cifrele 0 i 1, spre deosebire de sistemul zecimal unde sunt folosite cifrele de la 0 la 9. Un numr binar este un ir de cifre binare cum sunt 1010 sau 100011. Deci, sistemul binar a fost preferat din urmtoarele motive: simplitatea regulilor pentru operaiile aritmetice i logice; materializarea fizic relativ simpl a cifrelor. Este de subliniat aici, din nou, c sistemele de calcul nu opereaz de fapt cu numerele 0 i 1, ci cu dou stri asociate lor, respectiv semnalele Low i High, contact nchis-contact deschis, prezena sau absena de curent etc. Circuitele care trebuie s diferenieze numai dou stri sunt mai sigure n funcionare dect cele care trebuie s diferenieze 10 stri. Fizic sunt folosite elemente bistabile cu strile: conducie (+5V) blocat (0V) care sunt asociate cu valorile 0 i respectiv 1. Un astfel de element reprezint unitatea de memorie denumit bit (bit este un acronim al cuvintelor engleze binary digit - cifr binar). Evident, acest mod de reprezentare impune transformarea informaiilor de orice natur (texte, sunete, imagini, etc.) n secvene de cifre binare. Totalitatea regulilor de reprezentare a numerelor i de operare cu acestea, mpreun cu mulimea cifrelor, poart denumirea de sistem de numeraie. Sistemul de numeraie folosit n mod uzual, sistemul arab, este un sistem poziional, adic un sistem n care o cifr i aduce aportul la valoarea numrului format att prin valoarea sa, ct i prin poziia pe care o ocup. Numrul cifrelor (simbolurilor) folosite pentru reprezentarea numerelor definete baza sistemului de numeraie poziional. Astfel, orice numr Nr n baza b se reprezint, n mod unic prin relaia (1.1) care n scriere desfurat se reprezint prin relaia (1.2):
m

Nr = c i bi1 ,
i= n

(1.1)

adic:

14

Nr = c m b m + c i1 bm1 + ... + c 1 b1 + c 0 b 0 + c 1 b 1 + ...c n b n

(1.2)

unde: 0 c i b 1 pentru i = n,..., m , iar c m 0 . n mod curent se utilizeaz reprezentarea n baza 10, dar n mod frecvent sunt folosite i alte baze, cum ar fi 2, 8, 16. Utiliznd relaia (1.1) n sistemul zecimal (baza 10), pentru numrul 2529, rezult urmtoarea reprezentare:
(2529 )10 = 2 10 3 + 5 10 2 + 2 101 + 9 10 0

(1.3) (1.4)

n mod asemntor putem reprezenta valori n binar (baza 2):


(1011101)2 = 1 2 6 + 0 25 + 1 2 4 + 1 23 + 1 22 + 0 21 + 1 20

sau, n hexazecimal (baza 16):


(75A4F)16 = 7 16 4 + 5 16 3 + 10 16 2 + 4 161 + 15 16 0

(1.5)

Observaii Baza folosit pentru reprezentarea unui numr determin numrul cifrelor (simbolurilor) folosite. Dac se face reprezentare n baza 2, de exemplu, se vor folosi simbolurile 0 i 1 (vezi relaia 1.4). Dac se face reprezentare n baza 8, se vor folosi simbolurile 0, ..., 7. Numrul (2593)8, fiind reprezentat n baza 8, este incorect deoarece conine cifra 9. Pentru reprezentarea numerelor n baz mai mare dect 10 este necesar adugarea de simboluri utilizate. Pentru baza 16 care este n mod frecvent utilizat, se folosesc cifrele 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a sau A (10), b sau B (11), c sau C (12), d sau D (13), e sau E (14), f sau F (15) (exemplu relaia 1.5).

U1.2. Conversii ntre baze de numeraie Conversia ntre baze de numeraie se face pornind de la modul de reprezentare a numerelor descris prin relaia (1.1). Astfel, transformarea din orice baz n baza 10 se face folosind relaia (1.1), respectiv (1.2) (vezi exemplele din relaiile (1.4) i (1.5)). Exemplu de transformare din baza 2 n baza 10: (1011101)2 = 1 . 26 + 0 . 25 + 1 . 24 + 1 . 23 + 1 . 22 + 0 . 2 + 1 = (93)10 (1.6)

15

Exemplu de transformare din baza 16 n baza 10: (75A4F)16 = 7 . 164 + 5 . 163 + 10 . 162 + 4 . 16 + 15 = (481871)10 (1.7) Transformarea din baza 10 n orice baz se face efectund mpriri succesive ale numrului la baza ctre care se face transformarea, resturile obinute reprezentnd cifrele ce alctuiesc numrul n noua reprezentare: 37 2 1 18 0

2 9 1

2 4 0

(37)10 = (100101)2 2 2 0 2 1

Fig. 1.1. Exemplu de transformare a unui numr din baza 10 n baza 2

Observaie Cifrele se obin n ordine cresctoare a puterii bazei, astfel c n alctuirea numrului ele vor fi poziionate n ordine invers obinerii lor.

Conversiile ntre bazele 10, 2, 8, 16 care sunt utilizate n mod frecvent pentru reprezentarea informaiei n calculatoarele numerice se pot face i folosind tabelul de corespondene ce urmeaz (Tabelul 1.1).

Tabelul 1.1. Tabel de coresponden ntre valori cu reprezentare n bazele 10, 2, 8 i 16

Zecimal Binar 0 1 2 3 4 5 6 7 0000 0001 0010 0011 0100 0101 0110 0111

Octal 00 01 02 03 04 05 06 07

Hexazecimal 0 1 2 3 4 5 6 7

Zecimal Binar Octal Hexazecimal 8 9 10 11 12 13 14 15 1000 1001 1010 1011 1100 1101 1110 1111 10 11 12 13 14 15 16 17 8 9 A B C D E F

16

U1.3. Operaii aritmetice n binar Algoritmii de efectuare a operaiilor aritmetice sunt aceeai, indiferent de baza de numeraie utilizat. Spre exemplu, mai jos sunt reprezentate regulile pentru operaiile de adunare i nmulire n binar, comparativ cu efectuarea acelorai operaii n baza 10: Adunarea: Operaia n baza 2 a 0 0 1 1 b 0 1 0 1 a+b 0 1 1 0 Observaie Cu T s-a reprezentat cmpul de transport T 0 0 0 1 100101+ 10101 111010 Operaia n baza 10 37 + 21 58

nmulirea: Operaia n baza 2 a 0 0 1 1 b 0 1 0 1 a*b 0 0 0 1 100101* 10101 100101 100101 100101 1100001001 Operaia n baza 10 37 * 21 37 74 . 777

U1.4. Operaii logice la nivel de bit n afar de operaiile aritmetice, n mod frecvent se utilizeaz i operaii logice efectuate la nivel de bit. Acestea se efectueaz ntre fiecare pereche format din biii situai pe aceeai poziie n alctuirea operanzilor. Mai jos sunt reprezentate regulile pentru operaiile logice care se efectueaz la nivel de bit: Negarea (NOT) a 0 1

a 1 0

0 1

0 1

1 0

0 1

0 1

1 0

0 1

1 0

17

I logic (AND) a 0 0 1 1 b 0 1 0 1 a&b 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 1 1 37 21 37 & 21

SAU logic (OR) a 0 0 1 1 b 0 1 0 1 a|b 0 1 1 1 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 1 1 0 0 0 1 1 1 37 21 37 | 21

SAU EXCLUSIV (XOR) a 0 0 1 1 b 0 1 0 1 a^b 0 1 1 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 1 0 0 0 0 1 1 0 37 21 37 ^ 21

Operaii de deplasare la nivel de bit Operaiile de deplasare au ca efect deplasarea tuturor biilor cu acelai numr de poziii la stnga (<<), respectiv la dreapta (>>). Locaiile eliberate se vor completa cu valoarea 0.

Fig. 1.2. Descrierea operaiilor de deplasare la nivel de bit

Observaii Deplasarea la stnga cu 1 este echivalent cu nmulirea cu 2 a numrului respectiv, iar deplasarea la dreapta cu 1, cu mprirea ntreag la 2. Deplasarea la stnga cu n este echivalent cu nmulirea cu 2n a numrului respectiv, iar deplasarea la dreapta cu n, cu mprirea ntreag la 2n.

18

U.1.5. Reprezentarea numerelor ntregi cu semn Reprezentarea valorilor numerice ntregi pozitive nu ridic probleme deosebite. Dac se folosete o secven format din n bii, se poate reprezenta orice valoare N<2n. n figura 1.3. sunt utilizai 8 bii, deci se poate reprezenta orice valoare <28. Valoare reprezentat este 1 27 + 1 21 + 1 20 = 131 . Dac ns se dorete reprezentarea de valori negative, se pune problema reprezentrii semnului, avnd la dispoziie doar cele dou simboluri 0 i 1. Pentru a rezolva aceast problem, bitul de pe poziia cea mai din stnga (MSb-Most Significant Bit) va fi folosit pentru reprezentarea semnului, valoarea 0 reprezentnd semnul + i valoarea 1 semnul -.
b7 b6 b5 b4 b3 b2 b1 b0

Cel mai semnificativ bit (MSb)

Cel mai puin semnificativ bit (LSb)

Fig. 1.3. Reprezentarea valorilor numerice ntregi utiliznd 8 bii (un octet sau byte)

Plecnd de la aceast convenie, se folosesc trei tipuri de coduri binare: cod direct (numit i cod mrime / modul i semn, notat pe scurt MS) cod invers (numit i cod complement fa de 1, notat pe scurt C1) cod complementar (numit i cod complement fa de 2, notat pe scurt C2) Reprezentarea numerelor cu semn n cod direct (cod mrime i semn) Mod de reprezentare: Modulul numrului are aceeai reprezentare att pentru numere pozitive ct i pentru cele negative, iar semnul ia valoarea 0 pentru numere pozitive, respectiv 1 pentru numere negative. 0 1 0 0 1 1 0 0 0 0 1 1 0 0 1 1 reprezentarea binar a valorii (37)10 reprezentarea binar a valorii (-37)10

Reprezentarea numerelor cu semn n cod invers (cod complement fa de 1) Mod de reprezentare: Pentru numere pozitive bitul de semn ia valoarea 0, ceilali bii reprezentnd valoarea modulului numrului. Pentru numere negative, bitul de semn este 1, ceilali bii fiind obinui prin complementarea bit cu bit a reprezentrii binare a modulului 19

numrului. 0 1 0 1 1 0 0 1 0 1 1 0 0 1 1 0 reprezentarea binar a valorii (37)10 reprezentarea binar a valorii (-37)10

Reprezentarea numerelor cu semn n cod complementar (cod complement fa de 2) Mod de reprezentare: Pentru numere pozitive reprezentarea este identic cu cea fcut in MS. Aceast reprezentare respect i convenia de reprezentare a semnului: bitul de pe poziia cea mai din stnga (MSB - Most Significant Bit) este bitul de semn, valoarea 0 a acestuia avnd ca semnificaie semnul +, iar valoarea 1 reprezint semnul -. Pentru a obine reprezentarea binar a unui ntreg negativ, se realizeaz negarea la nivel de bit a reprezentrii valorii absolute a respectivului numr i se adun valoarea 1, obinndu-se aa numitul complement fa de doi. De exemplu, valoarea (-37)10, folosind un octet pentru reprezentare, se obine astfel: 0 1 1 0 1 1 1 0 0 0 1 1 0 1 1 1 0 0 0 1 + 1 1 0 1 1 reprezentarea binar a valorii (37)10 negarea bit cu bit (complement fa de 1) reprezentarea binar a valorii (-37)10

Observaii Pentru mainile de calcul reprezentarea numerelor ntregi negative se face prin complementul fa de doi, acesta prezentnd o serie de avantaje n implementarea operaiilor aritmetice.

U1.6. Reprezentarea numerelor reale Numerele reale sunt numerele care sunt formate din: semn, parte ntreag i parte fracionar. Virgula (punctul zecimal sau binar, n notaia englez) nu se reprezint fizic nicieri n registrele calculatorului, dar poziia sa este cunoscut (stabilit) pentru oricare dintre modurile de reprezentare. Reprezentarea numerelor reale se poate face n 2 moduri: reprezentarea n virgul fix; reprezentarea n virgul mobil.

20

Reprezentarea valorilor reale n virgul fix

Fig.1.4. Reprezentarea valorilor numerice reale n virgul fix

n reprezentarea n virgul fix se presupune c partea ntreag este desprit de partea fracionar printr-o virgul imaginar care se gsete ntr-o poziie fix. n acest caz sunt fixe att numrul de poziii ale prii ntregi ct i numrul de poziii ale parii fracionare. Poziia virgulei fixe este o caracteristic a tipului de calculator si a modului n care este construit. De exemplu, dac se reprezint pe 8 bii un numr fracionar cu numrul de poziii ntregi 5, numrul de poziii zecimale va fi 3. In cazul n care numrul N care se reprezint este pozitiv, domeniul de valori al datei va fi: adic: (00000,000)2 N (11111,111)2 (0,0)10 N (31,925)10 Dac numrul este negativ, se va reprezenta prin complement fa de 2, primul bit fiind bitul de semn i domeniul de valori al datei va fi: adic: (11111,11)2 N (01111,111)2 (-16,025)10 N (5,925)10 Aceast reprezentare a numerelor reale nu este avantajoas deoarece nu permite dect reprezentarea de numere reale ntr-un domeniu de valori restrns. Reprezentarea valorilor numerice reale n virgul mobil Pentru stocarea i prelucrarea numerelor reale n calculator se folosete reprezentarea n virgul mobila (VM). Denumirea provine de la faptul c virgula nu are poziie fix fa de biii de reprezentare a numrului. n calculator, un numr N este reprezentat in virgula mobila conform relaiei: N = M * BE (1.8)

unde: M = mantisa, care este de obicei codificat ca un numr binar subunitar, cu semn; 21

E = exponentul, un numr ntreg cu semn; B = baza, este 2 sau o putere a lui 2, dar nu este reprezentat, ea fiind recunoscut implicit ca avnd aceast valoare. Reprezentarea se face n cuvinte cu o anumit lungime (n numr de bii). Precizia de reprezentare a unui numr real este dat n primul rnd de numrul de bii folosii pentru reprezentarea mantisei. Domeniul maxim de reprezentare este determinat de valoarea adoptat pentru baza i de numrul de bii folosii pentru a reprezenta exponentul. n calculator se pot reprezenta deci doar un set finit de numere reale dintr-un anumit interval continuu +/-R (cel mult 2n, unde n este numrul de bii ai cuvntului reprezentat n VM). Deci numerele reale pot fi reprezentate cu o anumit eroare, determinat de numrul limitat de bii folosit pentru reprezentare. Eroarea de reprezentare depinde de distanta dintre dou numere succesive reprezentabile cu cei n bii. Toate numerele reale cuprinse ntre cele dou valori vor trebui aproximate prin una din cele dou valori. Dac baza folosit implicit pentru reprezentare nu este 2 ci 4 sau 16, dezavantajul este c numerele reprezentabile vor fi i mai rar distribuite pe intervalul +/-R; apare ns avantajul creterii domeniului de reprezentare cu n bii. Pentru reprezentarea numerelor n VM se folosete forma normalizata n care prima poziie binar dup virgul este diferit de zero. Normalizarea restrnge mrimea valorii absolute a mantisei binare la domeniul:
1 M <1 2

(1.9)

Numerele prea mari pentru a fi reprezentate corespund unei depiri superioare de capacitate (overflow), iar numerele prea mici unei depiri inferioare de capacitate (underflow). Pentru a fi reprezentat un numr real x este aproximat cu un numr n virgul mobil. Aproximarea lui x poart numele de rotunjire, iar eroarea introdus de eroare de rotunjire. Exist mai multe modaliti pentru rotunjire: trunchiere (rotunjire prin tiere) ; rotunjire la cel mai apropiat numr n virgul mobil. Acurateea sistemului n virgul mobil este caracterizat de aa numita precizie a mainii (sau epsilon main).

Fig. 1.5. Reprezentarea intern a unui numr real

22

Reprezentarea intern a unui numr real X se face sub forma descris n fig. 1.5., unde S reprezint semnul numrului, E este exponentul, iar 0, 1, ... p-1 reprezint cifrele binare ce alctuiesc mantisa. Formatele de reprezentare a numerelor n virgul mobil, conform standardului IEEE 754 (IEEE este acronim pentru Institute of Electrical and Electronics Engineers, o organizaie ce are drept principal scop elaborarea standardelor pentru produsele hardware i software; standardul IEEE-754 se refer la aritmetica n virgul mobil n sistemele binare) sunt: simpl precizie (single-precission) reprezentare pe 32 de bii (fig.1.6.): 1 bit pentru semnul mantisei 8 bii pentru exponent (Emin = -126, Emax= 127) 23 bii pentru mantis

Fig.1.6. Reprezentarea numerelor n simpl precizie

dubl precizie (double-precission) pe 64 de bii (fig.1.7.) 1 bit pentru semnul mantisei 11 bii pentru exponentul decalat (Emin = -1022, Emax = 1023) 52 bii pentru mantis

Fig.1.7. Reprezentarea numerelor n dubl precizie

Pentru: simpl precizie, numerele se reprezint cu 7 cifre zecimale semnificative; dubl precizie, numerele se reprezint cu 16 cifre zecimale semnificative.

23

U1.7. Coduri alfanumerice Computerele sunt dispozitive digitale, deoarece la baza interpretrii informaiilor stau dou valori, 0 i 1, asociate cu dou stri. Toate datele procesate de computer trebuie codificate digital ca serii de zero i unu. Evident, acest mod de reprezentare impune transformarea informaiilor de orice natur (texte, sunete, imagini, etc.) n secvene de cifre binare. Operaia de transformare a informaiei n secvene de cifre binare se numete codificare. Operaia invers codificrii se numete decodificare. Codificarea este realizeaz de dispozitivele destinate introducerii informaiei n calculator, iar decodificarea, de dispozitivele care prezint informaia din calculator ntr-o form accesibil omului. n cazul informaiei textuale, fiecare caracter are drept corespondent codul lui un ir finit format din opt cifre binare. irul respectiv se numete octet (n engleza byte). Corespondena dintre caractere i octei se definete cu ajutorul unui tabel, numit tabel de codificare sau, pur i simplu cod. Pe parcursul dezvoltrii tehnicii de calcul au fost elaborate mai multe coduri. n majoritatea calculatoarelor actuale, pentru codificarea caracterelor se folosete codul ASCII (American Standard Code for Information Interchange). n acest cod, reprezentarea caracterelor se face pe 8 bii. Setul de caractere de baz din codul ASCII cuprinde 127 caractere (deci se poate reprezenta numai pe 7 bii), care sunt literele alfabetului englez (majuscule i minuscule), cele zece cifre ale sistemului de numeraie zecimal, semnele de punctuaie i unele "caractere speciale" (spaiu liber, sfrit de linie, etc.). Acest set de baz este folosit n toate rile i este suficient pentru limba englez. El este, de asemenea, suficient pentru majoritatea limbajelor de programare, deoarece cuvintele cheie ale acestora sunt preluate tot din limba englez. n prezent se folosete codul ASCII extins, reprezentarea caracterelor fiind fcut pe 8 bii, apelat adesea doar prin numele de cod ASCII. Primele 32 de caractere ASCII codific coduri de control i sunt utilizate pentru a transmite diferite caractere de control privind mesaje. Aceasta pentru c ASCII a fost dezvoltat iniial pentru transmisia datelor (de exemplu caracterul de control ^D, EOT = End Of Transmission, este utilizat pentru a indica sfritul unui flux de date). Restul codurilor se refer la 64 litere i cifre i 196 caractere de control, semne de punctuaie, caractere grafice i alte caractere. Scopul principal al codului ASCII este reprezentarea textului. Astfel c adesea datele de tip text sunt referite ca date de tip ASCII. O secvena de caractere reprezentate prin codurile lor ASCII, e numit ir ("string"). irul poate sa fie gol (nici un caracter) sau poate cuprinde o fraz, un paragraf, sau chiar un bloc ntreg de caractere. La sistemul de operare DOS i la unele limbaje de programare, cum este C/C++, irul de caractere se termin cu un cod ASCII 0 (zero); acesta se numete ir ASCIIZ. n Tabelul 1.2. este prezentat codul ASCII pe 7 bii. n ultima vreme, pentru reprezentarea caracterelor s-a adoptat un nou sistem de 24

codificare, numit Unicode. n acest sistem, caracterele sunt reprezentate pe 16 bii, ceea ce permite s se reprezinte, practic, caracterele tuturor alfabetelor de pe glob. Este adevrat ns c, n acest fel, spaiul ocupat de un anumit text n memorie este dublu fa de cel ocupat n ASCII.
Tabelul 1.2. Codul ASCII pe 7 bii

b3b2b1b0 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

000 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI

001 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US

010 SP ! " # $ % & / ( ) * + , . /

b6b5b4 011 100 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O

101 P Q R S T U V W X Y Z [ \ ]

110 ' a b c d e f g h i j k l m n o

111 p q r s t u v w x y z { | } DEL

U1.8. Cantitatea de informaie Cantitatea de informaie exprim numrul minim de cifre binare necesare pentru codificarea i decodificarea univoc a informaiei. Prin folosirea unui singur bit, se pot reprezenta doar dou valori. Prin utilizarea a n bii, se pot reprezenta 2n valori. n informatic, pentru msurarea cantitii de informaie, n mod obinuit se folosete un multiplu al bitului, octetul (byte): 1 byte (octet) = 1B = 23 = 8 bii Pentru c n general cantitatea de informaie prelucrat este mare, n mod frecvent aceasta se exprim prin multiplii octetului (byte-ului) (Tabelul 1.3.):

25

Tabelul 1.3. Multiplii octetului (byte-ului)

1 kilobyte (kB) 1 megabyte (MB) 1 gigabyte (GB) 1 terrabyte (TB) 1 pentabyte (PB) 1 exabyte (EB)

= = = = = =

1024 bytes (210 bytes) 1024 kbytes (210 kB) 1024 Mbytes (210 MB) 1024 Gbytes (210 GB) 1024 Tbytes (210 TB) 1024 Pbyte (210 PB)

Observaie A nu se confunda bit-ul cu byte-ul, denumirea englezeasc pentru octet.

Rezumat n calculatoarele digitale, informaia de orice fel este reprezentat, stocat i prelucrat n form numeric. Pentru reprezentarea datelor se folosete sistemul de numeraie arab care este un sistem poziional. Pentru reprezentarea datelor n calculator se folosete sistemul binar. n notaiile binare sunt utilizate numai cifrele 0 i 1. n mod curent sunt folosite i alte baze de numeraie, i anume baza 10, 8 sau 16, valorile numerice reprezentate ntr-o baz putnd fi convertite i n alte baze. ntre valori numerice se pot efectua diferite tipuri de operaii, cum ar fi operaii aritmetice sau operaii la nivel de bit. Valorile numerice ntregi cu semn, n mod curent, sunt reprezentate n cod complement fa de doi. Valorile numerice reale, n mod curent, sunt reprezentate n virgul mobil, n simpl sau dubl precizie. Pentru reprezentarea datelor alfanumerice se folosesc codificri care asociaz valori numerice cu caractere; unul dintre codurile cu reprezentare pe un octet folosit n mod uzual este codul ASCII. Elementul de baz folosit n reprezentarea datelor este unitatea de memorie denumit bit. Pentru msurarea cantitii de informaie, n mod obinuit se folosete un multiplu al bitului, byte-ul i multiplii ai acestuia obinui prin nmulire cu 210. 26

ntrebri, exerciii i probleme 1. Care sunt avantajele reprezentrii informaiei folosind reprezentarea binar? 2. S se efectueze urmtoarele transformri: a. 11011001(2) = ?(10) b. 10101010(2) = ?(10) c. 11000000(2) = ?(10) d. 101001(2) = ?(8) e. 101001100(2) = ?(8) f. 10100110(2) = ?(8) g. 100010(2) = ?(8) h. 8(10) = ?(8) i. 16(10) = ?(8) j. 32(10) = ?(8) k. 128(10) = ?(8) l. 256(10) = ?(8)

m. n. o. p. q. r. s. t. u. v. w. x.

16(10) = ?(2) 32(10)= ?(2) 45(10) = ?(2) 256(10) = ?(2) 2A(16) = ?(10) 27(16) = ?(10) 3A2F(16) = ?(10) 8(10) = ?(16) 16(10) = ?(16) 32(10) = ?(16) 128(10) = ?(16) 256(10) = ?(16)

3. Efectuai urmtoarele operaii aritmetice. Verificai rezultatele obinute, transformnd operanzii n baza 10. a. 1001(2) + 110101(2) = ? b. 1111(2) + 1001(2) = ? c. 1101(2) + 111011(2) = ? d. 101(2) x 101(2) = ? e. 1011(2) x 100(2) = ? f. g. h. i. j. 111(2) x 111(2) = ? 1207(8) + 375(8) = ? 101(8) x 110(8) = ? 1A07(16) + 3B9(16) = ? 101(16) x 110(16) = ?

4. S se determine rezultatul urmtoarelor operaii la nivel de bit, operanzii fiind reprezentai n baza 10: a. 79 = ? (negare la nivel de bit) b. 65 & 99 = ? ( I logic la nivel de bit) c. 101 | 28 = ? ( SAU logic la nivel de bit) d. 23 ^ 48 = ? ( SAU EXCLUSIV la nivel de bit) e. 22 << 3 = ? ( deplasare la stnga la nivel de bit) f. 45 >> 3 = ? ( deplasare la dreapta la nivel de bit) NOT: La efectuarea operaiilor, operanzii vor fi reprezentai n binar. 5. S se determine reprezentarea n cod complement fa de 2, folosind un octet, urmtoarele valori: a. 69 ? b. 69 ? c. 127 ? 6. S se efectueze urmtoarele transformri: a. 1024 kB ? MB b. 1024 kB ? B d. -128 ? e. 255 ? f. 256 ?

c. 1GB ? B d. 1TB ? B

27

Unitatea de nvare U.2.

STRUCTURA GENERAL A SISTEMELOR DE CALCUL

Cuprins Introducere .................................................................................................................... 28 Obiectivele unitii de nvare ..................................................................................... 28 U2.1. Generaliti despre structura hardware a unui calculator .................................... 29 U2.2. Generaliti despre structura software a unui calculator ..................................... 32 U2.3. Sistemul de operare ............................................................................................. 35 Rezumat ........................................................................................................................ 39 ntrebri, exerciii i probleme ...................................................................................... 39

Introducere n general, noiunea de calculator (sistem de calcul) reprezint un ansamblu de dispozitive i circuite diverse care prelucreaz datele introduse ntr-o form prestabilit, efectueaz diverse operaii asupra acestora i furnizeaz rezultatele obinute (Fig.2.1.).

Fig.2.1. Reprezentarea general a unui sistem de calcul

Orice sistem de calcul este format din dou pri distincte: hardware-ul i software-ul. Hardware-ul este reprezentat de totalitatea echipamentelor i dispozitivelor fizice; Software-ul este reprezentat prin totalitatea programelor care ajut utilizatorul n rezolvarea problemelor sale. Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Structura general a unui sistem de calcul; Generaliti despre structura hardware a unui calculator; Generaliti despre structura software a unui calculator. Durata medie de parcurgere a celei de a doua uniti de nvare este de 2 ore.

28

U.2.1. Generaliti despre structura hardware a unui calculator Construcia fizic (hardware-ul) a unui calculator personal IBM PC cuprinde, n principal (Fig.2.2.): Unitatea central (UC); Magistrale de comunicaie; Echipamente periferice: Dispozitive de intrare; Dispozitive de ieire; Dispozitive de intrare-ieire; Dispozitive de stocare a informaiei. Unitatea central (UC) este de fapt creierul calculatorului personal. Aceasta: coordoneaz ntreaga activitate a calculatorului; solicit informaii pe care utilizatorul le introduce de la tastatur; realizeaz prelucrrile de date prin executarea unui program; ofer datele de ieire obinute n urma prelucrrilor.

Fig.2.2. Structura intern a calculatorului electronic

Caracteristicile UC dau caracteristicile principale ale unui calculator. UC conine, n principal: placa de baz; microprocesorul; memoria intern; accesorii. 29

Placa de baz este un suport ce conine circuite electronice i asigur stabilitatea i performanele unui calculator, comunicaiile ntre toate componentele existente n calculator (procesor, memorie, plac video, etc.). Microprocesorul (P) este un circuit integrat. Microprocesorul reprezint creierul ntregului calculator, coordonatorul tuturor operaiilor ce sunt efectuate de ctre acesta. Microprocesorul este conectat la celelalte componente ale calculatorului prin intermediul magistralei de date i a magistralei de comenzi. El este caracterizat n principal de: viteza de lucru; capacitatea maxim de memorie pe care o poate adresa; setul de instruciuni pe care le poate executa. Memoria intern este un ansamblu de circuite, prin intermediul crora se memoreaz programele i datele pe parcursul execuiei lor. Datele din memoria intern se pierd atunci cnd calculatorul se oprete. Fizic, memoria se prezint sub forma unor circuite integrate (circuite electrice obinute prin aplicarea pe un suport electroizolant a elementelor de circuit electric, n scopul miniaturizrii i simplificrii tehnologiei de fabricaie), lipite pe un circuit imprimat, care se ataeaz plcii de baz. Pentru a extinde capacitatea de memorare a calculatorului i a pstra datele se folosete memoria extern. Memoria intern este caracterizat de doi parametri: dimensiunea: este n strns legtur cu tipul microprocesorului folosit; timpul maxim de rspuns: este intervalul de timp care este necesar memoriei interne pentru a citi sau scrie date. Valoarea este de ordinul ns. Cu ct valoarea este mai mic, cu att va funciona mai rapid calculatorul. Din punct de vedere al accesului, memoria intern poate fi: Memorie RAM (Random Access Memory memorie cu acces aleator); Memorie ROM (Read Only Memory - memorie numai pentru citire). Memorie EPROM (Erasable Programmable ROM) sunt memorii de tip ROM care pot fi renscrise de un numr limitat de ori. Memoria RAM se mai numete memorie moart, deoarece datele pe care le memoreaz se terg la nchiderea calculatorului. Poate fi citit sau scris. Se mai numete memorie volatil deoarece informaia se pstreaz att timp ct este meninut alimentarea cu tensiune. Funcional, memoriile RAM se utilizeaz n diferite scopuri, spre exemplu ca: memorie de lucru; memorie cache; memorie video; memorie tampon pentru imprimant. Memoria de lucru este memoria folosit de utilizator, n ea se memoreaz 30

instruciunile programelor care se execut i datele asociate acestora, ele fiind preluate din memoria permanent. Datele care se dorete a fi pstrate trebuie salvate n memoria permanent. Memoria cache este o memorie tampon foarte rapid, ntre P (uneori ncorporat n acesta) i memoria intern propriu-zis. Memoria cache este de dou feluri: de nivel unu (intern) i de nivel doi (extern). Cea intern este integrat n P. Mrimea memoriei cache extern variaz de la un calculator la altul, valorile uzuale fiind de 64 Kb, 256 Kb, 512 Kb, 1 MB, 2 MB, etc. Memoria video sau grafic, permite afiarea pe ecran a unei grafici video complexe, avnd ca rol maximizarea performanelor plcilor grafice. Memoria tampon pentru imprimant reprezint ansamblul locaiilor de memorie, unde se stocheaz datele ce urmeaz a fi tiprite, pn ce imprimanta le poate prelua. Memoria RAM se prezint ca o succesiune de octei (octet sau byte sau locaie de memorie). Un octet are 8 bii. Bit-ul reprezint unitatea elementar de informaie i poate avea una din valorile: 0 sau 1. Capacitatea unei memorii este dat de numrul de locaii pe care aceasta le conine i 10 se msoar n multiplii de 1024 (2 ). De exemplu, 1 Mbyte = 1024 Kbytes; 1Kbyte = 1024 bytes.

Fig.2.3. Organizarea memoriei interne

Numrul de ordine al unui octet n memorie se poate specifica printr-un cod, numit adres (Fig.2.3.). Ordinea n care sunt accesate locaiile de memorie nu este impus, memoria fiind un dispozitiv cu acces aleator la informaie. n memorie se nregistreaz dou categorii de informaii: date - informaii de prelucrat; programe - conin descrierea (implementarea ntr-un limbaj de programare) a aciunilor care vor fi executate asupra datelor, n vederea prelucrrii acestora.

31

Observaii Prin program putem nelege fie un set de instruciuni scris de un programator, fie o secvena software executabil. O soluie de rezolvare a unei probleme se numete algoritm. Algoritmul const dintr-o succesiune finit de pai care, pornind de la date, produce rezultate. n memoria intern este pstrat doar informaia prelucrat la un moment dat. Memoria intern are capacitate redus; accesul la informaia pstrat n aceasta este extrem de rapid, iar datele nu sunt pstrate dup terminarea prelucrrii (au un caracter temporar). Memoria ROM poate fi doar citit, nu poate fi scris de utilizator; este scris o singur dat cu informaia necesar, de ctre productor. Este nevolatil, informaia ei se pstreaz chiar dac cip-urile nu sunt alimentate cu tensiune. Componentele neconfigurabile ale BIOS-ului (Basic Input Output System) sunt memorate ntr-o astfel de memorie. Aceste componente sunt secvene de program care sunt executate de fiecare dat la pornirea calculatorului. BIOSul rmne n fundal i conlucreaz cu sistemul de operare tot timpul ct calculatorul este n funciune. BIOS-ul asigur stabilitatea sistemului. O alt component important a memoriei o constituie cea care stocheaz principalii parametri configurabili ai BIOS-ului. Constructiv este de tip CMOS (Complementary Metal Oxide Semiconductor) i poate fi scris i citit. Este alimentat n permanen de un acumulator, ea fiind volatil (dac acumulatorul este ndeprtat, informaia se pierde). Ea conine date, cum ar fi: informaii referitoare la dat i ora sistemului; informaii referitoare la componentele hardware (hard-disk-uri, floppy disk-uri, dispozitive de afiare, tastatur, etc.); informaii referitoare la parola sistemului.

U2.2. Generaliti despre structura software a unui calculator Software-ul reprezint ansamblul de programe care fac posibil realizarea funciei sistemului de calcul, de prelucrare a informaiilor i care constituie suportul logic de funcionare a unui sistem de calcul (fig.2.4.). ntr-o traducere mot--mot, software-ul nseamn partea moale" a calculatorului, spre deosebire de hardware, "partea tare. Firmware-ul este componenta de programe ncrcate n memoria fix ROM de ctre productorul sistemului de calcul. Aceast component se afl la limita dintre hardware i software, reprezentnd software-ul integrat n partea de hardware. Componenta firmware a unui sistem de calcul, setul de instruciuni microprogramate ncrcate n memoria fix ROM, definete un anumit mod de funcionare i implicit de 32

utilizare a sistemului de calcul. Din acest motiv, firmware-ul trebuie s fie suficient de redus pentru a nu particulariza excesiv sistemul de calcul. Prin utilizarea unor memorii cu citirescriere, nevolatile, alturi de memoria ROM, se obin componente cu microprogramare dinamic. Aceasta const n posibilitatea adaptrii secvenei de programe fixe din ROM la ncrcarea sistemului de operare.

Fig.2.4. Componentele software ale unui sistem de calcul

Componenta ROM-BIOS a sistemelor de calcul compatibile PC este o component firmware, realizat prin microprogramare dinamic. Rolul componentei BIOS este de interfa ntre hardware i software, oferind componentei software funcii de baz pentru utilizarea hardware-ului. n acest fel se realizeaz independena componentelor software fa de caracteristicile hardware specifice sistemului de calcul, elibernd, n acelai timp, componentele software de detalii legate de modul de lucru al hardware-ului. Fiind realizat prin microprogramare dinamic, componenta firmware (BIOS) permite modificarea unor parametri de funcionare ai PC-ului ntr-o secven special, derulat n timpul procedurii de ncrcare a sistemului de operare, la pornirea sistemului de calcul. Componenta software a unui sistem de calcul cuprinde programe grupate n mai multe categorii, dup natura problemelor pe care le rezolv. Aceste categorii sunt: Software-ul de baz, care este alctuit din programele care asigur serviciile generale i care se adreseaz tuturor utilizatorilor sistemului de calcul; Software-ul utilitar (sistem de programe utilitare), care include programe cu grad mare de generalitate puse la dispoziia utilizatorilor pentru a realiza anumite prelucrri specifice asupra informaiilor, prelucrri comune tuturor utilizatorilor. Software-ul de aplicaie, constituit din programe ale utilizatorilor, care rezolv probleme cu un nivel redus de generalitate, specifice fiecrui utilizator. 33

Software-ul de baz reprezint totalitatea programelor care fac posibil funcionarea i utilizarea unui sistem de calcul. El include programe ierarhizate dup natura problemelor pe care le rezolv i dup importana lor. n acest sens avem: Sistemul de operare, care acioneaz ca o interfa ntre sistemul de calcul i utilizator. Sistemul de operare are rolul de a coordona i supraveghea funcionarea sistemului de calcul i de a realiza comunicarea ntre utilizator i sistemul de calcul: Gestiunea echitabil i eficient a resurselor din cadrul sistemului de calcul; Realizarea interfeei cu utilizatorul; Furnizarea suportului pentru dezvoltarea i execuia aplicaiilor. Sistemul de programare cuprinde componentele software, care permit utilizatorului s realizeze programe executabile pentru sistemul de calcul respectiv. Sistemul de programe cuprinde pachete de programe dedicate, specifice fiecrui limbaj de programare folosit de utilizator. Spre exemplu: programe editoare folosesc pentru introducerea i modificarea interactiv a instruciunilor; programe translatoare specifice pentru fiecare limbaj de programare, sunt acele aplicaii care transform programele surs scrise ntr-un limbaj de programare n programe-obiect, scrise n limbaj-main; programe editoare de legturi, adic aplicaiile care transform programele din format obiect n programe executabile, realiznd, dac este cazul, integrarea mai multor module-obiect ntr-un singur program executabil; programe de depanare, interactive sau nu, care permit monitorizarea erorilor; aplicaii complexe numite medii de programare, care includ toate funciile componentelor prezentate anterior, cu scopul de a genera un program executabil ntr-un mediu integrat. programele editoare de texte (programe interactive, destinate introducerii, modificrii, formatrii i tipririi textelor). n categoria software-ului utilitar intr: programele care permit exploatarea componentelor hardware ale sistemelor de calcul n condiii optime. Aceste programe pot utiliza verificarea strii de funcionare a echipamentelor hardware, configurarea parametrilor de funcionare, optimizarea modului de utilizare a componentelor hardware ale sistemelor de calcul. medii de prelucrare complex a datelor, organizate sub form de text, imagine, sunet sau sub form de tabele. Aceste instrumente software pot fi folosite direct de 34

utilizatori neprofesioniti pentru dezvoltarea unor aplicaii sau pot fi folosite de proiectanii de software ca instrumente de mare productivitate. suprafee de operare care sunt aplicaii specifice sistemelor interactive, care nlocuiesc dialogul utilizatorului cu sistemul prin intermediul limbajului de comand al sistemului de operare cu interfee de lucru prietenoase. Software-ul de aplicaie este construit din programe ale utilizatorilor care rezolv probleme cu un nivel redus de generalizare i care permite utilizarea sistemului de calcul n cele mai diverse domenii: economice, industriale, sociale, medicale etc. Execuia programelor dintr-o anumit categorie se sprijin pe serviciile oferite de categoriile precedente. Astfel, software-ul de aplicaie este dependent de tipul software-ului de baz pentru care a fost proiectat. La nivelul utilizatorilor, aceast dependen creeaz deseori multe probleme. Din aceast cauz, o trstur important a software-ului de aplicaie este portabilitatea, adic acea caracteristic ce permite rularea software-ului de aplicaie fr transformri pe diverse sisteme de operare. Software-ul de baz, n special componenta sistemului de operare, vine i ea n ntmpinarea acestei probleme, realiznd emulri ale funciunilor sistemelor de operare anterioare n noile sisteme de operare. Software-ul de aplicaie are foarte multe categorii n care poate fi clasificat, prerile referitoare la clasificare fiind mprite. Una din clasificri permite mprirea software-ului de aplicaie astfel: software cu destinaie tiinific; software cu destinaie economic; software de proces (software pentru urmrirea proceselor industriale); software de gestiune (care vizeaz funciunile financiare, contabile i de conducere ale ntreprinderii). n ultimul timp se constat o deplasare a ponderii de interes de la componentele financiar-contabile spre componentele de conducere. Au aprut n aceast categorie aanumitele sisteme informatice pentru sprijinirea deciziei, sisteme informatice pentru conducere. Accesibilitatea, gradul de diversitate i numrul programelor crete de la componenta firmware ctre componenta software de aplicaie. n acelai timp, nivelul de specializare al celor crora li se adreseaz crete de la componenta software de aplicaie ctre componenta firmware.

U2.3. Sistemul de operare Sistemul de operare reprezint ansamblul de programe care asigur folosirea optim a resurselor fizice i logice ale unui sistem de calcul. El are rolul de a coordona i controla 35

execuia programelor i de a permite comunicarea utilizatorului cu sistemul de calcul. Pe scurt, sistemul de operare este acea parte a componentei sistemului de calcul care coordoneaz i supravegheaz ntreaga activitate. Folosirea hardware-ului unui sistem de calcul ar fi dificil i ineficient n lipsa unui sistem de operare accesibil utilizatorilor. Din punct de vedere al interaciunii cu componentele hardware, sistemul de operare este organizat pe dou niveluri: 1. Nivelul fizic, care include componenta firmware a sistemului de calcul. Acest nivel ofer servicii privind lucrul cu componentele hardware. La acest nivel, comunicarea sistemului de operare cu sistemul de calcul se realizeaz prin intermediul aa-numitului sistem de ntreruperi, care semnalizeaz apariia unor evenimente interne sau externe sistemului de calcul. De exemplu, n componenta ROM-BIOS sunt grupate, dup funcia lor, urmtoarele programe: programe care execut pornirea sistemului de calcul; programe care verific starea de funcionare a sistemului de calcul; programe de iniializare a activitii sistemului de calcul; rutinele care coordoneaz rularea componentelor fizice ale sistemului de calcul, numite i drivere fizice; ele ofer servicii pentru lucrul cu tastatura, imprimanta i cu perifericele nestandard. 2. Nivelul logic include partea de operare a sistemului de calcul i ofer utilizatorului mijloacele prin care poate exploata sistemul de calcul. Comunicarea utilizatorului cu sistemul de calcul se realizeaz prin intermediul comenzilor i instruciunilor din programele pe care le execut. Comunicarea invers, sistem de calcul-utilizator, se realizeaz prin mesajele transmise de sistemul de operare utilizatorului. Programele nivelului logic adreseaz dispozitivele hardware prin intermediul programelor nivelului fizic al sistemului de operare i din acest motiv ele sunt independente de structura hardware a sistemului de calcul. Nivelul fizic constituie, aadar, o interfa ntre hardware i nivelul logic al sistemului de operare Din punct de vedere funcional, programele sistemului de operare se mpart n dou categorii: componentele de comand i control care cuprind programe care au rolul de a asigura utilizarea eficient a resurselor sistemului de calcul; componentele de servicii care cuprind programe destinate minimizrii efortului uman implicat n utilizarea sistemului de calcul. Funcia sistemului de operare, privind optimizarea exploatrii unui sistem de calcul, este mprit ntre componenta de comand i control i componenta de servicii. Resursele sistemului de calcul, pe care sistemul de operare le pune la dispoziia utilizatorului, se constituie din totalitatea componentelor fizice sau logice ale sistemului de calcul, care pot fi 36

solicitate la un moment dat n timpul execuiei unui program. Gestionarea resurselor sistemului de calcul este principala sarcin a sistemului de operare. n general, pentru a executa un program ntr-un sistem de calcul secvenial cu program memorat este necesar ncrcarea acestui program n memoria intern a sistemului de calcul i, sub controlul unitii centrale de prelucrare, sunt executate secvenial instruciunile programului. n detaliu, execuia unui program se definete ca o succesiune de activiti care se desfoar la un moment dat sub controlul sistemului de operare, activiti numite procese i care se caracterizeaz prin: prelucrrile pe care le realizeaz determinate de programul de execuie din care a derivat procesul; contextul de lucru care const din resursele alocate procesului. Executarea unei instruciuni program presupune mai nti alocarea unor resurse, cum ar fi: alocarea unitii aritmetice logice pentru efectuarea de operaii aritmetice sau logice asupra datelor; alocarea unui dispozitiv periferic pentru transferul de informaii ntre acesta i memoria intern; alocarea de spaiu n memoria intern; accesarea unei anumite structuri de date din memoria extern; apelul pentru execuie al unui alt program. ntotdeauna execuia unui alt program presupune alocarea unei anumite zone din memoria intern a sistemului de calcul i, simultan, afectarea unei perioade din timpul de lucru al unitii centrale de prelucrare. Pentru a realiza alocarea unei resurse la un proces, sistemul de operare trebuie s aib rspuns la urmtoarele ntrebri (de la caz la caz): dac resursa cerut exist n sistem; dac resursa este disponibil; ct din resurs este disponibil; pentru ct timp poate fi alocat resursa; dac resursa este alocat, dac i mai este necesar procesului cruia i este alocat (eliberarea resursei). Rezult, aadar, funciile ce trebuie ndeplinite de componenta sistemului de operare care are rolul de gestionare a resurselor: evidena resurselor sistemului de calcul n fiecare moment, prin nregistrarea fiecrei resurse, a strii ei (alocat sau liber) i a gradului ei de ocupare; implementarea unor algoritmi de alocare a resurselor conform unei strategii de alocare stabilite. O strategie de alocare trebuie s rspund la ntrebrile: crei solicitri i se aloc resursa;

37

ct din resurs se aloc; n ce moment se face alocarea; pentru ct timp se face alocarea resursei; cum se realizeaz alocarea efectiv a resursei, cu actualizarea informaiilor legate de starea resursei; cum se realizeaz eliberarea resursei, care poate fi fcut la iniiativa procesului care a solicitat-o, atunci cnd ea nu mai este necesar procesului sau la iniiativa sistemului de operare, pentru a fi alocat altor procese. Aceast ultim variant este utilizat numai de anumite tipuri de sisteme de operare; s planifice i s controleze fluxul aplicaiilor; s detecteze i s corecteze erorile care apar n procesul de prelucrare; s gestioneze sistemul de fiiere. Componenta de comand i control a sistemului de operare. Activitatea de lansare n execuie a unui program, activitatea de gestionare a alocrii resurselor, ca i operaiile efectuate la ncheierea execuiei acestuia sunt funcii realizate de componenta de comand i control a sistemului de operare . Componenta de servicii a sistemului de operare. Aceasta s-a dezvoltat odat cu cerinele utilizatorilor. Gradul de accesibilitate al unui sistem de calcul, ca i complexitatea sarcinilor pe care utilizatorul le poate rezolva cu ajutorul lui sunt influenate de existena i eficiena programelor de sistem incluse n componenta de servicii. Programele de servicii se execut sub supravegherea programelor de comand i control, ca orice program de aplicaii. Aceast component ofer servicii diferite de la un sistem de operare la altul sau chiar de la versiuni diferite ale aceluiai sistem de operare. Componenta de servicii a unui sistem de operare poate include: program ncrctor, care lanseaz programe ale sistemului de operare la pornirea sistemului de calcul; program de tip "interpretor de comenzi", care traduce comenzile lansate de utilizator sistemului de operare, asigurnd astfel comunicarea ntre utilizator i sistemul de operare. Funciile realizate de aceast component sunt: Funcia de gestionare a dialogului cu utilizatorul, fie n mod comand, oferind mecanisme de editare a comenzilor, fie prin intermediul unei interfee grafice. Funcia de nlnuire prin date a comenzilor sistemului de operare, de agregare a comenzilor sistemului de operare, sub forma unor macrouri sau a unor fiiere de comenzi. Funcia de asisten on-line, cunoscuta i sub numele de help al sistemului de operare.

38

Funcia de tipul "plug and play" realizeaz aciunea de autodetecie a echipamentelor nou instalate n sistem, permite reconfigurarea cu uurin a sistemului i notificarea schimbrii configurrii sistemului, de exemplu la cderea unui echipament. Funcia care ofer suportul pentru utilizarea limbii naionale, adic adaptarea informaiilor cu caracter naional (simbol monetar, marca zecimal, dat calendaristic etc.).

Rezumat Orice sistem de calcul este format din dou pri distincte: hardware-ul i software-ul. Unitatea central (UC) coordoneaz ntreaga activitate a calculatorului; Memoria intern este un ansamblu de circuite, prin intermediul crora se memoreaz programele i datele pe parcursul execuiei lor. Memoria intern este volatil, informaia stocat n ea se pierde la scoaterea de sub tensiune a sistemului de calcul. Memoria de lucru este organizat ca o succesiune de octei asociai cu valori numerice numite adrese. Componenta software cuprinde programe grupate: software de baz, software utilitar, software de aplicaie. Sistemul de operare are rolul de a coordona i supraveghea funcionarea sistemului de calcul i de a realiza comunicarea ntre utilizator i sistemul de calcul. El conine componenta firmware care ofer servicii privind lucrul cu componentele hardware i componente care asigur comunicarea utilizatorului cu sistemul de calcul se realizeaz prin intermediul comenzilor i instruciunilor din programele pe care le execut, acestea fiind independente de structura hardware a sistemului de calcul.

ntrebri. Exerciii. Probleme. 1. Descriei structura hardware general a unui calculator. 2. Descriei structura memoriei interne. 3. Ce reprezint adresele de memorie? 4. Care este rolul firmware-ului. 5. Descriei componentele i rolul sistemului de operare.

39

Unitatea de nvare U.3. NOIUNI INTRODUCTIVE PENTRU


LIMBAJELE DE PROGRAMARE C/C++

Cuprins Introducere .................................................................................................................... 40 Obiectivele unitii de nvare ..................................................................................... 41 U3.1. Etapele parcurse pentru obinerea unui program executabil ............................... 41 U3.2. Elementele de baz ale limbajelor C/C++........................................................... 41 U3.2.1. Identificatori ......................................................................................... 42 U3.2.2. Semne de punctuaie i caractere speciale ............................................ 44 U3.2.3. Spaii albe ............................................................................................. 44 U3.3. Structura programului C/C++ ............................................................................. 44 U3.4. Directive de preprocesare.................................................................................... 47 U3.5. Primul program C/C++ ....................................................................................... 48 U3.6. Utilizarea comentariilor ...................................................................................... 49 U3.7. Tipuri de date fundamentale ............................................................................... 50 Exemple ........................................................................................................................ 53 Rezumat ........................................................................................................................ 55 Test de autoevaluare ..................................................................................................... 56 ntrebri, exerciii i probleme ...................................................................................... 57

Introducere Limbajul C a fost dezvoltat la nceputul anilor 1970 de Ken Thompson i Dennis Ritchie, odat cu care scrierea nucleului sistemului de operare UNIX. Limbajul C este un limbaj simplu i portabil. Este implementat pe marea majoritate a platformelor de calcul existente azi, i este unul dintre cele mai populare limbaje de programare. Limbajul C este un limbaj care se bazeaz pe principiile programrii procedurale, facilitnd programarea structurat, cu posibiliti de control, permind scrierea unor aplicaii complexe, asemeni limbajelor de nivel nalt, cum ar fi Pascal, Basic, Fortran etc. n acelai timp se apropie i de limbajele de nivel sczut, permind inserarea de cod scris n limbaj de asamblare, ceea ce asigur o mare flexibilitate. Din aceste motive este ncadrat n categoria limbajelor de nivel mediu.

40

Avnd n vedere larga lui utilizare, n anul 1990 a fost adoptat standardul ANSI C (ANSI-American National Standards Institute) care standardizeaz elementele specifice limbajului C, cum ar fi: cuvintele cheie disponibile, bibliotecile de funcii, operaiile de intrare/ieire, utilizarea irurilor de caractere. La sfritul anilor 80, odat cu dezvoltarea tehnicii de programare orientat pe obiecte (OOP-Object Oriented Programming), Bjarne Stroustrup a creat limbajul C cu clase, care este construit pe baza limbajului C completat cu faciliti de creare i utilizare de clase. Ulterior acest limbaj a fost numit C++, el fiind de asemenea standardizat prin adoptarea standardul ANSI C++. Aplicarea principiilor OOP duce la creterea productivitii programrii. Limbajele C/C++ sunt limbaje structurate. Trstura caracteristic a limbajelor structurate este compartimentarea datelor i a codului (folosirea variabilelor temporare). Programele scrise n C/C++ sunt alctuite din una sau mai multe funcii (trebuie s conin cel puin o funcie i aceasta s se numeasc main). Nu este permis crearea i declararea unei funcii n interiorul altei funcii. Folosind variabile locale, se pot scrie proceduri care s realizeze o sarcin specific i care s nu cauzeze efecte secundare nedorite n alte pri ale codului. Un program scris intr-un limbaj structurat este organizat sub forma de blocuri permindu-i acestuia o structur modular.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii elementele de baz ale limbajelor C/C++: Identificatorii folosii n C/C++; Structura unui program C/C++; Folosirea directivelor de preprocesare #define i #include Convenii de introducere a comentariilor; Tipuri de date fundamentale.

Durata medie de parcurgere a celei de a treia uniti de nvare este de 2 ore.

U3.1. Etapele parcurse pentru obinerea unui program executabil Calculatorul prelucreaz datele de intrare printr-o succesiune de transformri pentru a obine datele de ieire. Succesiunea de prelucrri este descris prin program. Fiecare

41

prelucrare este rezultatul uneia sau mai multor instruciuni. La scriere unui program se are n vedere ordinea de efectuare a prelucrrilor, ea respectnd un anumit algoritm. Principalele etape care se parcurg pentru obinerea unui program executabil sunt (Fig.3.1): etapa de scriere a programului surs (fiier cu extensia .cpp): este etapa n care, prin intermediul unui editor de text sau IDE (Integrated Development Environment mediu de dezvoltare a programelor), se scrie programul, respectndu-se sintaxa limbajului i logica aplicaiei; etapa de compilare: mai nti se execut directivele de preprocesare prin expandarea n codul surs i apoi se transpune programul surs n program obiect (fiier cu extensia .obj); etapa de link-editare: crearea legturilor ntre modulele obiect obinute la pasul anterior i cu bibliotecile de sistem i transformarea intr-un program executabil (fiier cu extensia .exe); etapa de lansare n execuie a fiierului executabil.

Fig.3.1. Principalele etape parcurse pentru obinerea unui program executabil

U3.2. Elemente de baz ale limbajelor C/C++ La scrierea unui program n C/C++ se folosesc uniti sintactice care se ncadreaz n diferite categorii, cum ar fi: identificatori nume care desemneaz tipuri de date, constante, variabile, funcii, etc. semne de punctuaie i caractere speciale simboluri care separ diverse entiti ale programului, unii pot avea dubl semnificaie; spaii albe sunt caractere cu rol de delimitare sau care cresc lizibilitatea programului surs; operatori simboluri utilizate pentru precizarea operaiilor ce se efectueaz; constante valori fixe reprezentnd valori numerice, ntregi sau reale, caractere sau iruri de caractere.

U3.2.1. Identificatori Identificatorii limbajului C++, ca i n limbajul C standard, sunt formai cu ajutorul caracterelor alfanumerice i liniua de subliniere (underscore), _. Acetia denumesc tipuri de date, variabile, funcii, operatori, instruciuni etc. 42

Primul caracter al unui identificator nu poate fi o cifr. Exemple Raza raza mesaj _maxx a5 5a A_B_C A%B // valid // valid // valid // valid // valid // invalid, primul caracter este cifr // valid // invalid, caracterul % nu poate fi folosit ntr-un // identificator

Limbajul C/C++ este case sensitive, adic face diferen ntre majuscule i minuscule, astfel, n exemplele date anterior, numele Raza este diferit de raza. Din mulimea identificatorilor posibili, se remarc cuvintele cheie (reserved keywords) ale limbajului, identificatori a cror semnificaie este predefinit i nu poate fi modificat de programator. Standardul ANSI C prevede un set de 32 de cuvinte cheie. La acestea, standardul ANSI C++ aduce completri. Cuvintele cheie ale limbajului C++ sunt prezentate n Tabelul nr. 3.1. Cuvintele cheie din tabel care ncep cu semnul underscor reprezint variabile interne. Tabelul nr. 3.1. Cuvinte cheie ale limbajului C++ Cuvinte cheie ale limbajului C++ _asm cdecl default enum _fastcall huge _loadds _pascal return _ss typedef while asm char delete _es float if long pascal _saveregs static union auto class do _export for inline _near private _seg struct unsigned break const double extern friend Int Near protected short switch virtual case continue _ds _far goto _interrupt new public signed template void _cdecl _cs else far _huge interrupt operator register sizeof this volatile

43

U3.2.2. Semne de punctuaie i caractere speciale Semne de punctuaie i caractere speciale constituie un set de caractere cu diferite utilizri, care n funcie de poziia ocupat n textul programului surs pot determina aciunile care vor fi executate. Aceste caractere sunt: [ ] ( ) { } * , : = ; ... # Unele caractere pot desemna operatori (ca de exemplu [ ] * , =) altele nu desemneaz o operaie, ci delimiteaz zone n alctuirea codului surs. Spre exemplu, caracterul ; (punct i virgul) marcheaz sfritul unei instruciuni, iar { i } (paranteze acolade) marcheaz nceputul i respectiv sfritul unui bloc de instruciuni. Caracterul # nsoete numai directivele de preprocesare. Semnificaia i modul de utilizare al acestor caractere se va preciza n capitolele urmtoare. U3.2.3. Spaii albe Spaiile albe sunt caractere speciale care, dei nu sunt afiabile, produc efecte n afiarea textului. Aceste caractere sunt: space (are valoarea 32 n codul ASCII), tab (are valoarea 9 n codul ASCII), newline (are valoarea 10 codul ASCII), vertical-tab (are valoarea 11 n codul ASCII), formfeed (are valoarea 12 n codul ASCII), carriage-return (are valoarea 13 n codul ASCII). Aceste caractere sunt interpretate ca separatori cnd sunt plasate ntre entiti diferite ale programului sau ca i caractere dac intr n alctuirea irurilor de caractere. Sunt situaii n care aceste caractere se folosesc pentru a crete lizibilitatea programului surs, caz n care ele vor fi ignorate de compilator.

Observaie Operatorii i constantele vor fi prezentate n capitole viitoare.

U.3.3. Structura programului C/C++ Aciunile efectuate de un program C/C++ se pot grupa respectnd algoritmul transpus, programul fiind structurat n module, fiecare avnd un rol bine definit. Fiecare aciune este determinat de o instruciune. O succesiune de instruciuni poate fi grupat ntr-un bloc numit funcie.

44

Structura general a unui program este alctuit, n general, din 3 zone: I < directive de preprocesare > II < declaraii globale > III definiii de funcii

Zonele I i II sunt opionale, dar cea de a III-a este obligatoriu s existe. Preprocesorul efectueaz operaii nainte de compilarea codului, indicate prin aa numite directive de preprocesare, marcate totdeauna de caracterul #. Ele produc modificri n codul care va fi compilat, cum ar fi inserarea unor fiiere fie din biblioteca standard, fie create de utilizator, declararea de macrodefiniii, etc. Declaraiile globale pot conine definiii de tipuri de date, prototipuri de funcii, declaraii de variabile globale. Programul trebuie s conin cel puin o funcie, denumit main(), execuia programului ncepnd cu aceast funcie. Funcia main() este unic, ea nu poate fi supradefinit. Restul funciilor pot efectua diferite aciuni, ele putnd fi definite de utilizator, sau s fie preluate din bibliotecile de funcii C/C++. Funciile n C/C++, spre deosebire de alte limbaje, cum ar fi Pascal, nu pot include definirea altor funcii. Deci funciile sunt definite n afara oricrei funcii. Definiia unei funcii are urmtoarea structur: <tip_r> nume_functie (< lista_parametri >) { <declaratii locale > secventa de instructiuni } tip_r precizeaz tipul rezultatului funciei. Dac nu este specificat, n mod implicit rezultatul ntors de funcie este o valoare numeric ntreag, tipul de dat fiind int. Dac funcia nu returneaz nici o valoare, acest lucru este precizat prin tipul de dat void. Dac funcia prelucreaz date existente n momentul apelului funciei (date de intrare), aceste date pot fi preluate prin lista de parametri (lista_parametri). Aceasta are urmtoarea sintax: tip_p nume_parametru< , tip_p nume_parametru ,, tip_p nume_parametru > unde tip_p reprezint tipul parametrului, iar nume_parametru un identificator diferit de cuvintele cheie sau cei care au deja o semnificaie n domeniul funciei. Lista parametrilor este ncadrat ntre paranteze, ( ). 45

n cazul n care nu sunt necesari parametri, acest fapt este precizat prin cuvntul cheie void care desemneaz lipsa parametrilor. n lipsa oricrei specificri pentru lista de parametri, n mod implicit compilatorul interpreteaz c lista este void. Apelul funciei (lansarea n execuie a funciei) se face prin precizarea numelui funciei, nsoit de paranteze rotunde n interiorul crora se specific valorile atribuite parametrilor, numite valori efective, dac acetia exist: nume_functie(<valoare_parametru1, valoare_parametru2,, valoare_parametrun>); Este de remarcat faptul c, att la definirea funciei, ct i la apelul funciei, parantezele trebuie sa nsoeasc numele funciei, chiar dac funcia nu are parametri. Corpul funciei este format din declaraii locale i dintr-o succesiune de instruciuni cuprinse ntre acolade, { }. Declaraiile locale, fcute n interiorul unei funcii, pot fi folosite numai n interiorul acelei funcii, ele ncetnd s mai existe odat cu terminarea execuiei funciei. Cteva exemple de definiii de funcii: void functia_1(void) { printf(Se executa functia 1); } void functia_2(int parametru) { printf(Se executa functia 2); } int functia_3(int parametru_1, int parametru_2) { printf(Se executa functia 3); return (parametru_1+parametru_2); } - funcia nu preia parametri i nu ntoarce nici un rezultat.

1.

2.

- funcia preia un parametru i nu ntoarce nici un rezultat.

- funcia preia doi parametri i ntoarce un rezultat.

3.

Apelul (lansarea n execuie) acestor funcii se face astfel: 1. 2. functia_1(); functia_2(100); - apelul funciei fr parametri. - apelul funciei cu un parametru; valoarea preluat de parametru este 100. - apelul funciei cu doi parametri; valorile preluate de parametri sunt 100 i respectiv 500; funcia ntoarce valoare, 600 (100+500), valoare ce poate fi preluat de o variabil sau folosit ntr-o expresie.

3.

functia_3(100, 500);

46

Programul surs poate fi alctuit din una sau mai multe funcii. Acestea pot fi definite ntr-un singur fiier surs, sau n mai multe fiiere surs, acestea putnd fi compilate separat, legturile ntre acestea fiind realizate n faza de link-editare pentru a genera un singur fiier executabil. Noiuni legate de definirea i apelul funciilor vor fi reluate i dezvoltate n capitolele urmtoare.

U3.4. Directive de preprocesare Preprocesorul efectueaz operaii prealabile compilrii, indicate de directivele de preprocesare. Acestea sunt precedate de caracterul #. n mod frecvent sunt utilizate directivele #define i #include. Directiva # define Directiva define este utilizat pentru a asocia un identificator cu un ir de caractere. n etapa de precompilare fiecare apariie a identificatorului va fi nlocuit, caracter cu caracter, cu irul corespunztor. Forma general de utilizare a directivei #define este: #define nume sir de caractere Exemple #define TRUE 1 #define FALSE 0 #define NULL 0 #define MIN 10 #define MAX MIN+100 #define f(a, b) a+b Directiva #define : permite folosirea constantelor simbolice n programe uzual, dar nu obligatoriu, simbolurile sunt scrise cu litere mari nu se termin cu ';' apar n general la nceputul unui fiier surs fiecare apariie a simbolului este nlocuit, caracter cu caracter, cu valoarea sa Observaii Directivele preprocesor ncep cu simbolul # Directivele preprocesor nu se termin cu ';' In mod uzual, directivele preprocesor sunt scrise la nceputul fiierului surs

47

Directiva #include Directiva de preprocesare #include determin includerea unui fiier surs n alt fiier surs. Sintaxa de utilizare are una din formele: #include < nume_fisier > #include nume_fisier Pentru prima variant, fiierul va fi cutat ntr-un director predefinit care conine fiiere header puse la dispoziie de mediul de programare, cea de a doua va cuta fiierul pe calea specificat n numele fiierului. Dac nu e precizat calea fiierului, va fi cutat n directorul curent. Exemple de folosire a directivei #include #include <stdio.h> #include c:\dir1\dir2\fis_meu1.h #include fis_meu2.h // fiierul e cutat n directorul predefinit // fiierul este cutat pe calea c:\dir1\dir2\ // fiierul este cutat n directorul curent

U3.5. Primul program C/C++ n continuare se prezint un exemplul de program, exemplu consacrat ca fiind primul program n mare parte a manualelor de specialitate, fiind urmat de comentarii referitoare la noiunile prezentate pn la acest moment. Exemplu

1 2 3 4 5 6 7

#include <stdio.h> int main(int argc, char* argv[]) { printf("Hello World!\n"); return 0; } Hello World!

La execuia programului se va afia:

Observaii un program n C/C++ trebuie s conin cel puin o funcie i aceasta s se numeasc main(); funcia main(), ca orice funcie poate prelua parametri sau nu, poate returna

48

valoare, sau nu; n exemplul de fa, este o funcie cu parametri i care returneaz valoare; execuia programului ncepe cu execuia funciei main(); execuia programului se face secvenial, instruciune dup instruciune, ncepnd cu prima instruciune din main() i terminnd cu ultima instruciune din main(); identificatorul main nu poate fi folosit n alt scop, el fiind unul dintre cuvintele rezervate; limbajul C/C++ este case sensitive, adic face diferen ntre majuscule i minuscule, astfel c identificatorii Main, MAIN, etc. pot fi utilizai n ce scop i propune utilizatorul; cuvintele cheie, ca de exemplu int, char, return, sunt scrise cu litere mici; fiecare instruciune se termina cu ';' ; irurile de caractere sunt incluse intre ghilimele duble "Hello World!\n"; \n poziioneaz cursorul la nceputul liniei urmtoare, el reprezentnd caracterul cu valoarea 10 n codul ASCII, newline; n linia 1 a programului se indic printr-o directiv de preprocesare, #include, includerea fiierului stdio.h; acesta face parte din biblioteca standard i conine funcii destinate efecturii de operaii de intrare/ieire; printf() este o funcie utilizat pentru afiarea pe ecran a unui mesaj; ea este definit n fiierul stdio.h ; { i } delimiteaz nceputul i sfritul unui bloc-program; return este cuvnt cheie i reprezint o instruciune ce ncheie execuia funciei main(); caracterele albe, cum ar fi spaiul, tab sau rnd gol (rndul nr. 2) sunt ignorate de compilator.

U3.6. Utilizarea comentariilor La scrierea programelor surs este util n numeroase situaii s se introduc anumite comentarii care s explice eventuale secvene de instruciuni. Comentariile sunt ignorate de compilator putnd conine orice text, ele fiind utile doar programatorului. Comentariile se pot scrie astfel: comentarii pe un rnd sunt precedate de caracterele // comentarii pe mai multe rnduri sunt marcate ntre caracterele /* i */

49

Exemplu

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

//exemplificarea utilizrii comentariilor /* Acesta este un comentariu scris pe mai multe linii. Comentariile sunt ignorate de compilator. */ #include <stdio.h> int main() { // comentariu pe o linie printf("Hello World !\n"); printf("Hello World !\n"); return 0; // instruciunea return ncheie execuia unei funcii printf("Hello World !\n"); /* aceasta linie nu se va executa deoarece se afla dup instruciunea return */ }

Observaii pe rndurile 1, 10 i 13 sunt inserate comentarii pe un rnd; comentariile scrise pe mai multe rnduri sunt inserate pe rndurile 25, respectiv 1416 ; comentariile sunt ignorate de compilator

U.3.7. Tipuri de date fundamentale Tipul unei date determin dimensiunea zonei de memorie ocupat i valorile pe care le poate lua. Tipurile datelor se pot grupa n: tipuri fundamentale; tipuri derivate. Tipurile de date fundamentale cuprind tipurile aritmetice de baz i tipul void. Exist patru tipuri aritmetice de baz, specificate prin cuvintele cheie: char, int, float i double. Gama de valori poate fi extins prin modificatori de tip desemnai prin cuvintele cheie: signed, unsigned, short, long. Tipurile ntregi ce se obin prin combinarea tipurilor de baz cu modificatorii de tip sunt prezentate n Tabelul nr. 3.2, iar cele reprezentate n virgul mobil n Tabelul nr. 3.3. Tipul fundamental void indic absena oricrei valori i se utilizeaz n urmtoarele situaii: declaraia unei funcii fr parametri sau care nu returneaz un rezultat, tipul pointer 50

generic i conversii de tip cu operatorul cast pentru pointeri. Pentru determinarea numrului de octei de memorie folosii pentru stocarea datelor se poate folosi operatorul sizeof (va fi prezentat n capitolul destinat operatorilor). Iat cteva exemple de expresii care returneaz ca valoare spaiul de memorie ocupat de date de diferite tipuri: sizeof (long int); // expresia returneaz valoarea 4 sizeof (unsigned char) // expresia returneaz valoarea 1 sizeof (long double) // expresia returneaz valoarea 8 sau 10

Observaii Modul de memorare al acestor tipuri de date depinde de varianta de implementare a limbajului C/C++. De exemplu, tipul int este reprezentat pe 2 byte n unele versiuni i pe 4 byte n altele. n plus, modul de implementare poate fi modificat prin utilizarea modificatorilor : signed - cu semn (pentru char, int, long int) unsigned - fr semn (pentru char, int, long int) short - scurt (pentru int) long - lung (pentru int i double) Tabelul nr. 3.2. Tipuri de date ntregi Tip char = signed char unsigned char short int = signed short int int = signed int Spaiu de memorie ocupat 8 bii 8 bii 16 bii 16/32 bii Domeniu de valori -128127 0255 -3276832767 -3276832767 / -21474836482147483647 unsigned int = unsigned short int long int = signed long int unsigned long int 16/32 bii 32 bii 32 bii 065535 / 04294967295 -21474836482147483647 04294967295

51

Tabelul nr.3.3. Tipuri de date n virgul mobil Tip float Spaiu de memorie ocupat 32 bii Domeniu de valori +/-(3.4E-383.4E+38) precizie 7 cifre double long double 64 bii 80 bii +/-(1.7E-3081.7E+308) precizie 15 cifre +/-(3.4E-49321.1E4932) precizie 19 cifre

Exemple int ordonata, abscisa; unsigned int Lungime; char caracter; double RAZA; long double x, y, z;

Observaii Variabilele ordonata i abscisa se vor aloca n memorie, pentru fiecare utilizndu-se cte 2/4 byte (depinde de compilatorul folosit); astfel, ele vor putea lua valori n intervalul -3276832767 sau -21474836482147483647 Pentru variabila Lungime se aloc tot 2 sau 4 byte de memorie, n funcie de compilatorul folosit, iar domeniul de valori este 065535, respectiv 04294967295 Pentru variabila caracter se aloc un byte, valorile fiind cuprinse n intervalul -128127 Pentru variabila RAZA se aloc 8 byte, valorile fiind cuprinse n intervalul +/-(1.7E-3081.7E+308) Pentru variabilele x, y i z se aloc 8 sau 10 byte, n funcie de compilatorul utilizat. Celor cinci tipuri de date fundamentale: char, int, float double, void definite n limbajul C, limbajul C++ le adaug nc dou, i anume tipurile bool i wchar_t. n prezentul curs vor fi utilizate doar tipurile specifice limbajului C.

52

Exemple /*************************************************************************** Exemplu1 3.1. - Afiarea unor mesaje ***************************************************************************/ #include <stdio.h> void main(void) { printf("Salut !"); } /**************************************************************************/ La execuia programului se afieaz: //functia printf() - afiseaza pe ecran sirul de caractere "Salut !" //irurile de caractere se ncadreaz ntre ghilimele //directiva de preprocesare - in fiierul stdio.h este definita // functia printf()- functie de afisare //orice program C/C++ trebuie s conin o funcie main() - cu // ea ncepe execuia programului; funcia main() este unic

/*************************************************************************** Exemplu1 3.2. - Afiarea unor mesaje ***************************************************************************/ #include <stdio.h> void main(void) { printf("Salut !"); printf("Salut !"); }

//functia printf() - afiseaza pe ecran sirul de caractere "Salut !" //functia printf() - afiseaza pe ecran sirul de caractere "Salut !"

/**************************************************************************/ La execuia programului se afieaz:

53

/*************************************************************************** Exemplu1 3.3. - Afiarea unor mesaje ***************************************************************************/ #include <stdio.h> void main(void) { printf("Salut !"); printf("\nSalut !"); } /**************************************************************************/ La execuia programului se afieaz:

// secvena \n inclus n irul de caractere are ca efect // mutarea cursorului la nceputul rndului urmtor

/*************************************************************************** Exemplu1 3.4. - Afiarea unor mesaje ***************************************************************************/ #include <stdio.h> #include <conio.h> void main(void) { printf("Salut !"); printf("\nSalut !"); getch(); // in fiierul conio.h este definita functia getch() - functie // care citete de la tastatur un caracter

//functia getch() citete de la tastatur un caracter

/* caracterul citit este ignorat, funcia fiind apelat pentru a ntrerupe execuia programului pn la apsarea unei taste; n absena ei, programul se execut, dar utilizatorul nu poate vizualiza mesajele afiate datorit faptului c, odat cu terminarea programului se nchide i fereastra n care au fost afiate mesajele. */ } /**************************************************************************/ La execuia programului se afieaz: (fereastra se nchide dup apsarea unei taste)

54

/*************************************************************************** Exemplu1 3.5. Utilizarea comentariilor ***************************************************************************/ /* Acesta este un comentariu scris pe mai multe linii. Comentariile sunt ignorate de compilator */ #include <stdio.h> #include <conio.h> void main() { // comentariu pe o linie printf("Primul mesaj !\n"); printf("Al doilea mesaj !\n"); getch(); return; // instruciunea return ncheie execuia functiei main() printf("Al treilea mesaj !\n"); /* aceasta linie nu se va executa deoarece se afla dup instruciunea return*/

} /**************************************************************************/ La execuia programului se afieaz: comentariile sunt ignorate de compilator, deci ele nu produc nici un efect la execuia programului; instruciunile aflate dup instruciunea return (instruciunea return ncheie execuia funciei main, deci i a programului) nu sunt executate, astfel c irul "Al treilea mesaj !\n" nu este afiat pe ecran.

Rezumat Pentru realizarea unui program (executabil), programatorul scrie programul surs ca fiier text cu extensia .cpp, prin compilare i link-editare obinndu-se apoi executabilul; Numele (identificatorii) folosite ntr-un program C/C++ sunt formate din literele alfabetului englez, mici i mari, cifre i caracterul underscore (_); Limbajul C/C++ este case-sensitive; Exist un set de cuvinte rezervate (cuvinte cheie) care au o semnificaie prestabilit care nu poate fi modificat; Spaiile albe sunt ignorate de compilator, dar mresc lizibilitatea programului; Orice program C/C++ trebuie s conin cel puin o funcie; aceasta se numete main() care este unic (nu se poate supradefini).

55

La definirea unei funcii se stabilete numele acesteia, tipul valorii returnat de aceasta, lista de parametrii; corpul funciei este ncadrat ntre acolade, {}; Apelul (execuia) funciei se face prin numele acesteia nsoit de paranteze rotunde, ntre care se precizeaz, dac este cazul, valorile efective ale parametrilor efectivi; Pentru folosirea unor funcii definite n fiiere bibliotec (header) se folosete directiva de preprocesare #include; Pentru definirea de constante cu nume se poate folosi directiva de preprocesare #define; La scrierea programelor surs este util n numeroase situaii s se introduc anumite comentarii; acestea se pot scrie pe un rnd (precedate de caracterele //) sau pe mai multe rnduri (marcate ntre caracterele /* i */); Reprezentarea datelor n limbajul C se face folosind tipurile de date fundamentale: char, int, float i double; Tipul fundamental void indic absena oricrei valori; Numrul de octei folosit n reprezentarea unor date i domeniul de valori pot fi modificate prin cuvintele cheie: signed, unsigned, short, long. Determinarea numrului de octei de memorie folosii pentru stocarea datelor se poate determina folosind operatorul sizeof.

Test de autoevaluare 1. Un identificator poate conine: a. orice caracter afiabil; b. numai litere c. liniua de subliniere (underscor) d. cifre e. maxim 10 caractere 2. Urmtoarele nume de variabile sunt incorecte: a. acesta_este_un_nume; b. a1; c. 1a2b3c; d. abc def; e. _nume; 3. Urmtoarele nume de variabile sunt incorecte: a. float; b. variabila; c. MAX; d. !abc;

56

4. Care dintre urmtoarele afirmaii sunt corecte: a. un identificator poate conine litere mici si mari; b. un identificator poate conine orice caracter; c. un identificator nu poate conine cifre; d. un identificator poate ncepe cu caracterul '.' (punct); e. numarul caracterelor dintr-un identificator nu e limitat. 5. Care dintre urmtorii identificatori sunt coreci: a. a1b2c3; b. MAIN; c. double; d. raza; e. arie cerc. 6. Care dintre urmtoarele denumiri reprezint tipuri de date predefinite: a. double; b. main; c. char; d. boolean; e. string; 7. Care dintre urmtoarele afirmaii sunt corecte: a. limbajul C/C++ este case-sensitive b.sizeof reprezint un tip de date predefinit; c.sizeof este un operator care determin numrul de octei ocupai n memorie; d. cuvntul void desemneaz un tip de date 8. Care dintre urmtoarele afirmaii sunt incorecte: a. orice program n C/C++ trebuie s conin o funcie main(); b. ntr-un program C/C++, funcia main() poate avea mai multe definiii c. corpul unei funcii se ncadreaz ntre paranteze ptrate [] d. directiva #define se folosete pentru definirea tipurilor de date

ntrebri. Exerciii. Probleme. 1. Descriei componentele i rolul sistemului de operare. 2. Scriei un program care s afieze urmtorul text: Program EXEMPLU. Limbajul de programare folosit: C++ Autor: studentul .... 3. Scriei un program care s afieze un caracter, un ir de caractere, o valoare numeric ntreag i o valoare numeric real.

57

Unitatea de nvare U.4. CONSTANTE. VARIABILE.

Cuprins Introducere .................................................................................................................... 58 Obiectivele unitii de nvare ..................................................................................... 58 U4.1. Constante ............................................................................................................. 59 U4.1.1. Constante ntregi ................................................................................... 59 U4.1.2. Constante n virgul mobil .................................................................. 60 U4.1.3. Constante caracter ................................................................................. 61 U4.1.4. Constante ir de caractere ..................................................................... 62 U4.2. Variabile .............................................................................................................. 63 U4.2.1. Declaraii de variabile ........................................................................... 63 U4.2.2. Atributele variabilelor........................................................................... 65 U4.2.3. Modificatori de acces ............................................................................ 69 Exemple ........................................................................................................................ 69 Rezumat ........................................................................................................................ 73 Test de autoevaluare ..................................................................................................... 74 ntrebri, exerciii i probleme ...................................................................................... 76

Introducere Programele prelucreaz date care pot fi de diferite tipuri. Unele i pstreaz valorile nemodificate pe parcursul execuiei programului, purtnd numele de constante. n afara acestora, se vehiculeaz date introduse de la tastatur, preluate din fiiere sau sunt obinute n urma evalurii unor expresii. Acestea se stocheaz n locaii de memorie, valorile lor putnd fi modificate pe parcursul execuiei programului. Ele se numesc variabile. Constantele i variabilele se numr printre elementele de baz ale limbajelor C/C++ . Reprezentarea lor se face n strns legtur cu tipurile de date definite. Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Tipurile i sintaxa specifice constantelor literale; Semnificaia noiunii de variabil; modul de declarare i atributele variabilelor; Modificatori de acces ai variabilelor. 58

Durata medie de parcurgere a celei de a patra uniti de nvare este de 2 ore.

U4.1. Constante Constantele (constante literale) sunt valori fixe (numerice, caractere sau iruri de caractere), care nu pot fi modificate n timpul execuiei programului. Tipul constantei este determinat de compilator pe baza valorii i sintaxei utilizate, putnd avea oricare dintre tipurile predefinite de date. Ele rmn n memorie pe toat durata execuiei programului. U4.1.1. Constante ntregi Tipul constantei este determinat pe baza valorii. Astfel, de exemplu: dac valoarea numeric a constantei se ncadreaz n domeniul de valori al tipului int, atunci tipul implicit al constantei este int (chiar dac valoarea ar putea fi reprezentat folosind tipul char, ca de exemplu 15); dac valoarea depete domeniul tipului int dar se ncadreaz n domeniul de valori al tipului long, reprezentarea va fi ca dat long (de exemplu valoarea 99999 este reprezentat ca dat de tip long); dac valoarea constantei depete domeniul de valori al tipului long, chiar dac nu conine parte zecimal, ea va fi reprezentat n mod implicit ca o dat de tip double (de exemplu, constanta 98765432100). Se poate fora preluarea constantei cu alt tip dect cel implicit prin utilizarea unui sufix (U sau u pentru unsigned, respectiv L sau l pentru long). Constantele ntregi pot fi zecimale (cu reprezentare n baza 10), octale (cu reprezentare n baza 8) sau hexazecimale (cu reprezentare n baza 16). Constante zecimale (baza 10) Constantele zecimale se disting prin faptul c prima cifr este diferit de 0. Exemple 23 -555L 23u 3276L 32768 32768U 77UL // tip int // tip long int // tip unsigned int // tip long int // tip int sau long int, funcie de compilatorul folosit // tip unsigned int // tip unsigned long int

59

Constante octale (baza 8) Constantele octale sunt valori ntregi cu reprezentare n baza 8. Convenia de scriere este ca prima cifr s fie 0 (zero). Fiind vorba de reprezentare n baza 8, cifrele 8 i 9 sunt ilegale. Exemple -067 067u 02000000000 055UL 089 // tip int // tip unsigned int // tip long int // tip unsigned long // eroare, prima cifr indic reprezentarea n octal // i numrul include cifrele 8 i 9

Constante hexazecimale (baza 16) Constantele hexazecimale, cu reprezentare n baza 16, se disting prin prefixul 0x sau 0X. Pot conine cifre mai mari de 9 (af, sau AF). Exemple 0x7FFF 0X8A0L 0xffu 0x1000L 0xFFul U4.1.2. Constante n virgul mobil Constantele n virgul mobil sunt valori reale a cror reprezentare conine n general urmtoarele cmpuri: parte ntreag punct zecimal parte fracionar e sau E i un exponent cu semn (opional) sufix de specificare a tipului: f sau F (foreaz tipul float) sau l sau L (foreaz tipul long double). Se pot omite partea ntreag sau partea fracionar (dar nu amndou), punctul zecimal sau litera e (E) i exponentul (dar nu amndou). Tipul implicit pentru constantele n virgul mobil este tipul double. Se poate fora reprezentarea ca tip float, dac valoarea se ncadreaz n domeniul de valori corespunztor, prin ataarea sufixului f sau F. // tip int // tip long int // tip unsigned int // tip long int // tip unsigned long int

60

Exemple 2.1 11.22E5 -.33e-2 .5 1. 1.f 0.L U4.1.3. Constante caracter Constantele caracter sunt reprezentate de unul sau mai multe caractere ncadrate de apostrofuri, de exemplu: a, A, \n i ele sunt de tip char. Pentru a specifica o serie de caractere neafiabile, delimitatorii (), (), caracterul (\), etc. se utilizeaz aa numitele secvenele escape (secvene de evitare) (vezi Tabelul nr. 4.1.) care sunt formate din caracterul backslash (\) nsoit de o liter sau o constant numeric octal sau hexazecimal. Valoarea numeric corespunde valorii din codul ASCII a caracterului reprezentat. Tabelul nr. 4.1. Secvene escape Secven \a \b \t \n \v \f \r \ \ \? \\ \o \xH Valoare (hexa) 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x22 0x27 0x3F 0x5C Caracter alarm (bell) BS TAB LF VT FF CR ? \ orice caracter orice caracter Descriere semnal sonor backspace tab orizontal linefeed tab vertical formfeed carriage return ghilimele apostrof semnul ntrebrii backslash ir de cifre octale ir de cifre hexazecimale // valoare 2,1 (tip double) // valoare 11,22 x 105 (tip double) // valoare 0,33 x 10-2 (tip double) // valoare 0,5 (tip double) // valoare 1 (tip double) // valoare 1 (tip float) // valoare 0 (tip long double)

61

Exemplu de utilizare a constantelor caracter #include <stdio.h> void main() { putch(?); putch(63); printf(\n%c,\077); printf(\n%c,\x3F); }

// se afieaz caracterul ? // se afieaz caracterul ? , 63 fiind valoarea // corespunztoare n codul ASCII // se afieaz caracterul ? // se afieaz caracterul ?

Observaii Limbajul C++ permite specificarea unor constante alctuite din dou caractere, reprezentate pe 16 bii (tipul int) ca n exemplul care urmeaz: ab \t\t // reprezentarea n memorie ca ntreg de valoare 25185 // sau n hexazecimal 0x62 0x61 // reprezentarea n memorie ca ntreg de valoare 2313 // sau n hexazecimal 0x09 0x09

Primul caracter este memorat n octetul mai puin semnificativ. Constantele duble pot ridica probleme de portabilitate, ele nefiind recunoscute de alte compilatoare, de aceea este recomandabil a fi evitate.

U4.1.4. Constante ir de caractere Constantele iruri de caractere sunt alctuite dintr-un numr oarecare de caractere, ncadrate ntre ghilimele. irurile de caractere se memoreaz n tablouri de tipul char, cu dimensiune egal cu numrul de caractere cuprinse ntre ghilimele, la care se adaug terminatorul de ir \0. De exemplu, irul constant STRING este alocat n memorie ca n Fig. 4.1.

Fig. 4.1. Alocarea n memorie a unui ir de caractere constant

62

Caracterele care alctuiesc irul pot fi secvene escape: \tMesaj 1\n\tMesaj 2 irurile constante adiacente se concateneaz i formeaz un singur ir: Programare orientata pe obiecte Pentru scrierea irurilor lungi se poate utiliza simbolul (\) care semnaleaz continuarea irului pe rndul urmtor: Exemplu de sir \ scris pe doua rnduri

Observaii Reprezentarea n memorie a caracterului a este diferit de reprezentarea irului a. Caracterul este reprezentat pe un octet, n timp ce irul de caractere este format din caracterul a i caracterul \0, deci ocup doi octei n memorie.

U4.2. Variabile U4.2.1. Declaraii de variabile Variabila este un identificator asociat cu o locaie de memorie n care se memoreaz valori ce pot fi modificate pe parcursul existenei ei. Toate variabilele trebuie declarate nainte de a fi folosite. Declaraia unei variabile (obiect) precizeaz tipul datei i numele (identificatorul) cu care va fi referit, sintaxa fiind: tip_variabila nume_variabila; unde: - tip_variabila este un specificator de tip de date oarecare, standard (char, int, etc.), pointer sau definit de utilizator. - nume_variabila este orice identificator care nu a primit alt semnificaie n domeniul de existen al variabilei. De exemplu, se poate declara o variabil de tip int cu numele variabila_mea: int variabila_mea;

63

alocarea ei n memorie fiind reprezentat n Fig. 4.2.

Fig. 4.2. Alocarea unei variabile n memorie

Alte exemple de declarare de variabile: float r; unsigned int n; // declararea variabilei r de tip float, // declararea variabilei n de tip unsigned int

Se pot face declaraii de variabile cu iniializare utiliznd sintaxa: tip_var nume_var= valoare_initiala; sau se pot declara mai multe variabile de acelai tip utiliznd sintaxa: tip_var nume_var1<=val_initiala1>,< nume_var2<= val_initiala2>>,...; Exemple de declare a variabilelor: int variabila_mea=12000; double real=2.5; char c1, c2=a, ch; // declararea unei variabile de tip int iniializat cu // valoarea 12000 (vezi Fig. 4.1.) // declararea variabilei n virgul mobil de tip double, // iniializat cu valoarea 2.5 // declararea a trei variabile de tip char, c1, c2 i ch, variabila c2 // fiind iniializat cu valoarea a

Declaraia unei variabile are ca efect, la execuia programului, rezervarea unui numr de octei n memorie necesar reprezentrii tipului declarat al variabilei. Dac declaraia este cu iniializare, n acea locaie se va nscrie valoarea specificat.

Observaii Adresa de memorie la care se aloc o variabil nu poate fi precizat de utilizator, ci compilatorul face alocarea n funcie de memoria disponibil. Utilizatorul poate afla adresa la care a fost alocat o variabil cu ajutorul 64

operatorului & aplicat numelui variabilei. De exemplu: &variabila_mea Chiar dac nu poate impune adresa la care se aloc o variabil, prin locul n program n care se face declaraia sau specificatorii folosii, utilizatorul poate stabili zona de memorie n care se face alocarea. U4.2.2. Atributele variabilelor Atributele unei variabile sunt: tipul datei poate fi tip fundamental sau definit de utilizator i determin structura, gama de valori, dimensiunea spaiului ocupat n memorie; clasa de memorare stabilete zona de memorie n care se va plasa informaia asociat identificatorului (segment de date, registru, stiv, heap) i delimiteaz durata sa de alocare; domeniul reprezint poriunea de program n care poate fi accesat informaia asociat identificatorului, el fiind determinat de poziia declaraiei; durata de via a identificatorului reprezint perioada ct exist efectiv n memorie i este corelat cu clasa de memorie; legtura precizeaz modul de asociere a unui identificator cu un anumit obiect sau funcie, n procesul de editare a legturilor. Atributele se pot asocia identificatorilor n mod implicit, n funcie de poziia i sintaxa declaraiei, sau explicit prin utilizarea unor specificatori. Poziia declaraiei determin cele dou domenii de existen fundamentale: Domeniul bloc (local) - Identificatorii cu domeniu bloc se numesc locali i sunt rezultatul unor declaraii n interiorul unui bloc (au domeniul cuprins ntre declaraie i sfritul blocului) sau sunt parametrii formali din definiia unei funcii (au ca domeniu blocul funciei). Domeniul fiier (global) - Identificatorii cu domeniu fiier se numesc globali i sunt declarai n afara oricror funcii (domeniul este cuprins ntre declaraie i sfritul fiierului). #include <stdio.h> // zona declaraiilor globale float functie (int, float); int a; // definiii de funcii void main (void) { unsigned char c; // prototipul funciei // se declar variabila cu numele a, creia i se rezerv o zon de // memorie de 2/4 octei (16/32 bii) localizat n segmentul de // date, deoarece declaraia se afl n zona declaraiilor globale // se declar variabila automatic cu numele c creia i se rezerv // un octet n segmentul de stiv, variabila fiind o variabil // local

65

float r=2.5; // } float functie (int n, float q) { a=100; r=1.5 *a; // }

// se declar variabila automatic cu numele r creia i se rezerv // 4 octei n segmentul de stiv, variabila fiind o variabil local // care este iniializat cu valoarea 2.5 // se declar variabilele locale n i q, crora li se aloc 2, // respectiv 4 octei n segmentul de stiv // variabila a este declarat global, deci poate fi utilizat // de orice funcie definit n fiier // eroare, variabila r nu poate fi folosit n funcie(), ea // fiind declarat local funciei main(), deci nu poate fi // referit dect n aceasta

Observaii ntr-un bloc inclus n domeniul unei declaraii este permis o declaraie local a aceluiai identificator, asocierea fiind ns fcut unui alt obiect cu alocarea altei zone de memorie. Spre deosebire de C, care impune gruparea declaraiilor locale la nceputul unui bloc, C++ permite plasarea declaraiilor n interiorul blocului, bineneles nainte de utilizarea obiectului void main (void) { for (int i=5; i<8; i++) {} for {i=0; i<5; i++) {} }

// declararea lui i este imediat urmat de utilizarea sa // i a fost declarat anterior

Clasa de memorare se poate preciza prin specificatorii auto, static, extern, register. Aceti specificatori precizeaz modul de alocare a memoriei i timpul de via pentru variabile i legtur pentru funcii i variabile. auto Declaraia auto specific o variabil automatic i se poate utiliza pentru variabile cu domeniul local (cu spaiu alocat pe stiv). Variabilele ce se declar n interiorul unui bloc sunt implicit automatice, astfel c declaraia auto este rar folosit.

66

void fct() { auto float r; double s; ... }

// declararea unei variabile automatice cu declarare // explicit // declararea unei variabile implicit automatic

static Declaraia static a unei variabile locale foreaz durata static fr a modifica domeniul de utilizare. Variabilele statice i pstreaz valoarea ntre dou apeluri succesive ale blocurilor care le conin, asigurndu-se n acelai timp o protecie, dar ele nu pot s fie accesate din blocuri care nu constituie domeniul lor de existen. Variabilele statice pot fi declarate cu iniializare, n caz contrar, implicit se iniializeaz cu valoarea 0, similar variabilelor globale. #include <stdio.h> int fct() { static int a=2; return (a++); }

// se declar o variabil local funciei, cu durat static

void main(void) { int n; n=fct(); printf (\n Prima atribuire : n= %d, n); n=fct(); printf (\n A doua atribuire : n= %d, n); }

Programul afieaz: Prima atribuire : n= 3 A doua atribuire : n= 4 // la primul apel al funciei, variabila a are valoarea // iniial 2, ea fiind apoi incrementat // la al doilea apel al funciei, variabila a are la // nceput valoarea 3 (valoare datorat apelului // anterior al funciei), valoarea fiind apoi // incrementat

67

register Declaraia register are ca efect memorarea variabilei ntr-un registru al procesorului i nu n memorie, avnd ca rezultat creterea vitezei de execuie a programului. Aceste variabilele pot fi variabile locale, nestatice, de tip int sau char. Numai dou variabile pot fi memorate simultan n registre, n cazul existenei mai multor declaraii register, cele care nu pot fi onorate vor fi tratate de compilator ca variabile obinuite. register char c; // declararea variabilei c cu memorare ntr-un registru al // procesorului

extern Specificatorul extern indic legtura extern i asigur durata static pentru variabile locale i globale sau pentru funcii (acestea au implicit legtur extern i durat static). Pentru identificatorii cu legtur extern sunt permise mai multe declaraii de referin, dar o singur definiie. De exemplu, n cazul unui proiect n care o variabil se folosete n mai multe fiiere, ea se va defini global ntr-un fiier, n celelalte fiind declarat extern fr definire. Compilatorul i va aloca o singur dat memorie. Ca exemplu, se consider programul format din dou fiiere surs Ex_prj.cpp i Ex_prj1.cpp. Variabila m declarat n fiierul Ex_prj1.cpp este folosit n fiierul Ex_prj.cpp prin realizarea legturii externe pentru aceast variabil. // Fiier Ex_prj.cpp #include <stdio.h> extern int m; void main(void) { scanf(%d, &m); printf(\nm= %#x, m); } // Fiier Ex_prj1.cpp ... int m ; // se declar legtur extern pentru variabila m

// declaraia variabilei m

n exemplul anterior, cele dou fiiere, Ex_prj.cpp i Ex_prj1.cpp, se includ ntr-un proiect utiliznd opiunea project a meniului principal din mediul de programare C/C++. Variabila m este declarat global ntr-unul dintre fiiere, ea putnd fi referit din cellalt fiier datorit specificrii legturii extern .

68

U4.2.3. Modificatori de acces Modificatorii de acces ce pot fi utilizai sunt const i volatile i ei pot controla modul de modificare a unei variabile. const Variabilele const (constante cu nume) nu pot fi modificate pe parcursul execuiei unui program. Instruciunile care ncearc modificarea variabilelor const genereaz erori la compilare. const int a=99; a++; a=5; // declaraia variabilei a const // eroare, a nu se poate modifica fiind declarat const // eroare, a nu se poate modifica fiind declarat const

Observaii Variabilele const sunt n mod frecvent folosite atunci cnd: n program se utilizeaz valori constante n mod repetat, fiind mai comod s fie precizate prin numele lor; se dorete protejarea parametrilor funciilor care au fost transferai prin adres sau referin.

volatile Variabilele volatile pot fi modificate din exteriorul programului (de exemplu servirea unei ntreruperi).

Exemple

/*************************************************************************** Exemplul 4.1. - Se scrie un program n care se afieaz informaii referitoare la variabile. Se afieaz valoarea, adresa i numrul de octei ocupai n memorie de ctre variabile. ***************************************************************************/

69

Adresa variabilei a #include <stdio.h> #include <conio.h> void main(void) { int a=10, b=20; Valoarea variabilei a

Se afieaz numrul de octei utilizai n reprezentarea variabilei a

// declararea a dou variabile cu iniializare

printf("\na = %d, &a = %u, sizeof(a) = %d", a, &a, sizeof(a)); printf("\nb = %d, &b = %u, sizeof(b) = %d", b, &b, sizeof(b)); getch(); } Valoarea variabilei b Adresa variabilei b

Se afieaz numrul de octei utilizai n reprezentarea variabilei b

***************************************************************************/ La execuia programului se afieaz:

- valoarea afiat pentru variabile este valoarea de iniializare; - adresa de memorie la care este alocat o variabil poate fi aflat cu ajutorul operatorului & (adres); - numrul de octei utilizai n reprezentarea unei variabile se poate afla cu ajutorul operatorului sizeof; numrul de octei alocai unei variabile este determinat de tipul variabilei (n cazul de fa tipul celor dou variabile este int se reprezint pe 4 octei).

70

/*************************************************************************** Exemplul 4.2. - Se scrie un program n care : - se definesc funcii de calcul al ariei i lungimii unui cerc. - n funcia main se va exemplifica folosirea funciilor ***************************************************************************/ #include <stdio.h> I. Zona #include <conio.h> directivelor de preprocesare #define PI 3.1415 II. Zona declaraiilor globale float aria(float); float lungime(float); int r = 5; void main(void) { float raza, a, l; III. Definiii de funcii printf("\nIntroduceti valoarea razei: "); scanf("%f", &raza); a = aria(raza); l = lungime(raza); printf("\nCercul are:"); printf("\nraza = %f ", raza); printf("\naria = %f ", a); printf("\nlungimea = %f", l); printf("\nCercul are:"); printf("\nraza = %f ", r); printf("\naria = %f ", aria(r)); printf("\nlungimea = %f", lungime(r)); getch(); } float aria(float r) { float a; a = PI * r * r; return a; } float lungime(float r) { float l; l = 2 * PI * r; return l; } Declaraie local funciei aria() Secven de instruciuni Declaraii locale funciei main()

Declaraie local funciei lungime()

71

/*************************************************************************** Exemplul 4.3. - Se scrie un program n care se exemplific atributele variabilelor : - clasa de memorare - domeniu - durata de via ***************************************************************************/ #include <stdio.h> #include <conio.h> int a=5; void f1(void) { printf("\na=%d",a); } void f2(void) { int a=7; printf("\na=%d", a); } void main() { int b=10, c=20; variabil local - alocat pe stiv - durata de via - execuia funciei - domeniu: funcia variabil global - alocat n segmentul de date - durata de via - execuia programului - domeniu: fiier

variabile locale funciei main() - alocate pe stiv - durata de via - funcia main() - domeniu: funcia main()

printf("\na=%d, b=%d, c=%d", a, b, c); variabile locale blocului de instruciuni - alocate pe stiv - durata de via - execuia blocului de instruciuni - domeniu: blocul de instruciuni

{ int b=100, d=1000;

printf("\na=%d, b=%d, c=%d, d=%d", a, b, c, d); } printf("\na=%d, b=%d, c=%d", a, b, c); printf("\na=%d, b=%d, c=%d, d=%d", a, b, c, d); //- eroare, variabila d nu mai exista puts("\nSe executa functia f1"); f1(); puts("\nSe executa functia f2"); f2(); }

72

/*************************************************************************** Exemplul 4.4. - Exemplu de folosire a variabilelor statice ***************************************************************************/ #include <stdio.h> #include <conio.h> void func(void) { int a=10; static int b=10; a=a+1; b=b+1; printf("\na=%d, b=%d", a, b); } void main() { func(); func(); func(); getch(); } /**************************************************************************/ variabil local static - alocat n segmentul de date - durata de via - execuia programului - domeniu: funcia

variabil local automatic - alocat pe stiv - durata de via-execuia funciei - domeniu: funcia

Rezumat Constantele sunt valori fixe (numerice, caractere sau iruri de caractere), care nu pot fi modificate n timpul execuiei programului. Constantele pot fi introduse caracter cu caracter (constante literale) sau se pot folosi constante cu nume. Constantele literale corespund tipurilor de date predefinite (char, int, float, double). Constantele numerice se pot exprima ca ntregi, reprezentai n decimal, octal sau hexazecimal) sau n virgul mobil, n simpl sau dubl precizie. Constantele caracter se pot specifica prin caractere afiabile ncadrate ntre apostrofe (X) sau prin secvene escape n cazul caracterelor neafiabile. Constantele ir de caractere sunt alctuite dintr-un numr oarecare de caractere, ncadrate ntre ghilimele; ele se memoreaz n tablouri cu elemente de tip char, cu dimensiune egal cu numrul de caractere cuprinse ntre ghilimele, la care se adaug terminatorul de ir \0. 73

Variabilele sunt identificatori asociai cu locaii de memorie n care se memoreaz valori ce pot fi modificate pe parcursul existenei lor. Adresa la care a fost alocat o variabil se poate determina cu ajutorul operatorului & aplicat numelui variabilei, iar numrul de octei rezervai pentru variabil se determin cu operatorul sizeof. Atributele variabilelor (clasa de memorare, domeniu, durat de via) se stabilesc n mod implicit, n funcie de poziia i sintaxa declaraiei. Declaraiile globale (fcute n afara oricrei funcii) au ca domeniu ntregul fiier, ele putnd fi folosite din oricare funcie definit n fiier. Declaraiile din interiorul unui bloc se numesc declaraii locale i au domeniul cuprins ntre declaraie i sfritul blocului. Declaraia static a unei variabile locale foreaz durata static fr a modifica domeniul de utilizare. Variabilele const (constante cu nume) nu pot fi modificate pe parcursul execuiei unui program. Declaraia se face cu iniializare.

Test de autoevaluare 1. Constantele urmtoare au tipurile specificate: a. 40000 este de tip int; b. -12L este de tip long; c. 1.2 este de tip float; d. 123 este de tip char; e. "eroare" este un sir de caractere. 2. Care dintre urmtoarele specificri reprezint o constanta: a. A7B3; b. 0xA7B3; c. 077; d. 'm'; e. UL12; 3. Care dintre urmtoarele specificri reprezint o constanta: a. 0ABC; b. "mesaj"; c. 077; d. 'abc'; e. 12UL; 4. Declaratia de variabile se poate face: a. in afara oricrei funcii; b. numai in interiorul funciilor; c. numai cu initializare;

74

5. Declaratia unei variabile a. const in descrierea numelui si tipului su b. const in utilizarea datei intr-o expresie (exemplu: a=(25-a)/12;) c. se face numai pentru constante d. determina rezervarea unei locaii de memorie e. presupune obligatoriu iniializarea cu valoarea zero a datelor 6. Declaratia de variabile se poate face astfel: a. unsigned int ui; b. var double; c. char c1, c2; d. int a=9; b; c; 7. Declaratia de variabile se poate face: a. in afara oricrei funcii sau in interiorul funciilor; b. numai in interiorul funciilor; c. numai cu initializare; d. cu sau fr initializare; 8. Care dintre urmtoarele declaratii de variabile sunt corecte: a. var1, var2, var3; b. long double p="xyz"; c. char a='x', b='y'; d. int m=n=5; 9. Care dintre propoziiile urmtoare sunt adevrate: a. adresa unei variabile se poate modifica pe parcursul execuiei programului; b. valoarea unei variabile se poate modifica pe parcursul execuiei programului; c. o variabila declarata cu initializare nu i poate schimba valoarea; d. tipul unei variabile determina numarul de octeti ocupai in memorie de ctre aceasta. 10. Declaratia: int a=27; care apare intr-un program C are semnificaia: a. valoarea lui a va fi 27 pe tot parcursul execuiei programului b. se rezerv spaiu in memorie pentru variabila a c. variabila a este iniializat cu valoarea 27, aceasta putnd fi modificata pe parcursul execuiei programului d. aceasta declaraie nu e permisa, ea trebuind s fie fcut astfel: int a; a=27; 11. Care din expresiile de mai jos sunt permise intr-un program C? a. int a=25; a%=5; b. char d; d='&'; c. int a; &a=0x2000; d. const float e=2.71; e+=1.41; e. #define PI 3.141 PI=3.141592653

75

12. Care din expresiile de mai jos sunt permise intr-un program C? a. float a=25; a%=5; b. char d; d=&; c. int a; a=0x2000; d. const float e=2.71; double x=2.5*e; e. #define PI 3.1415 double PI=3.14;

ntrebri. Exerciii. Probleme.

1. Folosind Exemplul 4.2., s se scrie un program n care se definesc funcii de calcul al ariei, i respectiv al perimetrului unui dreptunghi. (Observaii: Funciile vor avea cte doi parametri, corespunztori celor dou laturi ale dreptunghiului). 2. Folosind Exemplul 4.2., s se scrie un program n care se definesc funcii de calcul pentru arii laterale i volum pentru diferite corpuri, cum ar fi paralelipiped, con, cilindru, etc.

76

Unitatea de nvare U.5. OPERAII DE INTRARE/IEIRE PENTRU CONSOL

Cuprins Introducere .................................................................................................................... 77 Obiectivele unitii de nvare ..................................................................................... 79 U5.1. Operaii I/O la nivel de caracter .......................................................................... 79 U5.2. Funcii pentru operaii I/O pentru iruri de caractere .......................................... 80 U5.3. Operaii de citire/scriere cu formatare ................................................................ 82 Exemple ........................................................................................................................ 89 Rezumat ........................................................................................................................ 93 Test de autoevaluare ..................................................................................................... 94 ntrebri, exerciii i probleme ...................................................................................... 98

Introducere n C/C++, spre deosebire de alte limbaje, operaiile de intrare/ieire (I/O Input/Output) nu se efectueaz pe baza unui tip de date dedicat i a unor funcii ncorporate n limbaj. Sistemul de intrare/ieire nu este parte a limbajului, ci se adaug printr-un set de funcii din biblioteca standard, ceea ce ofer programatorului un sistem I/O flexibil i puternic. Acest lucru asigur o bun portabilitate programelor C/C++, prin folosirea librriilor de funcii specifice, ele pot fi compilate pentru diferite sisteme de operare. Transferurile de date cu dispozitivele fizice de intrare/ieire (consol, disc, imprimant, etc.) se fac prin intermediul sistemului de operare i al unor dispozitive logice identice numite stream (flux). Detaliile funcionale ale dispozitivelor fizice pot fi ignorate la nivelul programului C/C++, ele trebuind s fie cunoscute doar la nivelul sistemului de operare care comand efectiv dispozitivele prin intermediul unor rutine dedicate. Operaiile de intrare/ieire se efectueaz prin funcii din biblioteca C/C++, declarate (majoritatea) n fiierul stdio.h. C++ dispune suplimentar de un sistem propriu, realizat pe principiile POO (Programrii Orientate pe Obiecte), dar acest aspect nu face obiectul acestei prezentri. Datorit nivelului de abstractizare introdus de fluxuri, programatorul utilizeaz acelai set de funcii din biblioteca C/C++, indiferent de dispozitivul fizic cu care comunic efectiv. Dei dispozitivele logice sunt identice, dispozitivele

77

fizice crora le sunt asociate difer din punct de vedere al tipului de operaie de I/O care poate fi efectuat. De exemplu, tastatura este un dispozitiv de intrare, monitorul sau imprimanta sunt numai dispozitive de ieire, o unitate de disc poate efectua operaii de citire/scriere pe disc, cu acces aleator la date, dar o unitate de band magnetic poate accesa informaia, pentru scriere sau citire numai secvenial. Se disting dou tipuri de streamuri: streamuri de tip text care transfer secvene de caractere organizate n linii. n C, separarea liniilor se face prin caracterul linie nou (LF 0AH). Pentru adaptarea la dispozitiv poate fi necesar o conversie (secvena 0DH se nlocuiete cu 0DH 0AH la scrierea textului pe disc). Din acest motiv, numrul de caractere transferate ctre stream poate fi diferit de numrul de caractere din dispozitivul fizic. streamuri binare - transfer o secven de octei fr nici o structur, deci fr alte prelucrri. Distingerea dintre cele dou categorii este convenabil, dar nu obligatorie. Exist 5 dispozitive logice predefinite care se creeaz automat la lansarea n execuie a programului i sunt nchise automat la terminarea execuiei: stdin stream de tip text - reprezint intrarea standard, care este asociat cu tastatura; poate fi redirectat de ctre sistemul de operare. stdout stream de tip text reprezint ieirea standard care e asociat cu monitorul; poate fi redirectat de ctre sistemul de operare. stderr - stream de tip text reprezint ieirea standard pentru erori i e asociat, de asemenea, cu monitorul. strprn stream de tip binar reprezint ieirea standard la imprimant, asociat dispozitivului DOS PRN. stdaux stream de tip binar reprezint intrare/ieire auxiliar, asociat dispozitivului DOS AUX. Cei 5 identificatori sunt constante de tip FILE * (definit n fiierul stdio.h). Pentru stream-urile utilizate se aloc o zon de memorie tampon prin intermediul creia se vor efectua transferurile. Funciile destinate operaiilor I/O definite n biblioteca standard pot fi, fie destinate unui dispozitiv predefinit, cum ar fi de exemplu funcia getch() care citete un caracter de la tastatur (stdin), sau funcia printf() care afieaz informaie pe ecran (stdout), fie funcii, care, prin intermediul parametrilor, pot direciona operaiile I/O ctre un dispozitiv sau altul, cum ar fi de exemplu funcia fscanf() care citete date de la un dispozitiv precizat ca parametru, cum ar fi un fiier, dar i stdin.

78

n continuare se va face referire la operaiile I/O pentru consol. Funciile de intrare/ieire pentru consol utilizeaz implicit dispozitivele predefinite stdin (tastatur) i stdout sau stderr (ecran). Unele funcii de intrare/ieire sunt destinate unui anumit tip de date, cum ar fi char sau int, altele pot efectua operaii cu oricare tip de date fundamental prin precizarea formatului specific fiecrui tip.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Generaliti privind operaiile de intrare/ieire (I/O); Funcii pentru operaii I/O cu caractere; Funcii pentru operaii I/O cu iruri de caractere; Funcii pentru operaii I/O cu formatare.

Durata medie de parcurgere a celei de a cincia uniti de nvare este de 2 ore.

U5.1. Operaii la nivel de caracter Funcii pentru operaii de citire a unui caracter: Pentru citirea unui caracter din stdin pot fi folosite urmtoarele funcii: int getchar(void); // definit n stdio.h

Funcia ntoarce primul caracter din stdin, corespunztor primei taste apsate, dar dup ce s-a apsat tasta Enter (CR). Caracterul este transformat n ntreg fr semn. n caz de eroare, ntoarce constanta EOF care are valoarea -1. int getche(void); // definit n conio.h;

Funcia ateapt apsarea unei taste, ntoarce caracterul corespunztor i l afieaz pe ecran (nu ateapt apsarea tastei Enter). int getch(void); // definit n conio.h;

Funcia ateapt apsarea unei taste, ntoarce caracterul corespunztor dar nu l afieaz pe ecran (nu ateapt apsarea tastei Enter). Exemple de folosire a funciilor de citire a unui caracter: char ch; // se declar variabila ch care poate primi valoarea citit prin una // din funciile de citire a unui caracter 79

ch=getchar(); ch=getche(); ch=getch(); getch();

// funcia getchar() ntoarce valoarea caracterului tastat, aceasta // e preluat de variabila ch, dar numai dup apsarea tastei // Enter; caracterul este afiat pe ecran // funcia getche() ntoarce valoarea caracterului tastat, aceasta // e preluat de variabila ch, fr a atepta apsarea tastei // Enter; caracterul este afiat pe ecran // funcia getch() ntoarce valoarea caracterului tastat, aceasta // e preluat de variabila ch, fr a atepta apsarea tastei // Enter; caracterul nu este afiat pe ecran // funcia getch() ntoarce valoarea caracterului tastat fr ca aceast // valoare s fie utilizat; aceast instruciune se folosete de regul // pentru a ntrerupe temporar evoluia programului pn la apsarea // unei taste; caracterul nu este afiat pe ecran

Funcii pentru operaii de afiare a unui caracter: Pentru scrierea unui caracter la stdout se folosesc funciile: int putchar(int c); // definit n stdio.h int putch(int c); // definit n conio.h Funciile transfer un caracter ctre stdout (l afieaz pe ecran) i ntoarce ca rezultat caracterul transmis n caz de succes, sau EOF n caz de eec. Exemple de folosire a funciilor de afiare a unui caracter: char ch=a; putch(x); putchar(y); putch(ch); putch(\n); putchar(\r); putchar(99); putchar(0x63); // se declar variabila ch care poate primi valoarea citit prin una // din funciile de citire a unui caracter // se afieaz caracterul constant x // se afieaz caracterul constant y // se afieaz coninutul variabilei ch, caracterul a // caracterul constant \n (newline) nu este afiabil, dar mut // cursorul pe linia urmtoare // caracterul constant \r (CR-carriage return) nu este afiabil, dar // mut cursorul la nceputul rndului // se afieaz caracterul constant cu valoarea 99 n codul ASCII, // caracterul c // se afieaz caracterul constant cu valoarea 0x63 n codul // ASCII, caracterul c

U5.2. Funcii pentru operaii I/O pentru iruri de caractere Operaii de citire a irurilor de caractere: char * gets(char * s); // definit n stdio.h

Funcia citete caractere din stdin i le depune n tabloul de la adresa s pn ntlnete caracterul \n (apsarea tastei Enter). n ir \n este nlocuit cu terminatorul de ir \0 . Dac operaia se ncheie cu succes, funcia ntoarce adresa irului (egal cu valoarea parametrului), 80

altfel ntoarce valoarea NULL. Operaii de afiare a irurilor de caractere: int puts (const char * s); // definit n stdio.h

Funcia copiaz la stdout (pe ecran) irul de la adresa s i trece la linie nou. n caz de succes ntoarce ultimul caracter, altfel ntoarce valoarea EOF.

Observaii n C/C++ irurile de caractere nu sunt definite printr-un tip de date predefinit, ci sunt construite ca tablouri cu elemente de tip char. Sunt formate din succesiuni de caractere ncheiate cu caracterul \0 (valoarea zero n codul ASCII). Un ir de caractere se declar cu sintaxa : char nume_sir[numar_caractere]; Declaraia se poate face i cu iniializare. Numele irului de caractere reprezint adresa de memorie la care a fost alocat irul, tipul datei fiind char * (pointer de char). Aspecte specifice lucrului cu iruri de caractere vor fi reluate n capitolele destinate tablourilor de date, i particularizrile acestora ca iruri de caractere. Exemple de folosire a funciilor I/O pentru iruri de caractere: char sir1[30]="primul sir"; char sir2[30]="al doilea sir"; puts("sir1:"); puts(sir1); puts("sir2:"); puts(sir2); puts("\nIntrodu un sir de caractere:"); gets(sir1); puts("\nIntrodu un sir de caractere:"); gets(sir2); puts("sir1:"); puts(sir1); puts("sir2:"); puts(sir2); // declararea irului sir1 cu iniializare // declararea irului sir2 cu iniializare // afiarea irului constant sir1: // afiarea coninutului irului sir1, se afieaz // coninutul iniial // afiarea irului constant sir2: // afiarea coninutului irului sir2, se afieaz // coninutul iniial // se citete de la tastatur coninutul irului sir1 // se citete de la tastatur coninutul irului sir2 // afiarea coninutului irului sir1, se afieaz // coninutul introdus de la tastatur // afiarea coninutului irului sir2, se afieaz // coninutul introdus de la tastatur

81

U5.3. Operaii de citire/scriere cu formatare n cazul unei operaii de citire, formatarea const n conversia datelor de la reprezentarea lor extern (la dispozitivul de intrare) la reprezentarea intern, binar. Pentru o operaie de ieire (scrie) se efectueaz conversia invers. Datele sunt introduse de la tastatur sub forma unor iruri de caractere ASCII, corespunztoare tastelor apsate i sunt separate de spaiere (spaiu, tab, linie nou, etc.). De exemplu, n cazul datelor numerice este necesar transformarea irului de coduri ASCII de cifre, punct zecimal, etc., n reprezentarea binar a valorii numerelor. O operaie invers este necesar pentru afiarea valorii pe ecran, deoarece dispozitivul de ieire consol ateapt un ir de coduri ASCII pe baza crora creeaz imaginea de pe ecran. n plus, formatarea permite controlul afirii pe ecran (numrul de spaii alocate, numrul de zecimale, etc.) i al introducerii datelor (numrul de caractere alocate). Citirea datelor cu formatare scanf(); Prototipul funciei este: int scanf(const char* sir_de_formatare, [lista_adrese_variabile]); unde : - sir_de_formatare conine caractere ASCII i specificatori de format. - valoarea returnat de funcie reprezint numrul cmpurilor a cror citire s-a realizat corect. - lista_adrese_variabile precizeaz adresele de memorie la care sunt memorate valorile introduse de la tastatur. Pentru ca operaia de intrare s se realizeze corect, trebuie ca numrul de formate precizate n ir_de_formatare i numrul adreselor n lista_adrese_variabile s fie acelai i tipurile precizate prin formate s corespund tipurilor obiectelor ce se gsesc la adresele precizate. Afiarea datelor cu formatare printf(); Prototipul funciei este: int printf(const char* sir_de_formatare, [lista_valori]); unde: - sir_de_formatare conine caractere ASCII i specificatori de format. - valoarea returnat de funcie reprezint numrul caracterelor afiate. - lista_valori reprezint o niruire de expresii care returneaz valori, cum ar fi nume de variabile, apeluri de funcii, expresii aritmetice, etc. Pentru ca operaia de afiare s se realizeze corect, trebuie ca numrul de formate // definit n stdio.h // definit n stdio.h

82

precizate n ir_de_formatare i numrul expresiilor din lista_valori s fie acelai i tipurile precizate prin formate s corespund tipurilor expresiilor. Dac lista de adrese sau de valori conin mai multe expresii dect formatele din irul de formatare, adresele sau valorile crora nu le corespund formate vor fi ignorate. Dac ns n irul de formatare exist formate care nu au corespondent adres, respectiv valoare, fie se vor afia valori aleatoare, fi se poate produce o eroare fatal care blocheaz execuia programului. Regulile de alctuire a irurilor de formatare i sintaxa celor dou funcii, scanf() i printf(), sunt similare. Specificatorii de format ncep cu caracterul % i sunt definii pentru toate tipurile predefinite de date. n tabelul nr. 5.1. sunt prezentate formatele pentru fiecare tip de date. Aceste secvene pot fi completate cu modelatori de format.

Tabel nr. 5.1. Specificatori de format Cod %c %d %i %u %o %x %X %f %e %E %g %G %s %p %[ ] %n caracter, tipul char numr ntreg zecimal numr ntreg zecimal numr ntreg fr semn numr ntreg reprezentat n octal numr ntreg reprezentat n hexazecimal, se folosesc cifrele a,b,c,d,e,f numr ntreg reprezentat n hexazecimal, se folosesc cifrele A,B,C,D,E,F numr n virgul mobil numr n virgul mobil, format tiinific, e pentru exponent numr n virgul mobil, format tiinific, E pentru exponent numr n virgul mobil, format tiinific, e pentru exponent numr n virgul mobil, format tiinific, E pentru exponent ir de caractere adres de memorie reprezentat n hexazecimal Caut un set de caractere Primete o valoare egal cu numrul de caractere citite pn atunci Semnificaie

83

Specificatorii de format pot fi nsoii de modelatori de format, cum ar fi: specificator pentru mrimea cmpului un ntreg care determin numrul de caractere ale cmpului specificator de precizie urmeaz dup specificatorul pentru mrimea cmpului i const n punct urmat de un ntreg modelatorul + - foreaz afiarea semnului plus (+) dac se afieaz valoare pozitiv (afiarea semnului minus se face n mod implicit pentru valori negative) modelatorul - - foreaz alinierea la stnga a cmpului afiat modelatorul * - se folosete pentru rezervarea unui loc pentru un argument modelatorul # - se afieaz punctul zecimal pentru valori reprezentate n virgul mobil care nu au parte zecimal - se afieaz cifra 0 pe prima poziie a unui ntreg octal - se afieaz 0x la nceputul unui ntreg hexazecimal Se consider exemplul urmtor n care se declar dou variabile, una int, cealalt float. Se citesc valori de la tastatur pentru ambele variabile folosind funcia scanf() i apoi se afieaz valorile preluate de cele dou variabile folosind funcia printf(). int a; float b; scanf(%d, %f, &a, &b); printf(\na = %d, \t b = %f, a, b);

Descrierea sintaxei folosit pentru apelul funciei scanf() este fcut n Fig. 5.1, iar cea a apelului funciei printf() n Fig. 5.2.

Fig.5.1. Sintaxa apelului funciei scanf()

a.) descrierea parametrilor efectivi ; b.) corespondena dintre formatele precizate i adresele
variabilelor

84

Fig.5.2. Sintaxa apelului funciei printf() a.) descrierea parametrilor efectivi ; b.) alctuirea irului de formatare i corespondena dintre formatele precizate i valori

Observaii irul de formatare al funciei scanf() este recomandat s fie alctuit numai din formatele specifice pentru datele care urmeaz a fi citite. Orice alt caracter, n afara acestor formate, va trebui tastat la introducerea datelor. Acest lucru poate genera erori la citirea datelor. De exemplu, pentru instruciunea: scanf(a=%d, &a); la execuie, pentru ca citirea s se fac corect, trebuie tastat caracterul a, caracterul = i apoi valoarea pentru variabila a. Dac irul de formatare al funciei printf() conine alte caractere n afara formatelor, acele caractere vor fi afiate pe ecran. Dac irul de formatare al funciei printf() nu conine nici un format, se va afia irul constant specificat, efectul fiind similar cu cel al funciei gets(). Ca orice ir constant i irul de formatare poate conine secvene de escape. Dac se dorete afiarea caracterelor \, sau , care au o semnificaie anume n sintaxa specific limbajului, acestea trebuie precedate de caracterul \. De exemplu, funcia printf( \ \\ \ ); va afia pe ecran succesiunea de caractere \ n cazul ambelor funcii, scanf() i printf(), lista de adrese, respectiv lista de variabile pot lipsi, dar irul de formatare este obligatoriu s existe.

85

Este important s se respecte corespondena ntre formatul datei precizat i tipul variabilei creia i se atribuie valoarea citit de la tastatur. n caz contrar, valorile preluate de variabile sunt aleatoare sau se pot genera erori fatale, execuia programului fiind ntrerupt. Este situaia prezentat n exemplul urmtor: int a; float b; scanf(%d, %f, &b, &a); printf(\na=%d, \tb=%f, a, b);

// eroare, formatul %d corespunde unei variabile float, // iar formatul %f corespunde unei date int,

n continuare sunt prezentate mai multe exemple prin care se explic modul de folosire a tuturor formatelor i a modelatorilor de format. int a; printf("\nIntrodu un intreg:"); // se afieaz irul constant "\nIntrodu un intreg:" scanf("%x", &a); // se citete variabila a n format hexazecimal printf("\na=%d, a=%o, a=%x, a=%u, a=%c", a, a, a, a, a); // se afieaz valoarea variabilei // a n diferite formate: zecimal, octal, // hexazecimal, unsigned, caracter float r; printf("\nIntrodu un real:"); scanf("%f", &r); // se citete o valoare real printf("\nr=%f, r=%e, r=%g", r, r, r); // se afieaz valoarea citit n format clasic i // format tiinific printf("\nIntrodu un real(in format stiintific):"); scanf("%e", &r); printf("\nr=%f, r=%e, r=%g", r, r, r);

Observaii Formatul %f este formatul specific valorilor reale: parte_ntreag . parte_zecimal n mod implicit se afieaz 6 zecimale. De exemplu, valoarea 12.34 va fi afiat: 12.340000. Formatul %e sau %E reprezint formatul tiinific de scriere a realilor: x . xxxxxx E +/-xx De exemplu, valoarea 12.34 va fi afiat: 1.234000E+01. Formatul %g sau %G alege ntre formatul clasic de scriere sau formatul tiinific, astfel nct numrul de caractere utilizat s fie minim.

86

printf (\n*%f*, 12.3456); printf (\n*%10.2*,12.3456); printf (\n*%+10.2*, 12.3456); printf (\n*%+010.2*, 12.3456);

// implicit se afieaz 6 zecimale // se precizeaz numrul de caractere al cmpului // (10-numrul total de caractere) i precizia de // afiare (2 zecimale) // se afieaz semnul + // caracterele neutilizate ale cmpului vor fi // completate cu 0

Pentru secvena anterioar se va afia: *12.345600* * 12.34* * +12.34* *0000+12.34* char ch; scanf(%c, &ch); printf(\nc = %c, c = %d, ch, ch);

// se citete un caracter // se afieaz caracterul tastat i valoarea // lui din codul ASCII

char sir[20]; printf("\nIntrodu un sir de caractere:"); scanf("%s", &sir); printf("\nsirul este=%s ", sir);

// se citete un ir de caractere // se afieaz irul de caractere

Observaii La citirea unui ir de caractere nu este necesar s se foloseasc operatorul adres deoarece numele irului reprezint adresa la care este alocat n memorie. Deci urmtoarele dou instruciuni sunt echivalente: scanf("%s", &sir); scanf("%s", sir); char a[20], b[20]; printf("\nIntrodu un sir [abc]:"); scanf("%[abc]", a);

// se citete un ir de caractere format numai din // caracterele a, b sau c ; la tastarea primului // caracter diferit de acestea, se va ntrerupe // operaia de citire // se citete un ir de caractere format numai din // caracterele cuprinse n intervalul d - m ; // se afieaz coninutul irului a pe minim 12 // caractere, completndu-se cu spaii dac este // cazul; alinierea se face la dreapta

printf("\nIntrodu alt sir [d-m]:"); scanf("%[d-m]", b); printf("\nSirurile sunt:"); printf("\na=%12s", a);

87

printf("\nb=%-10s", b);

// se afieaz coninutul irului b pe minim 10 // caractere, completndu-se cu spaii dac este // cazul; alinierea se face la stnga

char a[20]=abcdefgh; printf(\n*%s*, a); printf(\n*%10s*, a); printf(\n*%-10s*, a); printf(\n*%5s*, a);

// dac mrimea cmpului e mai mic dect // lungimea irului, acesta nu va fi trunchiat, ci se // afieaz ntregul ir

Pentru secvena anterioar se afieaz: *abcdefgh* * abcdefgh* *abcdefgh * *abcdefgh* int a=10; printf(adresa variabilei: %p\n, &a);// se afieaz adresa variabilei a n format // hexazecimal printf(adresa variabilei: %u\n, &a);// se afieaz adresa variabilei a ca ntreg // fr semn n reprezentare zecimal printf(Exemplu de folosire a modelatorului # \n); printf(%o \t %#o, 124); // se afieaz valoarea 124 transformat n format octal printf(%x \t %#x, 124); // se afieaz valoarea 124 transformat n reprezentare // hexazecimal Pentru secvena anterioar se va afia: 174 7C 0174 0x7C

Aa cum s-a precizat, transferul informaiei n operaiile I/O se face prin zone de memorie tampon asociate cu stream-urile folosite n care se depune informaia temporar, pn la preluarea i prelucrarea de funciile corespunztoare. Exist posibilitatea ca la execuia unei funcii I/O n zona tampon s se gseasc date reziduale rmase de la operaiile anterioare din diferite cauze, cum ar fi depirea dimensiunii cmpurilor, utilizarea de caractere ilegale, etc. Pentru a evita preluarea de date reziduale, este necesar ca nainte de aceste operaii s se realizeze golirea zonelor de memorie tampon. Acest operaie se poate face folosind funcia fflush(), definit n fiierul stdio.h care are prototipul: int fflush(FILE* stream); Funcia golete streamul specificat ca parametru i returneaz valoarea 0 dac operaia 88

s-a efectuat cu succes i EOF n caz contrar. int a, b; scanf(%2d, &a); scanf(%2d, &b); Dac la execuia secvenei anterioare pentru variabila a se tasteaz 123456, variabila a preia dou caractere, deci a=12, n zona tampon rmnnd 3456. Ca urmare b va prelua valoarea 34 i n zona tampon rmne secvena 56. Aceasta va fi preluat de urmtoarea funcie de citire de la tastatur. Pentru a evita astfel de situaii, se va folosi funcia fflush() : fflush(stdin); scanf(%2d, &a); fflush(stdin); scanf(%2d, &b);

Exemple

/**************************************************************************

Exemplu1 5.1. - Se scrie un program n care se exemplific folosirea funciilor de intrare ieire pentru caractere n care: - se declar 3 variabile de tip char sau int; - se citesc valori pentru cele trei variabile cu funciile getch(), getche(), respectiv getchar(); - se afieaz coninutul variabilelor folosind funciile putch() sau putchar() Observaii: Se afieaz mesaje care s ajute la nelegerea desfurrii programului. **************************************************************************/ #include<conio.h> #include <stdio.h> void main(void) { char c1, c2, c3; puts("Introdu un caracter : "); c1 = getch(); puts("\ncaracterul tastat este : "); putch(c1);

89

puts("\nIntrodu un caracter : "); c2 = getche(); puts("\ncaracterul tastat este : "); putch(c2); puts("\nIntrodu un caracter : "); c3=getchar(); puts("\ncaracterul tastat este : "); putch(c3); putch('\n'); }

/**************************************************************************

Exemplu1 5.2. - Se scrie un program n care se exemplific folosirea funciilor de intrare ieire pentru iruri de caractere n care: - se declar 2 iruri de caractere cu iniializare; - se afieaz coninutul irurilor cu funcia puts(); - se citesc valori pentru cele dou iruri cu funcia gets(); - se afieaz din nou coninutul irurilor folosind funcia puts(). Observaie: Se vor afisa mesaje care sa ajute la nelegerea desfurrii programului. ***************************************************************************/ #include<stdio.h> #include<conio.h> void main(void) { char sir1[30]="primul sir"; char sir2[30]="al doilea sir"; puts("sir1:"); puts(sir1); puts("sir2:"); puts(sir2); puts("\nIntrodu un sir de caractere:"); gets(sir1); puts("\nIntrodu un sir de caractere:"); gets(sir2); puts("sir1:"); puts(sir1); puts("sir2:"); puts(sir2); getch(); }

90

/**************************************************************************

Exemplu1 5.3. - Se scrie un program n care se exemplific folosirea funciilor de intrare ieire pentru diverse tipuri de date.
**************************************************************************/

#include < stdio.h > #include<conio.h> void main() { char caracter = 'A'; int nr_intreg = 20; float nr_real = 123.45; double nr_double = 1122.33E3; char sir[30] = Exemplu; printf("caracter = %c\n", caracter ); printf("intreg = %d\n", nr_intreg); printf("real = %f\n", nr_real ); printf("real dublu = %e\n", nr_double); printf("sir de caractere = %s\n", sir); getch(); }
/**************************************************************************

Exemplu1 5.4. - Se scrie un program n care se exemplific folosirea funciilor de intrare ieire pentru tipul de date int. Se folosesc toate diverse formate compatibile cu tipul int.
**************************************************************************/

Format pentru reprezentarea n baza 10 (zecimal). #include <stdio.h> #include <conio.h> void main() { int a, b; Format pentru reprezentarea n baza 8 (octal). Format pentru reprezentarea n baza 16 (hexazecimal).

Format pentru reprezentarea ca printf("\nIntrodu un intreg:"); ntreg fr semn. scanf("%d", &a); printf("\na=%d, a=%o, a=%x, a=%u, a=%c", a, a, a, a, a); getch(); Format pentru printf("\nIntrodu 2 intregi:"); reprezentarea ca i scanf("%d%d", &a, &b); printf("\na=%d, a=%o, a=%x, a=%u, a=%c", a, a, a, a, a); caracter.

91

printf("\nb=%d, b=%o, b=%x, b=%u, b=%c", b, b, b, b, b); getch(); printf("\nIntrodu 2 intregi:"); scanf("%2d%2d",&a,&b); printf("\na=%d, a=%o, a=%x, a=%u, a=%c", a, a, a, a, a); printf("\nb=%d, b=%o, b=%x, b=%u, b=%c", b, b, b, b, b); getch(); printf("\n*%+6d*",1); printf("\n*%+6d*",12); printf("\n*%+6d*",123); printf("\n*%+6d*",1234); printf("\n*%+6d*",12345); getch(); } Se precizeaz numrul de caractere preluate de variabil

/**************************************************************************

Exemplu1 5.5. - Se scrie un program n care se exemplific folosirea funciilor de intrare ieire pentru tipul de date float. Se folosesc toate diverse formate compatibile cu tipul float.
**************************************************************************/

#include <stdio.h> #include <conio.h> void main() { float a, b; printf("\nIntrodu un real:"); scanf("%f", &a); printf("\na=%f, a=%e, a=%g", a, a, a); printf("\n*%12f*", a); printf("\n*%.2f*", a); printf("\n*%12.2f*", a); printf("\n*%+12.2f*", a); getch(); }

Format de afiare a valorilor reale prin parte ntreag i parte fracionar. Format de afiare a valorilor reale n format tiinific.

Se precizeaz numrul de caractere folosite n afiare. Se face afiare cu 2 zecimale. Se cere afiarea semnului.

92

Rezumat n C/C++ operaiile de intrare/ieire (I/O Input/Output) nu se efectueaz pe baza unui tip de date dedicat i a unor funcii ncorporate n limbaj, ci se adaug printr-un set de funcii din biblioteca standard. Transferurile de date cu dispozitivele fizice de intrare/ieire se fac prin intermediul sistemului de operare i al unor dispozitive logice identice numite stream prin funcii din biblioteca C/C++, declarate (majoritatea) n fiierul stdio.h, sau n C++ printr-un sistem propriu, realizat pe principiile POO. n biblioteca standard exist definite funcii I/O destinate anumitor tipuri de date (caractere i iruri de caractere) i funcii care pot opera cu oricare dintre tipurile de date predefinite. Citirea de la tastatur a caracterelor se poate face cu funcii dedicate, cum ar fi de exemplu getch(), getche(), getchar(), definite n fiierele header conio.h i stdio.h. Afiarea pe ecran a caracterelor se poate face cu funcii dedicate, cum ar fi de exemplu putch(), putchar(), definite n fiierele header conio.h i stdio.h. Citirea de la tastatur a irurilor de caracterelor se poate face cu funcii dedicate, cum ar fi de exemplu gets() definit n fiierul header stdio.h. Afiarea pe ecran a irurilor de caracterelor se poate face cu funcii dedicate, cum ar fi de exemplu puts() definit n fiierul header stdio.h. Funciile consacrate pentru operaii I/O pentru oricare dintre tipurile de date predefinite sunt definite n fiierul stdio.h (scanf(), printf()). La aceste funcii se precizeaz formate de citire/afiare n concordan cu tipul datelor vehiculate. n cazul unei operaii de citire, formatarea const n conversia datelor de la reprezentarea lor extern (la dispozitivul de intrare) la reprezentarea intern, binar. Datele sunt introduse de la tastatur sub forma unor iruri de caractere ASCII, corespunztoare tastelor apsate i sunt separate de spaiere (spaiu, tab, linie nou, etc.) i se face transformarea irului n reprezentarea binar a valorii respective. O operaie invers este necesar pentru afiarea valorii pe ecran, deoarece dispozitivul de ieire consol ateapt un ir de coduri ASCII pe baza crora creeaz imaginea de pe ecran. Apelul funciei scanf() precizeaz irul de formatare (conine caractere ASCII i specificatori de format) i lista adreselor de memorie la care sunt memorate valorile introduse de la tastatur. Pentru ca operaia de intrare s se realizeze corect, trebuie ca numrul de formate precizate n irul de formatare i numrul adreselor n lista de adrese ale variabilelor s fie acelai i tipurile precizate prin formate s corespund tipurilor obiectelor ce se gsesc la adresele precizate.

93

Apelul funciei printf() precizeaz irul de formatare (conine caractere ASCII i specificatori de format) i lista de valori. Pentru ca operaia de afiare s se realizeze corect, trebuie ca numrul de formate precizate n irul de formatare i numrul expresiilor din lista de valori s fie acelai i tipurile precizate prin formate s corespund tipurilor expresiilor. Specificatorii de format pot fi nsoii de modelatori de format, cum ar fi: specificator pentru mrimea cmpului, specificator de precizie, modelatorii *, +, -, # care influeneaz formatul de citire sau afiare a datelor. Exist posibilitatea ca la execuia unei funcii I/O n zona tampon s se gseasc date reziduale rmase de la operaiile anterioare din diferite cauze. Pentru a evita preluarea de date reziduale, se poate realiza golirea zonelor de memorie tampon asociate, folosind funcia fflush(), definit n fiierul stdio.h

Test de autoevaluare

1. Mesajul de pe ecran 1.234e-2 este generat de secvena de instruciuni: a. float b=1.234e-2; printf("%f", b); b. float a=1.234e-2; printf("%e", a); c. float c=0.01234; printf("%e", c); d. nici una din cele de mai sus 2. Secvena de instruciuni: #include<stdio.h> #include<conio.h> void main() { char ch; ch=getche(); putchar('A'); putchar(ch); } va produce dup apsarea tastei: a a. nu intra in execuie din cauza unei erori de sintaxa b. afisarea pe ecran a secvenei: aA c. afisarea pe ecran a secvenei: aAa d. ateapt apsarea tastei <Enter>

94

3. Secvena de instruciuni: #include<stdio.h> #include<conio.h> void main() { char ch; ch=getch(); putchar("\nA"); putchar(ch); } va produce dup apsarea tastei: a a. ateapt apsarea tastei <Enter> b. afisarea pe ecran a secvenei: aAa c. afisarea pe ecran a secvenei: A a d. nu intra in execuie din cauza unei erori de sintaxa 4. Secvena de instruciuni: #include<stdio.h> #include<conio.h> void main() { char str[80]="acesta este un sir"; putchar(str); } va produce : a. nu intra in execuie din cauza unei erori de sintaxa b. afisarea secvenei: acesta este un sir c. afisarea primei litere din sir: a d. afisarea ultimei litere din sir: r 5. Secvena de instruciuni: #include<stdio.h> #include<conio.h> void main() { char ch; ch=getche(); putchar('*'); } va produce dup apsarea tastei: a a. afisarea pe ecran a secvenei: a* b. afisarea pe ecran a secvenei: a * c. nu intra in execuie din cauza unei erori de sintaxa d. afisarea pe ecran a secvenei: * 6. Secvena de instruciuni: #include<stdio.h> #include<conio.h> void main()

95

long nr; puts("introduceti un numar:"); scanf("%d", nr); printf("\nnr=%3d", nr);

} la apsarea tastei 5: a. nu va intra n execuie din cauza unui erori de sintaxa; b. va afisa pe ecranul utilizator secventa : introducei un numar: 5 nr = 5; c. secventa: introduceti un numar:5 nr = 5; d. eroare la execuie 7. Secvena de instruciuni: #include<stdio.h> void main() { int nr; puts("introduceti un numar:"); scanf("%d", &nr); puts("nr=%3d"); } la apsarea tastei 5: a. nu va intra in execuie din cauza unui erori de sintaxa; b. va afisa pe ecranul utilizator secventa: introducei un numar:5 nr=%d; c. secventa: introducei un numar: 5 nr=%3d; d. secvena: introducei un numr: 5 nr = 5; 8. Secvena de program de mai jos: #include<stdio.h> void main() { char c='1'; printf("%c\t%x\n", c, c); } va genera urmtorul efect: a. eroare de compilare b. '1' 31 c. 1 1 d. 1 31 e. 31 31

96

9. Secvena de program de mai jos: #include<stdio.h> void main() { char x=42; printf("%d\t%c\t", x, x); } va genera urmtorul efect: a. 0x42 c b. 66 B c. 66 * d. 0x42 B e. eroare de sintaxa 10. Secvena de program de mai jos: #include<stdio.h> void main() { char x=0x42; printf("%x\t%c\t", x, x); } va genera urmtorul efect: a. 0x42 c b. 42 B c. 42 b d. 0x42 B e. eroare de sintaxa 11. Secvena de program de mai jos: #include<stdio.h> void main() { int x='a'; printf("%x\t%c\t%d\n", x, x, x); } va genera urmtorul efect: a. 0x97 a 97 b. 61 a 97 c. eroare de sintax d. a a a 12. Secvena de program de mai jos: #include<stdio.h> void main() { int a = 5; float b = 3.5; printf("\n%d\t%.2f", b, a); } va genera urmtorul efect: a. 3.500000 5 b. 3.5 5 c. 3 5.000000 d. nici una din cele de mai sus 97

ntrebri. Exerciii. Probleme.

1. S se scrie un program n care se exemplific folosirea funciilor de intrare ieire cu formatare pentru iruri de caractere. Se folosesc diverse formate compatibile cu iruri de caractere, similar exemplelor 5.3, 5.4. 2. S se scrie un program n care se exemplific folosirea funciilor de intrare ieire cu formatare pentru diverse tipuri de date (char, int, float, double). Se vor folosi i modelatorii cunoscui. Se are n vedere asocierea corect a formatelor cu tipurile datelor asociate.

98

Unitatea de nvare U.6. OPERATORI I EXPRESII

Cuprins Introducere .................................................................................................................... 99 Obiectivele unitii de nvare ..................................................................................... 99 U6.1. Operatori .......................................................................................................... 100 U6.2. Ordinea de evaluare a expresiilor...................................................................... 111 U6.3. Conversii de tip n expresii ............................................................................... 113 Exemple ...................................................................................................................... 114 Rezumat ...................................................................................................................... 116 Test de autoevaluare ................................................................................................... 117 ntrebri, exerciii i probleme .................................................................................... 119

Introducere Orice program transpune o problem prin intermediul unei succesiuni de instruciuni, fiecare producnd o aciune. Aceste instruciuni includ n mod frecvent expresii formate din succesiuni de operani i operatori. Operatorii sunt simboluri care, aplicate unor operanzi (date - constante, variabile, expresii), au ca efect realizarea unor operaii care returneaz un rezultat. O succesiune valid de operanzi i operatori formeaz o expresie. Limbajele C/C++ dispun de o gam larg de operatori. C++ posed toi operanzii limbajului C, completnd lista cu operanzi proprii. Operanzii pot fi grupai dup diferite criterii, de exemplu dup numrul operanzilor crora li se aplic sau dup tipul operaiei efectuat. n prezenta unitate de nvare sunt descrii majoritatea operatorii specifici limbajelor C/C++. Unii operatori vor fi introdui n alte uniti de nvare, odat cu introducerea unor noi noiuni.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Operatorii limbajelor C/C++; Evaluarea expresiilor; precedena i asociativitatea operatorilor; Conversii de tip la evaluarea expresiilor. 99

Durata medie de parcurgere a celei de a asea uniti de nvare este de 2 ore.

U6.1. Operatori Operatorii sunt simboluri care aplicate unor operanzi (date - constante, variabile, expresii) au ca efect realizarea unor operaii care returneaz un rezultat. O succesiune valid de operanzi i operatori formeaz o expresie. Limbajele C/C++ dispun de o gam larg de operatori. C++ posed toi operanzii limbajului C, completnd lista cu operanzi proprii: operatorii new i delete utilizai pentru alocarea dinamic de memorie, operatorul de scop (::), operatorul pointer la membru ( .* ) i forma sa echivalent ( ->. ) . Operatorii pot fi grupai dup diferite criterii. Unul dinte criterii l constituie tipul operaiei. Astfel, operatorii pot fi grupai n operatori aritmetici, operatori relaionali, operatori la nivel de bit i operatori logici. n afar de aceste categorii, exist o serie de operatori care descriu operaii diverse. Alt criteriu de clasificare a operatorilor l constituie numrul de operanzi crora li se aplic. Operatorii pot fi clasificai n operatori unari (se aplic la un operand), operatori binari (se aplic la doi operanzi) i ternari (se aplic la trei operanzi). Este de remarcat faptul c exist operatori care au dubl semnificaie, cum ar fi +, -, *, etc., fiind definii att ca operatori unari, ct i ca operatori binari. Interpretarea se face implicit, n funcie de numrul operanzilor crora se aplic. Operaia unar se descrie prin sintaxa: operator operand; Operaia binar se descrie prin sintaxa: operand_1 operator operand_2; Operaia ternar se descrie prin sintaxa: operand_1 operator operand_2 operator operand_3;

Observaie Operatorii sunt definii pentru a opera cu operanzi de tipuri predefinite. Limbajul C++ ofer mecanisme pentru supradefinirea acestora astfel nct s poat opera cu obiecte de tipuri definite de utilizator. 100

Operatorii limbajului C++ sunt prezentai n Tabelul nr. 6.1. Tabelul nr. 6.1. Operatorii limbajului C++ [] + < && -= ## () > || <<= sizeof . ~ <= ?: >>= new -> ! >= = &= delete ++ / == *= ^= :: -% != /= |= .* & << ^ %= , ->* * >> | += #

Observaie Operatorii # i ## aparin preprocesorului.

Operatorul de atribuire ( = ) Operaia cea mai frecvent folosit n programare este operaia de atribuire. Prin atribuire, se nscrie (memoreaz) o valoare ntr-o variabil (locaie de memorie). Este operaie binar, sintaxa general de utilizare a operatorului de atribuire fiind: operand_1 = operand_2; sau, n mod frecvent: variabila = expresie; Pe lng nscrierea unei valori ntr-o variabil, operaia returneaz valoarea variabilei, astfel c, se pot efectua atribuiri multiple cu sintaxa: variabila_1 = variabila_2== variabila_n = expresie; n urma atribuirii multiple, toate variabilele din expresie, variabila_1, , variabila_n, vor avea aceeai valoare, cea obinut prin evaluarea expresiei. int a; a=5; int b=7; a=b; b=a+10; // declaraia unei variabile // atribuirea unei valori constante unei variabile // declaraia unei variabile cu iniializare // atribuirea unei valori depus ntr-o variabil altei variabile // atribuirea valorii unei expresii unei variabile 101

a=b=100; a=a+b;

// atribuire multipl // expresia conine ca operand variabila ctre care se face // atribuirea; nti este evaluat expresia a+b cu valoarea pe care // o avea nainte de operaie i apoi se face operaia de atribuirea

operand_2 (expresie) se mai numete rvalue (right value - valoare dreapta). Acesta trebuie s fie o expresie care returneaz valoare. Expresia poate fi format din o constant, o variabil, apelul unei funcii care returneaz valoare, sau o expresie mai complex. operand_1 care se gsete n partea stng se mai numete lvalue (left value). Acesta trebuie s desemneze o locaie de memorie pentru care exist permisiunea de modificare a valorii. Astfel, lvalue poate fi numele unei variabile sau un pointer, dar nu poate fi o constant, o variabil declarat const, sau apelul unei funcii. int a = 15; const int ct = 100; ct = 99; protejat 5 = ct; a+5 = 20; a = getch(); getch() = a; // declaraie de variabil cu iniializare // declaraie de variabil const; iniializarea este obligatorie // eroare, se ncearc modificarea valorii unei variabile // prin specificatorul const // eroare, se ncearc modificarea unei constante literale // eroare, se ncearc atribuirea unei valori unei expresii // corect, se atribuie variabilei a valoarea din codul ASCII a // caracterului citit de la tastatur // eroare, se ncearc atribuirea unei valori unei funcii

Operaia de atribuire se poate efectua ntre tipuri de date diferite. n aceast situaie, se produc conversii implicite ale lvalue ctre tipul rvalue. Pot aprea dou situaii n efectuarea acestor conversii: tipul lvalue are reprezentare n domeniu de valori mai larg dect cel al rvalue aceste conversii nu produc efecte nedorite; tipul lvalue are reprezentare n domeniu de valori mai restrns dect cel al rvalue aceste conversii se efectueaz prin trunchierea valorilor, fapt ce poate duce fie la rotunjirea valorilor, fie la obinerea de valori aleatoare; situaiile sunt descrise n Tabelul nr. 6.2. Tabelul nr. 6.2. Conversii de tip la atribuire Tip lvalue char char char int Tip rvalue int unsigned char long int unsigned int Efect conversie Se preiau cei mai semnificativi 8 bii Dac valoarea este >127, se preia valoare negativ Se preiau cei mai semnificativi 8 bii Dac valoarea este >32767, se preia valoare negativ

102

Tip lvalue int int float double

Tip rvalue long int float double long double

Efect conversie Se preiau cei mai semnificativi 16 bii Se preia partea ntreag a valorii; dac aceasta depete domeniul int, se trunchiaz Se reduce precizia de reprezentare; dac i aa se depete domeniul float, se trunchiaz Se reduce precizia de reprezentare; dac i aa se depete domeniul long, se trunchiaz

Sunt prezentate cteva exemple: char ch = a ; int a = 10; char sir[20]; float r = 2.5; a = 1000; a = ch; ch = a;

// atribuire ntre date de acelai tip (int), nu se realizeaz // conversie // conversie cu lrgirea domeniului de valori, a va prelua // valoarea 97 (codul ASCII al caracterului a) // conversie cu reducere a domeniului de valori, valoarea se // ncadreaz n domeniul char, deci trunchierea nu va afecta // valoarea preluat // conversie cu reducere a domeniului de valori, valoarea nu se // ncadreaz n domeniul char, deci trunchierea va produce o // valoarea -24 // eroare, ch este de tip char, sir este adres de char; cele dou // tipuri sunt incompatibile, nu se poate face conversie, deci nici // atribuirea

ch = a;

ch = sir;

Observaie Conversiile predefinite se efectueaz la atribuire numai ntre tipuri de date numerice. ntre valori numerice i adrese de memorie nu se efectueaz conversii implicite.

Operatori aritmetici n categoria operatorilor unari se regsesc att operatori unari, ct i binari. Sunt prezentai n Tabelul nr. 6.3. 103

Tabelul nr. 6.3. Operatori aritmetici Tip operator Simbol + Unar ++ -+ Binar * / % Schimbarea semnului Incrementare Decrementare Adunare Scdere nmulire mprire Modulo restul mpririi ntregi Aciune Pstrarea semnului, nu produce nici o modificare

Operatorul + (unar) aplicat unei expresii va pstra valoarea expresiei. int a; a = +5;

// expresia +5 ntoarce valoarea 5

Operatorul - (unar) aplicat unei expresii va ntoarce valoarea expresiei cu semn schimbat. int a, b=2; a = -b; // expresia -b ntoarce valoarea lui b cu semn schimbat (-2); variabila b // nu este afectat de operaie, pstrndu-i valoarea, deci n final a=-2, b=2

Operatorii + - * / (binari) efectueaz i returneaz rezultatul operaiilor de adunare, scdere, nmulire, respectiv mprire. float r = 1.5, s = 3.2, t; t = r +s; // operaie de adunare t = r - s; // operaie de scdere t = r * s; // operaie de nmulire t = r / s; // operaie de mprire

Observaie mprirea ntregilor produce tot un ntreg prin trunchierea prii fracionare a rezultatului. Rezultatul operaiei 9/2 va fi 4 i nu 4.5 Operatorul % (binar) ntoarce restul mpririi a doi ntregi. int a = 15; int b; 104

b = a % 2; b = a % 1.5;

// b preia valoarea restului mpririi lui a la 2, deci preia valoarea 1 // eroare, unul dintre operanzi nu este ntreg.

Operatorii ++ i -- (unari) sunt operatori de incrementare, respectiv de decrementare. Operatorul ++ adun valoarea 1 la valoarea operandului. Operatorul scade valoarea 1 din valoarea operandului. Ambele operaii sunt nsoite de nlocuirea valorii operandului cu rezultatul obinut. Aceasta nseamn c operandul trebuie s fie o dat de tip lvalue, astfel nct atribuirea s se poat efectua. int a = 5 b = 10; ++a; // expresia este echivalent cu: a = a+1; a va primi valoarea 6 --b; // expresia este echivalent cu: b = b - 1; b va primi valoarea 9 Operatorii de incrementare (++) i de decrementare (--) pot fi prefixai sau post fixai. n primul caz, modificarea valorii operandului se face nainte de a-i folosi valoarea, n al doilea caz se folosete valoarea iniial a operandului i apoi se efectueaz modificarea acesteia. int i = 5, j; j = ++i j = i-- ;

// operatorul ++ este prefixat, deci nti se efectueaz operaia // de incrementare a lui i i apoi de face atribuirea ctre j, deci: // i=6, j=6; // operatorul -- este postfixat, deci nti se efectueaz operaia de // atribuire ctre j i apoi de face incrementare a lui i, deci: // i=5, j=6;

Aceti operatori se pot aplica numai datelor de tip lvalue, variabile desemnate prin nume sau pointeri. const int a = 3; a++; ++5 ; (i+j)-- ; ++(ghetchar());

// eroare, operatorul de incrementare se aplic unei variabile // const // eroare, operatorul de incrementare se aplic unei constante // eroare, operatorul de decrementare se aplic unei expresii // eroare, operatorul de incrementare se aplic unei funcii

Observaie Operaiile de incrementare, respectiv decrementare pot fi aplicate oricrui tip numeric de date, nu doar ntregilor: float r = 1.5; r++; // operaie valid r ia valoarea 2.5

105

Operatori relaionali Operatorii relaionali sunt operatori binari care se refer la relaiile dintre valorile operanzilor. Acetia sunt prezentai n Tabelul nr. 6.4. Tabelul nr. 6.4. Operatori relaionali Tip operator Simbol > >= Binar < <= == != Mai mare Mai mare sau egal Mai mic Mai mic sau egal Egal Diferit Aciune

Operaiile relaionale ntorc informaie despre faptul c relaia ntre operanzi este adevrat sau fals. Limbajele C/C++ nu au tipul de date boolean implementat, ci convenia de reprezentare este urmtoarea: - fals este reprezentat prin valoarea numeric 0 - adevrat este reprezentat prin orice valoare diferit de zero (de regul valoarea 1). Ca urmare, operaiile relaionale ntorc un rezultat care poate avea valoarea 0 sau 1. int a = 5; float r = 3.5; a > r; r >= a; a == r; a != r;

// expresia ntoarce valoarea 1 // expresia ntoarce valoarea 0 // expresia ntoarce valoarea 0 // expresia ntoarce valoarea 1

Operatori logici Operatorii logici pot fi unari sau binari. Ei realizeaz operaiile logice ntre valorile operanzilor. Acetia sunt prezentai n Tabelul nr. 6.5. Tabelul nr. 6.5. Operatori logici Tip operator Unar Binar Simbol ! && || i logic (AND) Sau logic (OR) Aciune Negare logic (NOT)

106

n interpretarea operaiilor logice se are n vedere modul de reprezentare a valorilor logice. Ca urmare, rezultatul acestor operaii se poate reprezenta prin tabelele de adevr prezentate n Fig. 6.1. p 0 1 !p 1 0 p 0 1 0 1 q 0 0 1 1 p && q 0 0 0 1 p 0 1 0 1 q 0 0 1 1 p || q 0 1 1 1

Fig. 6.1. Tabelele de adevr pentru operaiile logice

int a = 5, b=10; a && b; a && (!b); a || 3/2;

// ambii operanzi sunt diferii de 0 deci sunt logic adevrai; // rezultatul operaiei va fi 1 // (!b) returneaz valoarea 0, deci operaia && se face ntre un // operand adevrat i unul fals, rezultatul va fi 0 // operaia || se face ntre doi operanzi diferii de 0, deci rezultatul // va fi 1

Operatori la nivelul biilor Operaiile efectuate la nivel de bit apropie limbajele C/C++ de limbajul de asamblare. n mod curent, accesul la memorie se face la nivel de octet, octetul fiind cea mai mic unitate de memorie adresabil. Prin aceast categorie de operaii se pot face ns operaii la nivel de bit. Operaiile la nivel de bit se pot efectua cu operanzi de tip numeric ntreg. Nu se pot efectua astfel de operaii cu alte tipuri de date dect ntregi, deci nu se pot aplica datelor de tip real (float, double, long double). Operatorii la nivel de bit pot fi unari sau binari. Operatorii disponibili sunt prezentai n Tabelul nr. 6.6. Tabelul nr. 6.6. Operatori la nivel de bit Tip operator Unar Simbol ~ & ^ Binar | << >> Negare la nivel de bit i la nivel de bit Sau exclusiv la nivel de bit Sau la nivel de bit Deplasare la stnga (left shift) Deplasare la dreapta (right shift) Aciune

107

Modul de efectuare a acestor operaii a fost descris n unitatea de nvare nr. 01. int a=7, b=2, c; ~ a; a & b; a | b; a ^ b; a << b; a >> b;

// expresia returneaz valoarea -8 // expresia returneaz valoarea 2 // expresia returneaz valoarea 7 // expresia returneaz valoarea 5 // expresia returneaz valoarea 28 // expresia returneaz valoarea 1

Observaii Operaia de deplasare la stnga (a<<b) este echivalent cu operaia de nmulire a lui a cu 2b iar Operaia de deplasare la dreapta (a>>b) este echivalent cu operaia de mprire a lui a cu 2b. Modul de interpretare a acestor operaii reiese din reprezentarea binar a valorilor n memorie. Dac b are valoare relativ mare raportat la numrul biilor folosii n reprezentarea operandului a, se poate ajunge uor la depirea domeniului de valori, i ca urmare pierderea unor bii,

Operatorul sizeof (unar) Operatorul sizeof este un operator unar, care are ca rezultat un ntreg ce reprezint numrul de octei pe care este memorat operandul cruia i se aplic. Operandul este un tip de date sau o dat (constant sau variabil) de un anumit tip. Sintaxa de utilizare este: sizeof (expresie); sizeof(int); sizeof(double); sizeof(ab6de); int a sizeof( a * 1.5); // returneaz numrul de octei pe care este memorat un ntreg (2 sau 4) // returneaz numrul de octei pe care este memorat un double (8) // returneaz 6, nr. de octei pe care este memorat constanta // ir ab6de // returneaz numrul de octei pe care este memorat rezultatul // expresiei a *1.5, care este un double (8)

Operator & - adres (unar) Operatorul & (unar) a fost menionat n Cursul nr. 03 odat cu introducerea noiunii de variabil. Operatorul se aplic numelui unei variabile, rezultatul operaiei fiind adresa de memorie la care este alocat variabila respectiv. Sintaxa de utilizare este: &nume_variabila; 108

int a; &a; // returneaz adresa la care e alocat variabila a printf( %p , %u, &a, &a); // la execuia instruciunii se afieaz valoarea adresei // variabilei a n dou formate: hexazecimal (%p) i ntreg // zecimal fr semn (%u), de exemplu: FFF4, 65524

Operator condiional ? : (ternar) Singurul operator ternar disponibil n C/C++ este operatorul condiional. El este format din caracterele ? i : i se aplic la asupra a trei operanzi. Se folosete n expresii sub forma: e1 ? e2 : e3; Expresia e1 este evaluat prima. Dac valoarea acesteia este logic adevrat (nonzero), se evalueaz expresia e2 i aceasta este valoarea returnat de expresia condiional, n caz contrar, se evalueaz expresia e3, valoarea acesteia fiind cea returnat. int a, b, c; scanf(%d, &a); scanf(%d, &a); c = (a>b) ? a : b ;

// c primete ca valoare maximul dintre a i b

Expresia anterioar este echivalent cu secvena: dac (a>b) sau: if (a>b) c=a; else c=b; // if este instruciune de decizie care va fi prezentat n cursul // destinat prezentrii instruciunilor atunci c=a altfel c=b

Operatorul (tip) conversie explicit de tip (unar) Operatorul (tip) este un operator unar care apare n construcii numite cast sau typecast i convertete tipul operandului su la tipul specificat ntre paranteze. Se poate utiliza n orice expresie folosindu-se o construcie de forma: (nume_tip) expresie sau nume_tip (expresie) Rezultatul ntors de operaie este valoarea expresiei convertit n mod explicit la tipul de date precizat. Conversia se poate face fie ctre un tip de dat cu domeniu de valori mai larg dect al expresiei, sau ctre tip cu reprezentare mai restrns dect a expresiei. Expresia se 109

evalueaz similar conversiilor produse n mod implicit prin atribuire (vezi Tabelul 6.2.). int a=9; float r; (float) a; a/(float)2; r = 9/2; valoarea 4 r = (float)9 / 2; // 9 este convertit la tipul float, astfel c mprirea se va face ntre o // dat float i o dat int, rezultatul fiind float ; r va primi valoarea 4.5

// convertete operandul a (care era de tip ntreg) n float // convertete constanta 2, care este de tip int, la tipul float // se efectueaz mprirea ntreag, 9/2, rezultatul fiind 4 i apoi se face // atribuirea valorii lui r, astfel, dei r este de tip float, va prelua

Operatorul , virgul (binar) Operatorul virgul se folosete pentru a obine expresii complexe, alctuite dintr-o niruire de expresii. Sintaxa de utilizare a acestui operator este: expresie , expresie ; Valoarea operandului stnga este ignorat, operaia returnnd ca valoare valoarea expresiei situat n dreapta operatorului. int a = 5, b, c; c = ( b= 2*a, a+b); // evaluarea expresiei se face astfel: nti se atribuie variabilei b // valoarea 2*a, adic 10, apoi se evalueaz expresia a+b, // valoarea acesteia, 5+10, fiind valoarea ntoars de operatorul // virgul (,), astfel c variabila c primete valoarea 15

Operatorul ( ) parantez - operator binar Operatorul () se folosete pentru a fora ordinea de evaluare a expresiilor. Sunt situaii n care ordinea implicit de evaluare a expresiilor nu este convenabil, situaie n care se poate schimba aceast ordine prin folosirea parantezelor. int a = 2; int b; b = a + 2 * a +3; b = (a + 2) *( a +3);

// ordinea de evaluare este: se efectueaz nmulirea 2*a, apoi // se execut adunrile i n final se face atribuirea, deci b // primete valoarea 9 // ordinea de evaluare este: se evalueaz adunrile, ntre // rezultatele lor se efectueaz nmulirea i n final atribuirea, // deci b primete valoarea 20

Operatori de atribuire compui Operatorul de atribuire (=) poate fi combinat cu operatorii aritmetici sau cei la nivel de bit, rezultnd o scriere condensat a expresiilor.

110

Expresii de tipul: e1 = (e1) operator (e2); pot fi scrise ntr-o form condensat : e1 operator= e2; unde (operator= ) este operator de asignare n care operator poate fi unul dintre: + - * / % << >> & ^ | Astfel, se pot folosi expresiile extinse sau condensate, ca de exemplu: i = i+2; x= x*(y+1); a=a>>b; echivalent cu echivalent cu echivalent cu i+=2; x*=y+1; a>>=b;

Observaii Operatorii: * (unar), [ ], new, delete, .* , ->* vor fi prezentai n cursurile urmtoare

U6.2. Ordinea de evaluare a expresiilor La evaluarea expresiilor, se are n vedere o ordine de efectuare a operaiilor implicit, stabilit pe baza regulilor care stabilesc: prioritatea (precedena) indic ordinea de efectuare a operaiilor ntr-o expresie care conine operatori diferii; asociativitatea indic ordinea de efectuare a operaiilor care se ncadreaz n aceeai grup de preceden. Nivelurile de prioritate i ordinea de evaluare n cazul n care operatori consecutivi intr n alctuirea aceleiai expresii sunt prezentate n Tabelul nr.6.7. Se observ c operatorii unari au preceden mai mare dect majoritatea operatorilor binari. innd seama de regulile descrise prin Tabelul nr. 6.7., se pot scrie expresii echivalente, cum ar fi: c = a + b << 2; c = a + b + c; a > b && a >c ~!a echivalent cu echivalent cu echivalent cu echivalent cu c = (a + b) << 2; c = (a + b) + c (a > b) && (a > c) ~ ( ! a)

111

Tabelul nr. 6.7. Prioritatea i ordinea de evaluare a operatorilor Clasa de prioritate 1 2 Operatori ( ) [ ] -> :: . operatori unari: ! ~ + (tip) sizeof 3 4 5 6 7 8 9 10 11 12 13 14 15 16 .* * / + << >> < <= > >= ++ -->* % & * de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la stnga la dreapta de la dreapta la stnga de la dreapta la stnga de la stnga la dreapta new delete Asociativitate de la stnga la dreapta de la dreapta la stnga

= = != & ^ | && || ? : (operator condiional) = *= /= %= += &= ^= |= <<= , (operator virgul) -= >>=

Observaii Toi operatorii unari se afl n aceeai grup de prioritate, iar asocierea lor se face de la dreapta la stnga. Pentru a modifica ordinea de evaluare specificat n Tabelul nr. 6.7. se pot utiliza parantezele ( ) care vor impune ordinea gruprii operanzilor i operatorilor dorit de utilizator n evaluarea expresiilor.

112

U6.3. Conversii de tip n expresii Conversiile de tip se pot realiza implicit, sau explicit prin folosirea operatorului (tip). Dac ntr-o expresie apar operanzi de tipuri numerice diferite, se fac conversii implicite a operanzilor pentru fiecare operaie, astfel nct operaia s se efectueze ntre operanzi de acelai tip. Regula de baz const n conversia operandului de tip cu domeniu de valori mai mic ctre tipul cu domeniul de valori mai mare al celuilalt operand. Rezultatul fiecrei operaii este de tipul stabilit pentru operanzi. Excepia o constituie operaia de atribuire (=) care respect regulile descrise n paragraful de descriere a acestui operator. Valoarea membrului drept este convertit la tipul celui stng. n aceast situaie se pot efectua conversii de la un tip cu reprezentare pe un numr mai mare de octei la un tip cu reprezentare pe numr mai mic de octei, ceea ce poate provoca trunchieri (ex.: float -> int), rotunjiri (ex: double -> float) ale valorilor sau pierderea biilor de ordin superior n exces (ex: long int -> char). int i = 2; float r = 3.5; // valoarea constant 3.5, care are reprezentare double, // este convertit la tipul float i apoi este atribuit // variabilei r // 2.1 este de tip double, deci valoarea de tip int a // variabilei i se convertete la tipul double, rezultatul // returnat de operaia i+2.1 este de tip double, ca urmare // i valoarea variabilei float r se convertete la double, // rezultatul final al expresiei fiind i el de tip double

(i+2.1)*r

int i = 11; printf(%d, i / 2); // afieaz 5 ambii operanzi sunt de tip int, deci i // valoarea returnat este de tip int, astfel c exist // coresponden ntre format (%d) i tipul datei afiate // afieaz 5.5 se impune conversia operandului i la // tipul float, deci i operandul 2 se va converti la acelai // tip i n final tipul valorii returnate este tot float // afiare eronat se ncearc afiarea unei valori de tip // int n format float (%f)

printf(%f, (float) i / 2);

printf(%f, i/2);

113

Exemple

/**************************************************************************

Exemplu1 6.1. - Se scrie un program n care se exemplific folosirea operatorilor aritmetici si asimilai cu acetia: + - * / % ++ -- << >>
**************************************************************************/

#include <stdio.h> #include <conio.h> void main() { int a, b; printf("a="); scanf("%d", &a); printf("b="); scanf("%d", &b); printf("\n%d + %d = %d", a, b, a+b); printf("\n%d - %d = %d", a, b, a-b); printf("\n%d * %d = %d", a, b, a*b); printf("\n%d / %d = %d", a, b, a/b); printf("\n%d %% %d = %d", a, b, a%b); getch(); b=++a; printf("\nIncrementare (operatorul prefixat): a=%d, b=%d", a, b); b=a++; printf("\nIncrementare (operatorul postfixat): a=%d, b=%d", a, b); getch(); printf("\n%d << 3 = %d", a, a<<3); printf("\n%d >> 3 = %d", a, a>>3); getch(); }
/**************************************************************************

Exemplu1 6.2. - Se scrie un program n care se exemplific folosirea operatorilor la nivel de bit: ~ & | ^
**************************************************************************/

#include <stdio.h> #include <conio.h> void main() { int a, b; printf("a = "); scanf("%d", &a); 114

printf("b = "); scanf("%d", &b); printf("\n ~ %d = %d", a, ~a); printf("\n%d & %d = %d", a, b, a&b); printf("\n%d | %d = %d", a, b, a|b); printf("\n%d ^ %d = %d", a, b, a^b); getch(); }
/**************************************************************************

Exemplu1 6.3. - Se scrie un program n care se exemplific folosirea operatorilor aritmetici


**************************************************************************/

#include <stdio.h> #include <conio.h> void main() { int g, m, s; printf("grade:"); scanf("%d", &g); printf("minute ="); scanf("%d", &m); printf("secunde ="); scanf("%d", &s); m += s/60; s=s%60; g += m/60; m = m%60; g = g%360; printf("\nUnghiul este: %d grd. %d min %d sec.", g, m, s); getch(); }

/**************************************************************************

Exemplu1 6.4. - Se scrie un program n care se exemplific folosire a operatorului ternar ? : - se determina maximul dintre 3 valori.
**************************************************************************/

#include <stdio.h> #include <conio.h> void main() { int a, b, c, max; printf("a="); scanf("%d", &a);

115

printf("b="); scanf("%d", &b); printf("c="); scanf("%d", &c); //varianta 1 max = a>b ? a : b; max = max>c ? max : c; printf("\n Maximul dintre %d, %d, %d este: %d", a, b, c, max); //varianta 2 max = a>b && a>c ? a : b>c ? b : c ; printf("\n Maximul dintre %d, %d, %d este: %d", a, b, c, max); getch(); }

Rezumat Operatorii sunt simboluri care, aplicate unor operanzi (date - constante, variabile, expresii),au ca efect realizarea unor operaii care returneaz un rezultat. O succesiune valid de operanzi i operatori formeaz o expresie. Un criteriu de clasificare a operatorilor l constituie numrul de operanzi crora li se aplic. Operatorii se clasific n operatori unari (se aplic la un operand), operatori binari (se aplic la doi operanzi) i ternari (se aplic la trei operanzi). Prin atribuire, se nscrie (memoreaz) o valoare ntr-o variabil (locaie de memorie). Operatorii pot opera cu date de tipuri predefinite. Operaia de atribuire se poate efectua ntre tipuri de date diferite. n aceast situaie, se produc conversii implicite ale lvalue ctre tipul rvalue. Operaia modulo (% - restul mpririi ntregi) i operaiile la nivel de bit se pot efectua numai cu valori ntregi. Operaiile relaionale i logici, indiferent de tipul operanzilor crora li se aplic, returneaz valoare de tip int ( 0 fals; 1 adevrat). La evaluarea expresiilor se are n vedere o ordine de efectuare a operaiilor implicit, stabilit pe baza regulilor de prioritate i asociativitate. Dac ntr-o expresie apar operanzi de tipuri numerice diferite, se fac conversii implicite a operanzilor pentru fiecare operaie, astfel nct operaia s se efectueze ntre operanzi de acelai tip. Excepia o constituie operaia de atribuire (=) n care valoarea membrului drept este convertit la tipul celui stng.

116

Test de autoevaluare

1. Care din expresiile de mai jos sunt permise intr-un program C? a. int a = 25, b=3; a% = b; b. char d = '&', m; m=d+1; c. int a=2; printf(%d, !a) ; d. const float e = 2.71; e = e-2; e. #define PI 3.141 ++PI; 2. Care din secvenele de mai jos sunt permise intr-un program C? a. int i, j; i = 1 + ( j = 5 ); b. int a, b = -5; a = (!b) || (0e0); c. int a = 2; &a = 0x2000; d. int a = 2; printf("Adresa: %p\n", &a); e. int a = 7, b = 2, c; c = a << (++b); 3. Se considera declaratia: int a = 2, b = 1; Care din instruciunile de mai jos au ca efect final a=1 si b=2: a. b = -a; b. a- = b; c. a = ++b; d. b = --a; e. b = a--; 4. Se considera declaratia: int a = 7, b = 6; Care din instruciunile de mai jos au ca efect final coincidenta valorilor celor doua variabile: a. a- = 1; b. b = -a; c. a = --b; d. ++b; e. nici una 5. Care din secvenele de mai jos sunt permise intr-un program C? a. ++(++n); b. (&a)++; c. int x = sizeof(int); d. int y = sizeof(float); e. sizeof(float) = 4; 6. Secvena de instruciuni: int a = 9, b = 3, c; c = a << b; are ca efect atribuirea lui c a valorii: a. 27 b. 72 117

c. 3 d. 1 e. Nici una din cele de mai sus 7. Secvena de instruciuni: int a = 9, b = 2, c; c = a >> b; are ca efect atribuirea lui c a valorii: a. 20 b. 80 c. 160 d. 10 8. Ce fel de operator este operatorul: <= a. operator la nivel de bit b. operator relaional c. operator de atribuire d. operator logic e. nu este operator 9. Ce fel de operator este operatorul >> a. operator de deplasare b. operator logic c. operator relaional d. operator unar e. nu este operator 10. Care din atribuirile urmtoare sunt permise intr-un program C? a. 2+3 = b; b. x -= 3; c. b = 2 + (3++); d. a &= b; e. a --= b++; 11. Care este rezultatul operaiei: 25 & 42 a. 0 b. 8 c. 1 d. 59 e. nici unul din cele de mai sus 12. Care este rezultatul operaiei: 25 | 42 a. 0 b. 59 c. 8 d. 1 e. nici unul din cele de mai sus

118

13. Care este rezultatul operaiei: 25 ^ 42 a. 59 b. 51 c. 8 d. depire de domeniu e. eroare de sintaxa 14. Care este rezultatul operaiei: int a; a=7/2; este: a. 3 b. 3.5 c. 14 d. eroare de sintaxa e. nici unul din cele de mai sus 15. Rezultatul instruciunii: x = ! ( 6%3 ) && ( 7 >> 3 ); este atribuirea lui x a valorii: a. 0 b. 1 c. 2 d. nici una din valorile de mai sus

ntrebri. Exerciii. Probleme. 1. Sa se scrie un program in care se declar o variabil de tip char, una de tip int, una float, una double i un ir de caractere. Se citesc valori de la tastatur pentru cele cinci variabile. S se afieze valoarea, adresa, numr de octeti ocupai pentru fiecare variabil. 2. S se scrie un program n care se declar o variabil de tip int. Se citete valoarea variabilei de la tastatur. S se afieze rezultatele operaiilor unare care pot fi efectuate cu aceast variabil, ca n exemplul prezentat.

119

3. S se scrie un program n care se declar o variabil de tip float. Se citete valoarea variabilei de la tastatur. S se afieze rezultatele operaiilor unare care pot fi efectuate cu aceast variabil (vezi problema nr. 2). 4. S se scrie un program n care se declar dou variabile de tip int. Se citesc valori de la tastatur. S se afieze rezultatele tuturor operaiilor binare care pot fi efectuate cu aceste variabile, ca n exemplul prezentat.

5. S se scrie un program n care se declar dou variabile de tip float. Se citesc valori de la tastatur. S se afieze rezultatele tuturor operaiilor binare care pot fi efectuate cu aceste variabile, ca n exemplul prezentat.

120

Unitatea de nvare U.7. INSTRUCIUNI (1)

Cuprins Introducere .................................................................................................................. 121 Obiectivele unitii de nvare ................................................................................... 122 U7.1. Algoritmi ........................................................................................................... 122 U7.1.1. Generaliti ......................................................................................... 122 U7.1.2. Reprezentarea algoritmilor ................................................................. 123 U7.2. Instruciunea expresie ....................................................................................... 127 U7.3. Instruciunea compus (blocul de instruciuni) ................................................. 128 U7.4. Instruciuni de selecie (decizie) ....................................................................... 130 U7.4.1. Instruciunea de decizie if, if-else ....................................................... 130 U7.4.2. Instruciunea de selecie multipl switch ............................................ 132 Exemple ...................................................................................................................... 135 Rezumat ...................................................................................................................... 137 Test de autoevaluare ................................................................................................... 138 ntrebri, exerciii i probleme .................................................................................... 139

Introducere Aa cum s-a artat, calculatorul prelucreaz datele de intrare printr-o succesiune de transformri pentru a obine datele de ieire. Succesiunea de prelucrri este descris prin program. Fiecare prelucrare este rezultatul uneia sau mai multor instruciuni. Ordinea de efectuare a prelucrrilor este important, ea respectnd un anumit algoritm. Avnd n vedere faptul c un program este construit pe baza unui algoritm, n aceast unitate de nvare vor fi prezentate generaliti despre algoritmi i modul de reprezentare a acestora. Prezentarea algoritmilor nu este exhaustiv, avnd n vedere faptul c prezentul curs are ca subiect de interes limbaje de programare (C/C++), prezentarea se limiteaz doar la cteva aspecte necesare n nelegerea instruciunilor specifice limbajelor de programare i a structurrii programelor. n continuare sunt prezentate instruciunile specifice limbajelor C/C++. n prezenta unitate de nvare sunt prezentate instruciunile expresie, instruciuni compuse i instruciunile de decizie, celelalte instruciuni urmnd a fi discutate n unitatea de nvare nr. 8. 121

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Algoritmi - generaliti; reprezentarea algoritmilor prin scheme logice i limbaj pseudocod; Structurile de baz folosite n realizarea algoritmilor - structuri de control; Instruciunile limbajelor C/C++: expresie, instruciune compus, if/if-else, switch.

Durata medie de parcurgere a celei de a aptea uniti de nvare este de 2 ore.

U7.1. Algoritmi U7.1.1. Generaliti Pot fi scrii algoritmi care s descrie activiti din cele mai diverse domenii de via, dar algoritmii destinai scrierii programelor de calculator sunt cei care rezolv probleme ce admit o formulare matematic. Algoritmul este o metod general de rezolvare a unei probleme, metod care se poate implementa n programe prin intermediul unui limbaj de programare. Algoritmul poate fi gndit ca o succesiune de aciuni ce se pot aplica pentru obinerea unui rezultat. n toate domeniile exist activiti care pot fi descrise prin algoritmi. De exemplu, adunarea a dou fracii se realizeaz urmnd urmtorii pai: - se amplific fraciile pentru a le aduce la acelai numitor; - se efectueaz adunarea numrtorilor; - se simplific fracia obinut. Algoritmii folosesc obiecte cu care se realizeaz diverse operaii. Algoritmii se caracterizeaz prin: generalitate proprietatea care descrie faptul c ofer o strategie de rezolvare a unei probleme de un anumit tip; finitudine obinerea datelor de ieire se face ntr-un numr finit de pai i ntr-un timp finit; unicitate succesiunea de operaii este determinat n mod unic; realizabilitate toate operaiile descrise de algoritm pot fi realizate cu resursele existente; eficiena aceast caracteristic are n vedere att timpul cerut pentru execuie (complexitatea-timp), ct i resursele necesare pentru execuie, cum ar fi memorie, numr de

122

regitri etc. (complexitate-spaiu) aceast caracteristic este influenat i de maina pe care este implementat algoritmul. Etapele care trebuie urmate de la enunul problemei de rezolvat pn la obinerea produsului software final (programul) sunt urmtoarele: stabilirea caietului de sarcini (enunul problemei) trebuie s fie bine definit, astfel nct s fie clar ce trebuie s se execute; de regul este elaborat de utilizatorul programului mpreun cu programatorul; elaborarea algoritmilor se face pe baza analizei problemei, prin aplicarea unor tehnici de elaborare; obinerea unor algoritmi eficieni presupune i o oarecare experien de lucru ; exprimarea algoritmilor se face prin intermediul unui limbaj de programare folosit n implementarea algoritmului care trebuie s fie clar i concis; modul de abordare depinde de tipul limbajului utilizat, astfel, n anii 80 stilul era programarea structurat, ulterior s-a impus programarea orientat pe obiecte (C++ permite ambele abordri). validarea algoritmilor este etapa n care se obine confirmarea corectitudinii algoritmului, indiferent de limbajul folosit; analiza algoritmilor se face pe baza unui criteriu de apreciere stabilit care permite alegerea celui mai eficient algoritm; se poate avea n vedere memoria utilizat, viteza de execuie, etc. testarea programului presupune depanarea programului i trasarea, adic determinarea memoriei necesare i a timpului de calcul, etap care se realizeaz prin execuii repetate cu seturi de date de intrare diferite.

U7.1.2. Reprezentarea algoritmilor n general, descrierea algoritmului este o etap intermediar ntre formularea matematic i programul scris ntr-un limbaj oarecare. Descrierea algoritmului se poate face folosind diferite metode. Frecvent folosite sunt urmtoarele: - reprezentarea n limbaj natural acest mod de reprezentare nu presupune o pregtire special, dar pentru probleme complexe poate introduce neclariti; - reprezentarea prin scheme logice este o reprezentare grafic n care fiecare etap este reprezentat printr-un bloc, blocurile fiind nlnuite prin segmente orientate, ordinea lor respectnd logica problemei ; - reprezentarea n limbaj pseudocod limbajul pseudocod este apropiat de codificarea din Pascal sau C, permite o reprezentare clar i concis; - reprezentarea prin tabele de decizie metoda e specific problemelor cu numr mare de alternative, ele apelnd la logica boolean inventariaz toate aciunile posibile prin combinarea condiiilor precizate. Pentru etapa de familiarizare cu un limbaj de programare i cu logica algoritmic i 123

utilizarea structurilor de control, metoda de reprezentare prin scheme logice, care este o metod ilustrativ, este sugestiv, etapele i fluxul de prelucrare fiind uor de urmrit. Exist trei tipuri de scheme logice: - scheme de program care descriu toate procesele de prelucrare pornind de la datele de intrare pn la obinerea rezultatelor; - scheme de detaliere care descriu procese complexe la nivel de detaliu, secvenele aprnd o singur dat n program; - scheme de subprograme (rutine) care descriu procese repetabile n program. Blocurile folosite pentru reprezentarea etapelor de evoluie a algoritmului sunt urmtoarele: Blocuri de control delimiteaz nceputul i sfritul schemei logice.

Pentru scheme program:

Pentru scheme de detaliere:

Pentru scheme de subprogram:

Prin nume se precizeaz numele rutinei, iar parametrii formali precizeaz datele care vor fi prelucrate de aceasta. Blocuri de intrare/ieire precizeaz datele de intrare, respectiv cele de ieire ale algoritmului.
-

bloc comun celor dou tipuri de operaii: blocuri distincte pentru operaiile de intrare/ieire:

Blocuri de atribuire precizeaz expresia de evaluat i variabila creia i se atribuie rezultatul:

124

Blocuri de decizie marcheaz punctele de ramificare a programului i expresia condiional care determin evoluia algoritmului n continuare.

Blocuri de blocuri insereaz n algoritm un subprogram predefinit, preciznd numele acestuia.

Blocuri de apel rutine apelul unei rutine pentru care se precizeaz numele acesteia i valorile transmise pentru parametri.

Blocuri de conectare se folosesc pentru algoritmi compleci, pentru sporirea lizibilitii algoritmului. Conectare n pagin - pentru evitarea intersectrilor arcelor ce unesc blocurile

Conectare ntre pagini se folosesc atunci cnd algoritmul nu se poate reprezenta pe o singur pagin.

Pentru realizarea schemelor logice, n anii 70, s-au impus principiile programrii structurate. Acestea au dus la o puternic dezvoltare a limbajelor de programare. Prin aplicarea principiilor programrii structurate, se obine: - claritate n citirea programelor; - depanarea uoar a programelor; - generalitatea programelor i uurin n refolosirea codului scris. Structurile de control care stau la baza programrii structurate sunt: - structura secvenial; - structura alternativ; - structura repetitiv.

125

Structura secvenial reprezint o nlnuire de prelucrri n care o prelucrare ncepe numai dup finalizarea precedentei.

Structuri alternative (de decizie) selecteaz variante de prelucrate n funcie de condiiile evaluate prin intermediul unei expresii logice. Acestea pot fi: Structura pseudo-alternativ (fig. 7.1.) Structura alternativ simpl (fig. 7.2.) Structura alternativ multipl (fig. 7.3.)

Fig. 7.1. Structur pseudo-alternativ

Fig. 7.2. Structur alternativ simpl

Fig. 7.3. Structur alternativ multipl

Structuri repetitive descriu un proces ce se repet n funcie de ndeplinirea anumitor condiii: Structura repetitiv cu test anterior (test iniial) (fig. 7.4.) Structura repetitiv cu test posterior (test final) (fig. 7.5.) Structura repetitiv cu contor (fig. 7.6.)

126

Fig.7.4. Structur repetitiv cu test iniial

Fig.7.5. Structur repetitiv cu test final

Fig.7.6. Structur repetitiv cu contor

U7.2. Instruciunea expresie Prelucrrile efectuate de program sunt descrise prin instruciuni. Modificrile fcute asupra unor variabile se realizeaz prin operaia de atribuire, valoarea atribuit fiind rezultatul evalurii unei expresii. Instruciunea care realizeaz acest lucru se numete instruciune expresie. Toate celelalte instruciunile stabilesc succesiunea prelucrrilor folosind cele trei structuri de control: secveniale (succesiuni de operaii, instruciuni compuse), de decizie i repetitive. O instruciune expresie este o expresie care se ncheie cu punct i virgul (;) sintaxa fiind: < expresie > ; Exemple de instruciuni expresie: int i, j; float r; i = 10; j = i * 5; r = (float) i / j + 1.5 ; Instruciunile se pot scrie pe mai multe linii de program, spaiile nesemnificative fiind ignorate. int i; i= 5; Pe o linie de program se pot scrie mai multe instruciuni.

127

int i, j; i = 2; j += i; Pot fi incluse instruciuni expresie care nu produc efecte. Acestea sunt semnalate de compilator printr-un mesaj de atenionare (warning - cod as no efect). Acestea nu introduc erori n evoluia programului, dar ncarc n mod inutil codul. Instruciunea vid se ncadreaz tot n categoria instruciunilor expresie. Instruciunea vid are forma: ; Instruciunea vid semnific lipsa oricrei aciuni. Ea este util n anumite situaii cnd sintaxa impune o instruciune, ns programul nu cere nici o aciune. Exemplele de folosire a instruciunii vide vor fi incluse n paragrafele urmtoare.

U7.3. Instruciunea compus (blocul de instruciuni) Instruciunea compus grupeaz declaraii i instruciuni, nceputul i sfritul blocului fiind marcat de acolade ({ }). Blocul de instruciuni este sintactic echivalent cu o instruciune. Sintaxa general este: { lista_declaratii; lista_instructiuni; } Coninutul unui bloc de instruciuni poate fi descris ntr-un algoritm printr-o structur secvenial. Instruciunile compuse se utilizeaz deseori n combinaie cu instruciunile de ciclare i cele de decizie.

Observaii Toate variabilele declarate n interiorul unei instruciuni compuse nu pot fi accesate n afara acesteia, domeniul lor de existen fiind blocul de instruciuni. Exemplu de utilizare a blocului de instruciuni: #include <stdio.h> void main() { int i; int k;

// se declar i, variabil local funciei main() // se declar k, variabil local funciei main() 128

i=7; k=12; { int i; int j; i=9; j=2*i; k++;

// nceputul blocului // se declar variabila i local blocului // se declar variabila j local blocului // se folosete variabila i local blocului // n interiorul blocului se folosete // variabila k, declarat n main(), ea avnd // ca domeniu ntreaga funcie, inclusiv // blocul de instruciuni // se afieaz i=9 , valoarea variabilei // locale blocului de instruciuni // se afieaz j=18 // se afieaz k=12 // sfritul blocului // se afieaz i=7, valoarea variabilei locale // funciei main() // eroare, instruciunea se afl n afara // domeniului de existen a lui j // se afieaz k=13

printf(\ni=%d, i); printf(\nj=%d, j); printf(\nk=%d, k); } printf(\ni=%d, i); printf(\nj=%d, j); printf(\nk=%d, k); }

Observaii Variabilele declarate n interiorul unui bloc, sunt locale acelui bloc: se aloc n memorie doar n momentul n care se execut blocul i nceteaz s existe odat cu terminarea acestuia. Domeniul acestor variabile este blocul de instruciuni i durata de via este perioada execuiei blocului. Variabila k este declarat n main(), nainte de blocul de instruciuni, ea va avea ca domeniu ntreaga funcie main(), deci va putea fi folosit i n interiorul blocului. Dac exist variabile cu acelai nume att n afara blocului, ct i n interiorul lui, cea extern lui nu va putea fi accesat, prioritate avnd cea local blocului. n situaia din exemplu nu se poate folosi operatorul de rezoluie (::), acesta putnd fi folosit doar n cazul variabilelor globale. Ambele variabilele cu numele i sunt variabile locale, cu alocare pe stiv. Variabila j este local blocului de instruciuni, ea ncetnd s existe odat cu ncheierea blocului de instruciuni, deci n afara acestuia nu poate fi referit. n limbajul C declaraiile de variabile de fac la nceputul blocului, n timp ce, n cazul limbajului C++ pot fi fcute oriunde n blocul respectiv, nainte

129

de utilizarea lor. Totui, pentru a da lizibilitate programului, este de preferat ca aceste declaraii s se fac la nceputul blocului i n cazul limbajului C++.

U7.4. Instruciuni de selecie (decizie) U7.4.1. Instruciunea de decizie if, if-else Sintaxa instruciunii poate fi: if(condiie) (1) instruciune_1; sau if(condiie) instruciune_1; (2) else instruciune_2 Instruciunea if evalueaz logic expresia condiie. Se are n vedere faptul c se interpreteaz valoare logic adevrat orice valoare numeric diferit de 0 (zero), i logic fals valoarea 0. Deci, n cazul n care valoarea expresiei condiie este nenul, se execut instruciune_1, iar dac este nul se execut instruciunea imediat urmtoare instruciunii if, pentru prima form a sintaxei, sau instruciune_2 n cazul celei de a doua forme. Instruciunea if / if-else reprezint o structur alternativ, prima form, (1), fiind o structur pseudo-alternativ, cea de a doua, (2) reprezentnd structura alternativ simpl. Expresia condiie trebuie s fie o expresie scalar, care returneaz o valoare. De exemplu, dac se dorete ca o variabil s pstreze valoarea sa absolut, se poate folosi instruciunea if (secven pseudo-alternativ): int a; ... if (a < 0) a = -a; ... // // instruciunea if pseudo-alternativ // poate fi descris n schem logic // prin figura alturat //

Observaii Secvena scris anterior poate fi scris i folosind operatorul ternar, folosind instruciunea: a = (a < 0) ? a : a ; Dac se dorete determinarea maximului dintre dou valori, se poate folosi instruciunea if else (secven alternativ simpl):

130

int a, b, max; ... if (a > b) max = a; else max = b; ...

// // // instruciunea if else poate fi // descris n schem logic prin // figura alturat // //

Observaii Alt variant de scriere a secvenei anterioare poate folosi o secven pseudo-alternativ (if): max = a; if (max < b) max = b; Secvena scris anterior poate fi scris i folosind operatorul ternar, folosind instruciunea: max = (a >b 0) ? a : b ; Nu se poate nlocui instruciunea if / if-else cu operatorul ternar n orice situaie. Acest lucru este posibil doar dac instruciune_1 i instruciune_2 returneaz valoare compatibil cu tipul variabilei aflat n stnga operatorului de atribuire. Prin folosirea operatorului ternar rezult un cod mai compact, dar folosirea instruciunii if este mai sugestiv i face mai uoar citirea programului. Instruciunea if/if-else poate fi folosit i pentru descrierea secvenelor alternative multiple. n acest caz se recurge la folosirea instruciunilor if imbricate, adic, una, sau ambele dintre instructiune_1 i instructiune_2 pot fi la rndul lor instruciuni if/if-else. Pentru ilustrarea scrierii acestor secvene, se ia ca exemplu secvena urmtoare, n care se determin maximul dintre dou valori: int a, b, c, max; ... if(a>b) if(a>c) max = a; else max = c; else if(b>c) max = b; else max = c; // Secvena poate fi reprezentat prin figura alturat // // // // // // // // // //

131

Aceeai secven se poate rescrie n diferite variante. n general, orice problem poate fi implementat n diferite variante. Aceasta depinde de stilul adoptat de programator i, de multe ori, o variant este adoptat n urma analizei algoritmului adoptat, astfel nct s se obin eficien ct mai mare. In continuare este prezentat o alt variant de secven care determin maximul dintre trei valori. int a, b, c, max; ... if(a>b && a>c) max = a; else if(b>c) max = b; else max = c; ... // Secvena poate fi reprezentat prin figura alturat // // // // // // // // //

U7.4.2. Instruciunea de selecie multipl switch Instruciunea switch este o instruciune decizional, ea permind selecia, n funcie de valoarea unei expresii, ntre mai multe opiuni posibile. Sintaxa instruciunii este: switch (expr) { case const1: lista_instructiuni; <break;> case const2: lista_instructiuni; <break;> .. <default> lista_instructiuni; } unde: expr este o expresie ntreag (orice tip ntreg sau enumerare); const1, const2,... sunt constante de selecie, de tip ntreg, cu valori distincte; lista_instructiuni este o secven de instruciuni; La execuia instruciunii, se evalueaz expr. Valoarea obinut se compar succesiv cu valorile constantelor de selecie. Dac se gsete identitate de valoare, se execut succesiunea de instruciuni asociat. Instruciunea break ntrerupe execuia instruciunii switch. Dac lista_instruciuni nu este urmat de break, se continu execuia cu lista de instruciuni ataat urmtoarei etichete.

132

Dac valoarea expresiei nu se regsete printre etichete, se execut secvena de instruciuni asociat cu eticheta default. n lipsa acesteia, se finalizeaz execuia instruciunii switch. Pentru exemplificarea folosirii instruciunii switch este prezentat n continuare urmtoarea aplicaie: Se citesc de la tastatur dou valori numerice ntregi. Se citete de la tastatur operaia care se dorete a se efectua ntre aceti doi ntregi (+, -, *, /, %) i se afieaz rezultatul acesteia. #include <stdio.h> void main() { int a, b; char op;

// variabile folosite pentru citirea celor doi ntregi // variabila op este folosit pentru citirea ca i caracter a tipului // de operaie dorit printf("Introdu doua valori intregi:"); printf("\na="); scanf("%d", &a); printf("\nb="); scanf("%d", &b); printf("Introdu un operator aritmetic, simplu, binar (+, -, *, /, %) :"); fflush(stdin); scanf("%c", &op); switch (op) { case ('+'): printf("\n Operatia de adunare - rezultat: %d", a+b); break; case ('-'): printf("\n Operatia de scadere - rezultat: %d", a-b); break; case ('*'): printf("\n Operatia de inmultire - rezultat: %d", a*b); break; case ('/'): printf("\n Operatia de impartire - rezultat: %d", a/b); break; case ('%'): printf("\n Operatia de impartire intreaga - rest: %d", a%b); break; default: printf("\nOperatie ilegala!"); } // golirea buffer-ului de intrare astfel nct citirea urmtoare, a // caracterului care desemneaz operaia, s se fac corect // citirea se face n format caracter // expresia folosit pentru selecie este chiar valoarea // caracterului citit de la tastatur

} Secvena switch care selecteaz operaia aritmetic ce se efectueaz implementeaz schema logic din Fig. 7.7. 133

Fig.7.7. Schema logic pentru secvena se selecie a operaiei

Observaii Selecia multipl se poate implementa, aa cum am vzut, folosind instruciunea if/if-else, dar, dac selecia este controlat de valoarea unei singure expresii, este mai eficient i mai clar s se foloseasc instruciunea switch. Instruciunea switch evalueaz doar egalitatea de valori, n timp ce if poate evalua orice tip de expresie relaional sau logic. Dac n instruciunea switch constantele sunt de tip caracter, automat sunt convertite la ntreg prin codul ASCII corespunztor. ntr-o instruciune switch nu pot exista mai multe constante case cu valori identice. Se pot asocia mai multe etichete scrise consecutiv cu aceleai secvene de instruciuni. Aceast situaie se regsete n exemplul urmtor. Se dorete asocierea caracterelor ce reprezint o cifr hexazecimal cu valoarea numeric corespunztoare n baza 10. Caracterele pot fi: 0, 1, 2,...9, a, A, b, B..., f, F. char cifra; int i; //...

134

switch (cifra) {case 0: i=0; break; case 1: i=1; break; //... case 9: i=9; break; case a: case A: i=10; break; case b: case B: i=11; break; case c: case C: i=12; break; case d: case D: i=13; break; case e: case E: i=14; break; case f: case F: i=15; }

// dac cifra are ca valoare caracterul a sau A // i primete aceeai valoare, 10 // dac cifra are ca valoare caracterul b sau B // i primete aceeai valoare, 11 // dac cifra are ca valoare caracterul c sau C // i primete aceeai valoare, 12 // dac cifra are ca valoare caracterul d sau D // i primete aceeai valoare, 13 // dac cifra are ca valoare caracterul e sau E // i primete aceeai valoare, 14 // dac cifra are ca valoare caracterul f sau F // i primete aceeai valoare, 15 // fiind ultima instruciune din secvena switch, nu // este necesar instruciunea break

Exemple

/**************************************************************************

Exemplu1 7.1. - Se scrie un program pentru rezolvarea ecuaiei de gradul II: a x2 + b x + c = 0


**************************************************************************/

#include <stdio.h> #include <conio.h> #include <math.h> #include <stdlib.h> void main() {float a, b, c, delta, x1, x2; printf("coeficientul lui x^2:"); if (scanf("%f", &a)!=1) {printf("Coeficientul lui x^2 este incorect!\n"); getch(); return; // se poate folosi si apelul functiei: exit(0); } printf("coeficientul lui x:"); if (scanf("%f", &b)!=1) {printf("Coeficientul lui x este incorect!\n"); getch(); return; // exit(0); }

135

printf("termenul liber:"); if (scanf("%f", &c)!=1) {printf("Termenul liber este incorect!\n"); getch(); return; // exit(0); } if (a==0 && b==0 && c==0) {printf("Ecuatie nedeterminata !\n"); getch(); return; // exit(0); } if (a==0 && b==0) {printf("Ecuatie imposibila !\n"); getch(); return; // exit(0); } if (a==0) {printf("Ecuatie de grad I"); printf("\nSolutia este: x=%.2f\n", -c/b); getch(); return; // exit(0); } delta= b*b - 4*a*c; if ( delta<0) {printf("radacini complexe\n"); printf("x1= %.2f + i %.2f\n", -b/(2*a), sqrt(-delta)/(2*a)); printf("x2= %.2f - i %.2f\n", -b/(2*a), sqrt(-delta)/(2*a)); getch(); return; // exit(0); } if ( delta==0 ) {printf("Radacini reale si egale:\n"); printf("x1=x2=%.2f\n", -b/(2*a)); getch(); return; // exit(0); } printf("Radacini reale si distincte:"); printf("\nx1=%.2f\n", (-b+sqrt(delta))/(2*a)); printf("\nx2=%.2f\n", (-b-sqrt(delta))/(2*a)); getch(); }

/**************************************************************************

Exemplu1 7.2. - Se scrie un program care citete de la tastatur un ntreg. Corespunztor valorii acestuia se afieaz denumirea zilei corespunztoare din sptmn.
**************************************************************************/

#include<stdio.h> #include<conio.h>

136

main() { int zi; printf("\nIntrodu un numar <=7 :"); scanf("%d", &zi); switch (zi) { case 1: printf("\nZiua %d este Luni", zi);break; case 2: printf("\nZiua %d este Marti", zi);break; case 3: printf("\nZiua %d este Miercuri", zi);break; case 4: printf("\nZiua %d este Joi", zi);break; case 5: printf("\nZiua %d este Vineri", zi);break; case 6: printf("\nZiua %d este Sambata", zi);break; case 7: printf("\nZiua %d este Duminica", zi);break; default: printf("\nValoarea introdusa este incorecta !"); } printf("\n"); getch(); }

Rezumat La ntocmirea unui algoritm, trebuie s se asigure proprieti cum sunt: generalitate, finitudine, unicitate, realizabilitate, eficien. Reprezentarea algoritmilor se poate face n diferite moduri, frecvent folosite fiind reprezentarea n limbaj pseudocod i reprezentarea prin scheme logice. Pentru realizarea schemelor se aplic principiile programrii structurate care presupun folosirea structurilor de control secvenial, alternativ i repetitiv. Modificrile fcute asupra unor variabile se realizeaz prin operaia de atribuire, valoarea atribuit fiind rezultatul evalurii unei expresii. Instruciunea vid semnific lipsa oricrei aciuni; ea este format numai din caracterul punct i virgul (;). Instruciunea compus grupeaz declaraii i instruciuni, nceputul i sfritul blocului fiind marcat de acolade ({ }). Variabilele declarate n interiorul unei bloc de instruciuni au ca domeniu de existen blocul n care au fost declarate. Instruciunea if-else este o instruciune de decizie care permite alegere ntre dou variante de evoluie a programului n funcie de valoarea unei expresii condiionale. Instruciunea switch este o instruciune decizional care permite selecia, n funcie de valoarea unei expresii, ntre mai multe opiuni posibile.

137

Test de autoevaluare

1. Secvena de program : #include<stdio.h> void main() { int a=3,b=7; if (!(a-b)) { else } { }

a++; printf("%d\n", a); b++; printf("%d\n", b);

} va produce : a. incrementarea variabilei b si apoi afisarea sa b. incrementarea variabilei a si apoi afisarea sa c. eroare de sintaxa d. nici un rspuns nu este corect 2. Secvena de program : #include<stdio.h> void main() { int a=3, b=5, c=2, x; if(a<b) if(a<c) x=a; else x=c; } va produce : a. atribuirea lui x a valorii lui c b. atribuirea lui x a valorii lui a c. eroare de sintaxa d. nici un rspuns nu este corect 3. Se considera instruciunile : switch(i){ case 1 : i+=2; break; case 2 : i+=3; default: i+=4; } printf("%d\n", i); Care propoziii sunt adevrate ? a. daca i=1, se va afisa valoarea 3 b. daca i=1, se va afisa valoarea 2 c. daca i=8, se va afisa valoarea 12 d. daca i=2, se va afisa valoarea 5 4. Se considera secvena de program : switch(i) { case 1: i+=2;break; case 2: i+=3; 138

default: i+=4; } printf("%d\n", i); Care propoziii sunt corecte ? a. daca i=2, se va afisa valoarea 9 b. daca i=2, se va afisa valoarea 5 c. daca i=6, se va afisa valoarea 10 d. daca i=1, se va afisa valoarea 3 5. Se considera secvena de program : switch(i) { case 1: i+=2; break; case 2: i+=3; case 3: i+=4; } printf("%d\n", i); Care propoziii sunt corecte ? a. daca i=2, se va afisa valoarea 5 b. daca i=1, se va afisa valoarea 3 c. daca i=4, va apare o eroare d. daca i=2, se va afisa valoarea 9

ntrebri. Exerciii. Probleme. 1. S se scrie un program n care se declar o variabil de tip int pentru care se citete valoare de la tastatur. S se afieze un mesaj care s indice dac valoarea este par sau impar. 2. S se scrie un n care se declar trei variabile de tip float pentru care se citesc valori de la tastatur. S se verifice dac valorile pot reprezenta laturile unui triunghi i dac da, s se calculeze i s se afieze aria triunghiului. 3. Sa se scrie un program in care se citeste de la tastatura o data calendaristica (zi, luna, an - citite ca valori ntregi). Sa se afieze data, pentru luna fiind afiata denumirea. De exemplu, data 15.10.2009 va fi afiat 15 octombrie 2009. In secvena de afisare se va folosi instruciunea switch. 4. S se scrie un program n care se declar dou variabile de tip int pentru care se citesc valori de la tastatur. Se selecteaz tipul operaiei care se dorete a se efectua ntre cele dou valori prin apsarea simbolului asociat operaiei ( +, -, *, /, %). 139

Unitatea de nvare U.8. INSTRUCIUNI (2)

Cuprins Introducere .................................................................................................................. 140 Obiectivele unitii de nvare ................................................................................... 140 U8.1. Instruciuni de ciclare (repetitive) ..................................................................... 141 U8.1.1. Instruciunea de ciclare cu test iniial (while) ..................................... 141 U8.1.2. Instruciunea de ciclare cu test final (do-while) ................................. 143 U8.1.3. Instruciunea de ciclare cu contor (for) ............................................... 145 U8.2. Instruciuni de salt ............................................................................................. 147 U8.2.1. Instruciunea break.............................................................................. 147 U8.2.2. Instruciunea continue......................................................................... 149 U8.2.3. Instruciunea return ............................................................................. 150 U8.2.4. Funcia exit()....................................................................................... 151 U8.2.5. Instruciunea de salt necondiionat goto ............................................. 153 Exemple ...................................................................................................................... 154 Rezumat ...................................................................................................................... 156 Test de autoevaluare ................................................................................................... 157 ntrebri, exerciii i probleme .................................................................................... 159

Introducere Prezenta unitate de nvare continu prezentarea instruciunilor specifice limbajelor C/C++. Sunt prezentate instruciunile repetitive care permit executarea n mod repetat a unor secvene de program att timp ct o condiie (expresie) este logic adevrat (while, do-while, for). Pentru a fora ntreruperea execuiei structurilor secveniale, alternative sau repetitive, se pot folosi instruciuni de salt (break, continue, return, goto) sau funcia exit(). Se poate ntrerupe execuia unui bloc de instruciuni, a unei funcii sau chiar a programului n totalitatea sa.

140

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Sintaxa i modul de utilizare a instruciunilor repetitive ale limbajelor C/C++; Sintaxa i modul de utilizare a instruciunilor de salt ale limbajelor C/C++ .

Durata medie de parcurgere a celei de a opta uniti de nvare este de 2 ore.

U8.1. Instruciuni de ciclare (repetitive) U8.1.1. Sintaxa instruciunii este: while (expresie) instruciune; unde expresie e orice expresie logic, iar instruciune, o instruciune simpl sau bloc de instruciuni. La execuie, se testeaz valoarea expresiei. Dac este logic adevrat (nenul), se execut instruciune. Se evalueaz expresia din nou i dac este n continuare adevrat se reia execuia instruciunii. Se repet aceast succesiune de operaii att timp ct expresie rmne adevrat. n momentul n care expresie a devenit fals (zero), se ntrerupe execuia instruciunii while i se trece la instruciunea imediat urmtoare din program. int i; i = 5; while (i) {

// se testeaz valoarea lui i; iniial are // valoarea 5, deci se va executa blocul de // instruciuni; i este afiat i decrementat; printf(\ni=d, i ); // se repet afiarea i decrementarea lui i i--; // pn cnd acesta ia valoarea zero; // n acel moment se ntrerupe execuia } // instruciunii while i se trece la // urmtoarea linie din program. De obicei valoarea expresiei care constituie condiia de ciclare este modificat n interiorul secvenei care se repet. Dac valoarea acesteia nu este modificat, exist riscul de repetare fr sfrit a instruciunii, evoluia programului fiind blocat. Exist instruciuni care pot fora ieirea dintr-o instruciune repetitiv. Acestea vor fi prezentate n paragrafele urmtoare. n exemplul urmtor se implementeaz, folosind instruciunea while, urmtoarea

141

aplicaie: Se calculeaz media aritmetic a N valori citite de la tastatur. Valoarea N este, de asemenea citit de la tastatur. #include <stdio.h> void main() { int i, N;

// variabila i va fi folosit ca i contor pentru numrarea // valorilor citite; ea va controla evoluia secvenei repetitive float val; // variabila val se folosete pentru citirea valorilor de la tastatur float rez; // variabila rez este folosit pentru calculul mediei aritmetice printf("Introdu numrul de valori:"); scanf("%d", &N); i = 1; rez = 0; // se fac iniializri pentru variabilele utilizate n secvena // repetitiv

while (i <= N) // condiia de execuie a ciclului - compar valorile i i N { printf("Introdu o valoare:"); scanf("%f", &val); rez = rez + val; i++; // modificarea valorii variabilei de control a evoluiei ciclului } rez = rez/N; printf("\nMedia aritmetica a valorilor este: %10.2f\n", rez); }

Observaii Dac n momentul de nceput al instruciunii while condiia nu este ndeplinit se trece direct la instruciunea imediat urmtoare acesteia. n exemplul anterior, dac N primete valoare <1, instruciunea while nu va fi executat. Se trece la instruciunea rez = rez/N. Dac N=0, se ajunge la o situaie care produce eroare fatal, i anume mprirea la zero. Pentru un ciclu care se repet pn la apsarea tastei N, se poate scrie: char ch ; ... while( ch != N) { ... ch=getch(); } 142

sau: char ch ; ... while( ch=getch() != N) { ... } Instruciunea care se repet poate fi instruciunea vid, ca n exemplul urmtor: char ch ; ... while( ch=getch() != X) ; ... Efectul acestei instruciuni este c, pentru ca programul s poat continua, trebuie apsat tasta X.

U8.1.2. Instruciunea de ciclare cu test final (do-while) Sintaxa general a instruciunii este: do instructiune; while (expresie); Instruciunea instructiune se execut att timp ct expresie este nenul. Evaluarea expresiei expresie se face dup executarea instruciunii instructiune. ......... i=5; do { printf(\ni=%d, i ); i--; } // expresia condiional se evalueaz dup while (i); // ce blocul de instruciuni a fost executat o // dat; reluarea execuiei lui se face numai // dac i 0 Se reia aplicaia care calculeaz media aritmetic a N valori citite de la tastatur folosind pentru implementare instruciunea do-while.

143

#include <stdio.h> void main() { int i, N;

// variabila i va fi folosit ca i contor pentru numrarea valorilor citite; // ea va controla evoluia secvenei repetitive float val; // variabila val se folosete pentru citirea valorilor de la tastatur float rez; // variabila rez este folosit pentru calculul mediei aritmetice printf("Introdu numarul de valori:"); scanf("%d", &N); i = 1; rez = 0; do { printf("Introdu o valoare:"); scanf("%f",&val); rez = rez + val; i++; // modificarea valorii variabilei de control a evoluiei ciclului } while (i<=N); // condiia de execuie a ciclului - compar valorile i i N // se fac iniializri pentru variabilele utilizate n secvena // repetitiv

rez = rez/N; printf("\nMedia aritmetica a valorilor este: %10.2f\n", rez); }

Observaii Blocul de instruciuni se execut cel puin odat, indiferent de valorile variabilelor i i N Dac N primete valoare <1, instruciunea do-while va fi ntrerupt, ca i n cazul folosirii instruciunii while. Se trece la instruciunea rez = rez/N. Dac N=0, se ajunge la o situaie care produce eroare fatal, i anume mprirea la zero. n cazul celor dou versiuni care folosesc instruciunea while, respectiv dowhile, diferenele de cod nu sunt majore, problemele care pot aprea sunt similare. n funcie de aplicaie ns, pot aprea situaii n care una dintre instruciuni se preteaz a fi implementat mai eficient. do { printf("Introdu numarul de valori:"); scanf("%d", &N); } while (N<1); 144

Observaii Introducerea secvenei de verificare a valorii variabilei N poate evita situaia ce genereaz eroare prin mprirea la zero. n situaia de fa este de preferat s se foloseasc instruciunea do-while, avnd n vedere faptul c nti trebuie introdus valoare pentru N i apoi se face verificarea valorii ei.

U8.1.3. Instruciunea de ciclare cu contor (for) Sintaxa general a instruciunii for este: for( expr1; expr2; expr3) instruciune; Instruciunea for se execut n urmtorii pai: expr1 se evalueaz o singur dat, la intrarea n bucla for; expr2 se evalueaz naintea fiecrei iteraii i reprezint condiia de execuie a instruciunii; valoarea logic fals a ei provoac ieirea din ciclu; expr3 se evalueaz la sfritul fiecrei iteraii, pentru actualizarea parametrilor ciclului. Instruciunea for ofer posibilitatea scrierii unui cod mai compact i mai clar.

Observaii Instruciunea for este o instruciune de ciclare cu test iniial, fiind echivalent cu: expr1; while(expr2) { instructiune; expr3; }

Exemplu de folosire a instruciunii for: for( i = 5 ; i ; i-- ) printf(\ni=%d, i ); Aplicaia care calculeaz media aritmetic a N valori citite de la tastatur poate fi 145 // instruciunea nglobeaz iniializarea lui i, modificarea // valorii lui i, testarea valorii lui i

implementat cu folosirea instruciunii for, dup cum urmeaz: #include <stdio.h> void main() { int i, N;

// variabila i va fi folosit ca i contor pentru numrarea valorilor citite; ea // va controla evoluia secvenei repetitive float val; // variabila val se folosete pentru citirea valorilor de la tastatur float rez; // variabila rez este folosit pentru calculul mediei aritmetice printf("Introdu numarul de valori:"); scanf("%d", &N); for (i=1, rez=0; i<=N ; i++) { printf("Introdu o valoare:"); scanf("%f", &val); rez = rez + val; } rez = rez/N; printf("\nMedia aritmetica a valorilor este: %10.2f\n", rez); // se fac iniializri pentru variabilele i i rez, se // verific condiia de execuie a ciclului, se // modific valoarea variabilei de control i

} Se observ c prin folosirea instruciunii for codul devine mai compact.

Observaii Expresia de iniializare folosit iniializeaz ambele variabile, i i rez. Din sintaxa instruciunii for poate lipsi oricare dintre expresii, dar semnul de punctuaie punct i virgul (;) trebuie s fie folosit. De exemplu, se poate folosi o scriere similar cu folosirea instruciunii while: i = 1; rez = 0 for( ; i<=N ; ) { printf("Introdu o valoare:"); scanf("%f", &val); rez = rez + val; i++; } Calcul lui N factorialul ( N! ) se poate face astfel: int N, i, fact; ... for ( i=N, fact=1 ; i>0 ; i--) fact *= i; 146

sau: int N, i, fact; // ... for ( i=N, fact=1 ; i>0 ; fact *= i, i-- ) ;

Observaii Se observ c a doua variant ne ofer o scriere compact, expresia de calcul a variabilei fact fiind inclus n expr3. Instruciunea care trebuie executat repetitiv a devenit expresia vid. n sintaxa instruciunii for poate lipsi expr2, cea care descrie condiia de ieire din ciclu. Aceasta poate duce la o ciclare fr sfrit. Ca i cazul instruciunilor while, do-while se poate fora ieirea din ciclu cu instruciuni de salt. for ( ; ; ) // nu este precizat expresia care condiioneaz execuia instruciunii { printf(\nSe executa un ciclu infinit !); }

U8.2. Instruciuni de salt U8.2.1. Instruciunea break Instruciunea are forma: break; Instruciunea break se folosete: n interiorul instruciunii switch pentru a ntrerupe execuia acesteia dup executarea unei secvene asociat cu un selector case (vezi paragraful 7.4.2). n instruciunile de ciclare (while, do-while, for) determinnd ieirea forat din acestea. n continuare este prezentat un exemplu de folosire a instruciunii break: #define N 100 int i; for( i=1 ; i<=N ; i++) { if (!(i%7))

147

{ printf("\ni=%d - divizibil cu 7",i); getch(); break; // datorita lui folosirii instruciunii break ciclul for se va ntrerupe // cnd i devine divizibil cu 7 i nu cnd i ajunge la valoarea 100; // ca urmare, o sa se afieze doar primele 7 valori // si se iese din for; } printf("\ni=%d",i); } Instruciunea break nu poate fi inclus ntr-o structur secvenial sau structur alternativ realizat cu instruciunea if. int a, b; printf("\na="); scanf("%d", &a); printf("\nb="); scanf("%d", &b); if(a>b) { printf(\n a>b); break; } // .... n mod frecvent, instruciunea break se folosete n instruciuni repetitive fr condiie de finalizare a acestora. De exemplu: char ch; //... for ( ; ; ) // nu este precizat expresia care condiioneaz ieirea din ciclul for { // ... if ((ch=getch()) == X) // la tastarea caracterului X se foreaz ieirea din ciclul break; // for, prin instruciunea break } Dac o secven conine mai multe instruciuni repetitive imbricate i una dintre ele conine instruciunea break, se va ntrerupe doar ciclul care conine break. char ch; int a, b; //... while (a<b) { //... 148

// eroare, break nu este inclus nici n instruciunea switch, // nici n instruciune repetitiv

for ( ; ; ) // nu este precizat expresia care condiioneaz ieirea din ciclul for { // ... if ((ch=getch()) == X) // la tastarea caracterului X se foreaz ieirea din ciclul break; // for, prin instruciunea break, dar se continu while. } // la urmtoarea iteraie a ciclului while se va lansa din //... // nou instruciunea for care va putea fi ntrerupt prin // tastarea caracterului X }

U8.2.2. Instruciunea continue Instruciunea are forma: continue; Se folosete numai n instruciunile repetitive i are ca efect trecerea la urmtoarea iteraie ntr-un ciclu while, do-while sau for. Nu are ca efect ntreruperea instruciunii repetitive, ci vor fi ignorate instruciunile ce i urmeaz n interiorul ciclului. Acesta se va continua cu urmtoarea iteraie. Exemplu de folosire a instruciunii continue: int i; for( i=1 ; i<=100 ; i++) { if (!(i%7)) { printf("\ni=%d - divizibil cu 7", i); getch(); continue; // datorita lui continue, se va ignora linia urmtoare si se trece la // urmtoarea iteraie a lui for, ca urmare, se vor afia toate // valorile, de la 1 la 100, pentru cele divizibile cu 7 afiarea fiind // diferit fa de celelalte valori } printf("\ni=%d",i); } n urma execuiei acestei secvene se va afia: i=1 i=2 i=3 i=4 i=5 i=6 i = 7 divizibil cu 7 i =8 ....

149

Ca i n cazul instruciunii break, nici instruciunea continue nu poate fi folosit n structuri secveniale sau alternative. Dac o secven conine mai multe instruciuni repetitive imbricate i una dintre ele conine instruciunea continue, efectul va fi doar pentru ciclul care conine continue.

U8.2.3. Instruciunea return Formele admise pentru instruciunea return sunt: return; sau return (expresie); sau return expresie; Efectul instruciunii este de revenire dintr-o funcie, adic de a trece controlul la funcia care a apelat funcia ce conine instruciunea return, fr transmiterea unei valori n prima form i cu transmiterea valorii expresie n celelalte. Tipul de dat al valorii returnat trebuie s fie compatibil cu cel al funciei. int functie(void) { int a; ... return a; } // antetul funciei precizeaz tipul valorii ntoarse

// tipul expresiei returnate e identic cu cel al funciei

Dac tipul expresiei returnate e nu identic cu cel al funciei, se face o conversie a tipului expresiei returnate ctre tipul funciei, similar cu conversiile din operaiile de atribuire. Aceste conversii pot produce trunchieri ale valorii, rezultatul fiind necontrolat. int functie(void) { float a; ... return a; } // antetul funciei precizeaz tipul valorii ntoarse, int

// tipul expresiei returnate e float, iar al funciei este int; se face // conversie cu trunchiere a valorii returnate ceea ce poate // produce rezultate necontrolate

n funciile care conin secvene alternative se poate folosi instruciunea return de mai multe ori, dar la execuie se va executa doar cea selectat.

150

int functie(void) { int a, b; ... if (a>b) return a; else return b; }

// antetul funciei precizeaz tipul valorii ntoarse

// se selecteaz una dintre valorile care va fi returnat

Dac o funcie este void, instruciunea return nu e nsoit de valoare, sau chiar poate s lipseasc. void functie(void) { ... return; } void functie(void) { int a, b; ... if (a>b) return; . } // antetul funciei lipsa valorii ntoarse, este funcie void // funcia nu returneaz valoare

// antetul funciei indic lipsa valorii ntoarse, este funcie void

// se verific o condiie care poate ntrerupe execuia funciei

Toate instruciunile care se afl ntr-o funcie dup instruciunea return vor fi ignorate.

U8.2.4. Funcia exit() Dei nu este o instruciune de control al programului, ci este o funcie definit n fiierele header standard stdlib.h i process.h. Ea poate fi folosit pentru a ncheia execuia programului din orice punct al su. Spre deosebire de instruciunile break sau return care ntrerup doar execuia unui modul din program, funcia exit() ntrerupe execuia ntregului program i revenirea n sistemul de operare. Prototipul funciei este: void exit (int status); Valoarea parametrului, status, reprezint un cod ce poate fi interpretat de sistemul de operare. Valoarea 0 este interpretat ca terminare normal a programului, valorile diferite de zero pot indica diferite coduri de eroare n execuia programului. 151

La ieirea din program cu funcia exit(), sunt nchise toate fiierele care fuseser deschise prin programul respectiv i sunt golite buffer-ele de ieire. Este prezentat un exemplu de folosire a funciei exit() ntr-un program ce definete un meniu care permite selecia ntre patru opiuni, cea de a patra producnd ncheierea execuiei programului: #include <conio.h> #include <stdio.h> #include <stdlib.h> void op1() { printf("\noptiune 1"); getch(); return; } void op2() { printf("\noptiune 2"); getch(); return; } void op3() { printf("\noptiune 3"); getch(); return; } void af_meniu() { printf("\n1. Optiunea 1"); printf("\n2. Optiunea 2"); printf("\n3. Optiunea 3"); printf("\n4. Iesire"); printf("\n\n\nIntrodu optiunea:"); return; } void main() { int optiune; do { af_meniu(); fflush(stdin); optiune=getchar();

// instruciunea return ncheie execuia funcia //creia aparine i se revine n funcia apelant, // n cazul de fa se va reveni la funcia main()

152

switch(optiune) { case '1': op1(); break; // instruciunea break ntrerupe doar execuia case '2': op2(); break; // instruciunii switch case '3': op3(); break; case '4': exit(0); // funcia exit() ncheie execuia programului } } while(1); // condiia de execuie a instruciunii while este exprimat // printr-o constant, ceea ce duce la ciclare infinit; // finalizarea ei se va face prin funcia exit() }

U8.2.5. Instruciunea de salt necondiionat goto Instruciunea goto are ca efect saltul la eticheta specificat. Sintaxa sa este: goto nume_et; Eticheta nume_et este specificat folosind sintaxa: nume_et : Eticheta se poate afla, n succesiunea de instruciuni, att naintea instruciunii goto, ct i dup aceasta, dar ele trebuie s se regseasc n aceeai funcie. Nu este permis saltul dintr-o funcie n alta. O secven care calculeaz factorialul pentru o valoare N se poate scrie folosind instruciunea goto astfel: int i, N=4, fact; i=1; fact = 1; et: fact *= i; i++; if (i<=N) goto et; printf("%d", fact);

// iniializarea variabilelor de lucru // definirea unei etichete; marcheaz locul din program n care se // va face salt cu instruciunea goto

// se produce saltul la eticheta et; instruciunile dintre etichet i // aceast instruciunea goto; efectul este similar cu cel obinut // prin folosirea instruciunilor repetitive (for, while, do-while)

Observaii Instruciunea goto ncalc principiile programrii structurate i reduce claritatea programului, astfel nct este recomandat evitarea ei. Instruciunile de selecie i de ciclare pot nlocui aceast instruciune, oferind n plus fa de aceasta un bun control al programului. 153

Exemple

/**************************************************************************

Exemplu1 8.1. - S se ntocmeasc un program prin care se afieaz codul ASCII. Se vor face afiri n format %c i %d pentru a vedea corespondena caracter-valoare numerica. Observaii: Se vor face afiri n ordine cresctoare sau descresctoare, folosind for, while sau do-while.
**************************************************************************/

#include<stdio.h> #include<conio.h> void main () { int i; //se afiseaza codul ASCII folosind instructiunea for for( i=1 ; i<255 ; i++) { printf("%3d - %c ", i, i); if( !( i%8 )) // dupa afisarea a 8 valori se trece la rand nou printf("\n"); } getch(); //se afiseaza codul ASCII folosind instructiunea while i=1; while( i<255 ) { printf("%3d- %c ", i, i); if( !( i%8 )) printf("\n"); i++; } getch(); //se afiseaza codul ASCII folosind instructiunea do...while i=1; do { printf("%3d - %c ", i, i); if( !( i%8 )) printf("\n"); i++; } while( i<255 ); getch(); }

154

/**************************************************************************

Exemplu1 8.2. - S se ntocmeasc un program prin care se citesc de la tastatura doi ntregi >=2. S se afieze divizorii celor doi ntregi. S se calculeze i s se afieze c.m.m.d.c. i c.m.m.m.c. pentru cele dou valori.
**************************************************************************/

#include<stdio.h> #include <conio.h> void main(void) { int nr1, nr2, i, min, cmmdc, cmmmc; do { printf("nr1="); scanf("%d",&nr1); } while (nr1<=1); //se citesc valori >1 do { printf("nr2="); scanf("%d",&nr2); } while (nr2<=1); //se citesc valori >1 printf("\nDivizorii numarului %d sunt:\n", nr1); for(i=2 ; i<=nr1 ; i++) if (!(nr1 % i)) printf("%d ", i); printf("\nDivizorii numarului %d sunt:\n", nr2); for(i=2 ; i <= nr2 ; i++) if (!(nr2%i)) printf("%d ", i); min=nr1<nr2 ? nr1 : nr2; // se determina minimul dintre nr1 si nr2

// se determina c.m.m.d.c. for( i=2, cmmdc=1; i<=min ;i++) if(!(nr1%i)&&!(nr2%i)) cmmdc = i; // se determina c.m.m.m.c. cmmmc = nr1*nr2/cmmdc; printf("\ncmmdc = %d", cmmdc ); printf("\ncmmmc=%d\n",cmmmc ); getch(); } 155

Rezumat

Instruciunile repetitive permit executarea n mod repetat a unor secvene de program att timp ct o condiie (expresie) este logic adevrat. Se poate ntrerupe execuia unui bloc de instruciuni, a unei funcii sau chiar a programului n totalitatea sa folosi instruciuni de salt sau funcia exit(). Instruciunea de ciclare while este instruciune cu test iniial. Instruciunea de ciclare do - while este instruciune cu test final. Dac n momentul de nceput al instruciunii while condiia nu este ndeplinit se trece direct la instruciunea imediat urmtoare acesteia, n timp ce corpul instruciunii do - while se execut cel puin o dat. Instruciunea de ciclare for se mai numete instruciune cu contor, ea incluznd i reactualizarea variabilei de control. Ea este instruciune de ciclare cu test iniial. Din sintaxa instruciunii for poate lipsi oricare dintre expresii, dar semnul de punctuaie punct i virgul (;) trebuie s fie folosit. O instruciune de ciclare poate avea expresia condiional permanent adevrat, situaie n care se ajunge la o ciclare fr sfrit. Ieirea dintr-o astfel de instruciune se poate face folosind instruciunea break. Instruciunea continue se folosete numai n instruciunile repetitive i are ca efect trecerea la urmtoarea iteraie ntr-un ciclu while, do-while sau for, cu ignorarea anumitor instruciuni. Instruciunea return produce ncheierea unei funcii i revenirea la funcia apelant, cu sau fr transmiterea unei valori, n funcie de sintaxa folosit. n funciile care conin secvene alternative se poate folosi instruciunea return de mai multe ori, dar la execuie se va executa doar cea selectat. Funcia exit() poate fi folosit pentru a ncheia execuia programului din orice punct al su. Instruciunea goto are ca efect saltul la eticheta specificat. Eticheta se poate afla, n succesiunea de instruciuni, att naintea instruciunii goto, ct i dup aceasta, dar ele trebuie s se regseasc n aceeai funcie. Instruciunea goto ncalc principiile programrii structurate i reduce claritatea programului, de aceea recomandarea este s se evite folosirea acesteia.

156

Test de autoevaluare 1. Ce afiseaza secvena de program de mai jos : #include<stdio.h> void main() { int a=2; while(a) printf("%3d", a--); } a. 2 1 0 b. 2 1 c. 3 2 1 d. altceva 2. Se considera secvena de program de mai jos : #include<stdio.h> void main(){ int i=5,j=1; while(i-j) { i--; j++; printf("Mesaj\n"); } } De cate ori apare "Mesaj" pe ecran la rularea programului ? a. o singura data b. de 3 ori c. de doua ori d. niciodat 3. Ce afiseaza secvena de program de mai jos ? #include<stdio.h> void main() { int i=1, f=1; do { f = f*i ; i++; } while (i<=4); printf("%d\n", f); } a. 24 b. 12 c. nimic pentru ca programul se va bloca datorita buclei infinite d. 1. 4. Secvena de program : #include<stdio.h> void main(){ int i, j; for(i=1, j=7 ; j-i ; j--; i++; printf("Mesaj!\n");} va produce : a. afisarea mesajului pe ecran de 4 ori b. afisarea mesajului pe ecran o singura data c. afisarea mesajului pe ecran de 2 ori d. afisarea mesajului pe ecran de 3 ori e. eroare de sintaxa

157

5. Secvena de mai jos: #include<stdio.h> void main() { int i,n=4, factn; for(i=n, factn=1; i; i--) factn*=i; printf("%ul ",factn); } va afisa : a. 24 b. 120 c. 6 d. nici o valoare de mai sus 6. Secvena de mai jos: #include<stdio.h> void main() { int i; for(i=0;i<10;i++) { if (i%2) printf("mesaj\n"); else { printf("esec\n"); break; } } } va produce afisarea: a. de 5 ori a "mesaj" -ului b. de 5 ori "mesaj" si de 5 ori "esec" c. o data "esec" d. de 5 ori "esec" e. o data "mesaj" si o data "esec" 7. Secvena de mai jos: #include<stdio.h> #include<conio.h> do { for(i=0;i<10;i++) { if (i%2) printf("mesaj\n"); else printf("esec\n"); break; } } printf("testati alt ciclu?[y/n]\n"); } while ( getch()=='y'); va afisa: a. de 5 ori "mesaj" si asteapta y/n b. de 5 ori "mesaj" si de 5 ori "esec" si asteapta y/n c. o data "mesaj" si o data "esec" d. o data "esec" e. nici una din situaiile de mai sus

158

ntrebri. Exerciii. Probleme. 1. Se consider intervalul de valori [a , b]. Se citesc valori pentru a i b. S se afieze toate valorile divizibile cu 5 din intervalul dat. 2. Sa se scrie un program in care intr-o secvena repetitiva se citesc de la tastatura valori ntregi pozitive pentru o variabil de tip int, pentru fiecare valoare afindu-se factorialul. Secvena este finalizata la introducerea valorii 0 (zero). 3. S se scrie un program n care se declar o variabil de tip int. Se citete de la tastatur. S se determine i s se afieze inversul valorii acesteia. (De exemplu, inversul lui 12345 este 54321). Not: Se vor determina cifrele care alctuiesc numrul ca resturi obinute prin mpriri succesive la 10, inversul numrului obinndu-se prin adugarea acestor cifre nsoite de nmuliri succesive cu 10. 4. S se ntocmeasc un program n care : - se citete o valoare x cuprins n intervalul [1,170]; - se citete o valoare y cuprins n intervalul [1,x]; - se calculeaz i afieaz x! i y!; - se calculeaz i afieaz aranjamente de x elemente luate cte y A(x, y)=x*(x-1)*(x-2)** (x-y+1) - se calculeaz i afieaz combinri de x elemente luate cte y C(x, y) = A(x, y) / y! 5. S se scrie un program care afieaz toate valorile ntregi din intervalul [0, 20], valorile divizibile cu 2 i apoi cele divizibile cu 3 din acelai interval, ca n exemplul urmtor.

Nota: Se vor realiza variante de program folosindu-se pe rnd instruciunile while, do while, for.

159

Unitatea de nvare U.9. TABLOURI DE DATE

Cuprins Introducere .................................................................................................................. 160 Obiectivele unitii de nvare ................................................................................... 160 U9.1. Declararea tablourilor de date ........................................................................... 161 U9.2. Tablouri unidimensionale ................................................................................. 164 U9.3. iruri de caractere ............................................................................................. 167 U9.4. Tablouri multidimensionale .............................................................................. 170 Exemple ...................................................................................................................... 172 Rezumat ...................................................................................................................... 177 Test de autoevaluare ................................................................................................... 178 ntrebri, exerciii i probleme .................................................................................... 181

Introducere Cantitatea de informaie prelucrat de programe poate fi mare, de asemenea tipurile datelor prelucrate pot fi aceleai sau diferite. Este dificil ca aceste date s fie vehiculate doar prin intermediul unor variabile simple, deoarece ar fi necesar s se foloseasc un numr mare de declaraii, cu nume diferite. n astfel de situaii se pot folosi tablouri (masive) de date care permit ca, prin folosirea unui singur nume, s se stocheze i prelucreze un mare numr de date. Dimensiunea tablourilor este limitat doar de memoria disponibil. Prin folosirea tablourilor de date se construiesc i irurile de caractere pentru care n C/C++ nu exist tip de date predefinit.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Sintaxa de declarare a tablourilor de date; S foloseti tablouri unidimensionale cu operatorii specifici, referirea elementelor lor i folosirea acestora n expresii diverse; S foloseti iruri de caractere, att n prelucrri prin funcii specifice definite n biblioteca standard, ct i n prelucrri caracter cu caracter; S foloseti tablouri multidimensionale cu operatorii specifici, referirea elementelor lor i folosirea acestora n expresii diverse. 160

Durata medie de parcurgere a celei de a noua uniti de nvare este de 2 ore.

U9.1. Declararea tablourilor de date Tabloul de date (sau masiv de date) este o colecie de date de acelai tip, plasate ntr-o zon contigu de memorie (adresele elementelor tabloului sunt succesive). Tipul de date tablou este tip de date derivat. Este construit folosindu-se tipuri de date predefinite sau definite de programator. Tablourile de date se mai numesc variabile compuse (structurate), deoarece grupeaz mai multe elemente. Sintaxa declaraiei unui tablou cu N dimensiuni este: tip_element nume_tablou [dim_1][dim_2][dim_N]; unde: - tip_element poate fi orice tip de date, fundamental sau definit de utilizator; - nume_tablou orice identificator care nu a primit alt semnificaie n domeniul declaraiei; dim_1, dim_2,...,dim_N sunt constante numerice ntregi.

Zona de memorie rezervat conine dim_1 x dim_2 x ... x dim_N elemente de tipul tip_element, adic: dim_1 x dim_2 x ... x dim_N x sizeof(tip_element) octei. Variabilele tablou au nume, iar tipul tabloului este dat de tipul elementelor sale. Elementele tabloului pot fi referite prin numele tabloului i indeci (valori numerice ntregi) care reprezint poziia elementului n cadrul tabloului. Exemple de declarare de tablouri de date: float vect1[5]; int dimensiuni[4][12]; // se declar un tablou cu 5 elemente de tip float, zona de // memorie alocat fiind de 5*sizeof(float) bytes // se declar un tablou cu 4*12 elemente de tip int, zona // de memorie alocat fiind de 4*12*sizeof(int) bytes

Referirea unui element de tablou se face cu operatorul de indexare [ ] sub forma: nume_tablou [indice_1][indice_2]...[indice_N]; 161

unde: indice_1, indice_2,...,indice_N poate fi orice expresie care returneaz o valoare ntreag. Declaraia unui tablou se poate face cu iniializarea sa, folosind sintaxa: tip_element nume_tablou [indice_1][indice_2]...[indice_N] ={list_valori}; Lista de valori trebuie s conin constante de tip compatibil cu tipul de baz al tabloului, n ordinea plasrii n memorie. Exemple de declarare a tablourilor cu iniializare: float vect1[5]; int vect2[10]={2,7,-1,0,9,15,-5,22,6,11}; int mat[2][3]={{3,5,-3},{2,-1,0}}; // se declar un tablou cu 5 elemente // float, fr iniializare // se declar un tablou cu 10 elemente int // cu iniializare // se declar un tablou bidimensional cu // 2*3 elemente de tip ntreg, cu // iniializare

Dac numrul valorilor din lista de iniializare este mai mic dect dimensiunea tabloului, adic dect numrul de elemente ale tabloului, vor fi iniializate doar primele elemente n ordinea de alocare, celelalte rmnnd neiniializate. float vect[5] = { 1.5, 3.2, 7.1}; // se iniializeaz primele trei valori, dou // rmnnd neiniializate

Situaia n care numrul valorilor din lista de iniializare este mai mare dect dimensiunea tabloului genereaz un mesaj de eroare. float vect[5] = { 1.5, 3.2, 7.1, -2.5, 6, 10 }; // eroare, numrul valorilor de iniializare // este mai mare dect numrul de // elemente ale tabloului

Este permis declararea tablourilor fr precizarea dimensiunii, dac declaraia este cu iniializare. n aceast situaie, dimensiunea este stabilit n mod implicit egal cu numrul de valori din list. float vect[ ]={ 1.5, 3.2, 7.1, -2.5, 6 }; // numrul valorilor de iniializare este 5, deci // dimensiunea implicit a tabloului va fi 5

Indiferent c tabloul a fost declarat cu iniializare sau nu, valorile elementelor de tablou vor putea fi modificate pe parcursul execuiei programului, ca n cazul oricrei variabile.

162

float vect[5]; vect[0] = 1.5; vect[1] = -2.5; vect[5] = 3.2;

int mat[2][3]={{3,5,-3},{2,-1,0}}; mat[1][2]= 23;

// se declar un tablou cu 5 elemente float, fr // iniializare // elementului de index 0 i se atribuie valoarea 1.5 // elementului de index 1 i se atribuie valoarea -2.5 // dei nu este semnalat eroare, se folosete index // incorect indexul, valorile corecte fiind 0...4; aceast // situaie poate genera efecte necontrolate n evoluia // programului // se declar un tablou bidimensional cu // 2*3 elemente de tip ntreg, cu iniializare // elementului de indeci 1, respectiv 2, i // se atribuie valoarea 23

Observaii Numele tabloului (nensoit de indeci) reprezint adresa de memorie la care este alocat tabloul. Indecii elementelor tabloului iau valori ncepnd cu 0 (zero), deci valoarea maxim a lor este dim_n -1. Dup alocarea memoriei necesare, nici la compilare nici la execuie, nu se mai fac verificri de dimensiune, deci nu se verific dac indecii utilizai au valori corecte. Dac indecii depesc dimensiunea tabloului, exist riscul s se nscrie valori n zone de memorie utilizate n alt scop, distrugnd date sau cod de program. Elementele neiniializate ale tablourilor iau valori, asemeni oricrei variabile, dup cum urmeaz: valoare zero dac tabloul este declarat global; valoare rezidual, dac declararea tabloului este local unui bloc de instruciuni. La declararea unui tablou, dimensiunile se specific prin constante numerice ntregi literale sau cu nume, cum ar fi: #define dim1 15 const int dim2 = 99; int vector1[20]; float vector2[dim1]; double vector3[dim2]; Declaraia urmtoare: int dim = 30; unsigned int vector4[dim]; este semnalat cu mesaj de eroare, deoarece se utilizeaz o variabil pentru specificarea dimensiunii tabloului.

163

Folosirea tablourilor uureaz scrierea programelor care prelucreaz mai multe variabile de acelai tip, prelucrate n secvene similare, referirea lor fcndu-se cu ajutorul unui nume comun. Aceasta aduce uurin n scrierea programului, uurin n citirea i depanarea acestuia. n caz contrar, ar fi necesar declararea unui numr mare de variabile, cu nume distincte, scrierea programului fiind greoaie. n funcie de numrul dimensiunilor precizate la declararea tablourilor, tablourile pot fi grupate n tablouri unidimensionale (se mai denumesc vectori) i tablouri multidimensionale, dintre care tablourile bidimensionale (matrice) sunt cel mai frecvent folosite. Am vzut c, limbajele C/C++ nu au definit ca tip de date tipul ir de caractere. n aceste limbaje, irurile de caractere sunt construite cu ajutorul tablourilor unidimensionale cu elemente de tip char.

U9.2. Tablouri unidimensionale Declaraia unui tablou unidimensional se face, conform sintaxei precizat n paragrafului anterior astfel: tip_element nume_tablou [dim]; sau cu iniializarea elementelor: tip nume_tablou [dim] = { list_valori }; Pentru tabloul de date cu numele nume_tablou se aloc dim elemente de tipul tip_element plasate succesiv ntr-o zon contigu de memorie. Pentru referirea unui element se folosete sintaxa urmtoare: nume_tablou[index] unde index precizeaz poziia elementului n tablou. Acesta este reprezentat prin orice expresie ntreag pozitiv. Exemplu de declarare a unui tablou cu 6 elemente de tip int cu iniializare: int vector[6] = { 3, 5, -7, 15, 99, 43};

164

Fig. 9.1. Exemplu de alocare n memorie a unui tablou unidimensional

Alocarea tabloului n memorie se face ca n Fig. 9.1. Numele tabloului, vector, nensoit de index, reprezint adresa la care s-a fcut alocarea de memorie. Elementele tabloului sunt alocate la adrese de memorie succesive. Se poate determina spaiul de memorie alocat pentru tablou cu operatorul sizeof. printf(\nTabloul vector ocupa %d octeti in memorie, sizeof(vector)); Adresa de alocare este determinat prin numele tabloului. Se poate folosi i operatorul &, dar expresiile vector i respectiv &vector sunt echivalente. Pentru afiarea valorii se poate folosi formatul specific adreselor, %p, formatul fiind hexazecimal, sau cu formatul %u, ca ntreg zecimal fr semn. printf(\nTabloul vector este alocat la adresa de memorie %p, vector); printf(\nTabloul vector este alocat la adresa de memorie %u, vector); Referirea elementelor tabloului se face prin numele tabloului, operatorul [ ] i valoarea indexului. Acesta indic poziia elementului n tablou. Un element al tabloului se poate folosi ca orice variabil simpl de acelai tip. Lund n considerare declararea tabloului vector, se pot folosii expresii care includ elemente ale tabloului ca n exemplul urmtor: int a; int vector[6] = { 3, 5, -7, 15, 99, 43}; vector[0] = 10; a = (vector[1] +vector[2]) / 2; printf(\nValoarea adresei &vector[0] = %u, &vector[0]);

// se afieaz adresa la //care e alocat elementul // de index 0 printf(\nElementul vector[0] ocupa %d octeti, sizeof(vector[0])); // se afieaz nr. de // octei folosii pentru

165

printf(\nValoarea elementului vector[0] = %d, vector[0]);

// reprezentarea // elementului // se afieaz valoarea // elementului

Observaii Numerotarea indecilor n C/C++ ncepe totdeauna cu valoarea 0 (zero) ! Compilatorul nu verific corectitudinea indecilor folosii ! n mod frecvent, dac se dorete prelucrarea mai multor elemente, sau chiar a tuturor elementelor tabloului, se folosesc instruciunile repetitive (for, while, do-while). int i; for ( i=0 ; i<5 ; i++) printf(\nValoarea elementului vector[%d] = %d, i, vector[i]); n secvena anterioar, variabila i este folosit pentru desemnarea indexului elementelor. Prin valorile succesive de la 0 la 4 ale indicelui, se afieaz pe rnd valorile elementelor vector[0]... vector[4].

Observaii Operatorii specifici limbajului pot fi aplicai elementelor tabloului n msura n care tipul elementelor permite acest lucru. Nu se pot face operaii cu tablouri n ansamblul lor, ci doar cu elemente ale acestora. int tab1[5]; float tab[10]; // tab1 = tab2 ; // eroare, nu se poate face atribuirea; tab1 i tab2 sunt adresele // la care sunt alocate tablourile i ele nu pot fi modificate tab1 = 100 ; tab1+tab2 ; // eroare, ca si in cazul precedent, nu se poate face atribuirea, // adic nu se poate modifica adresa la care este alocat tabloul // eroare, operatorul + nu este definit pentru a opera cu tablouri // corect, tab1[0] i tab2[0] sunt date de tip int, respectiv // float, deci operaia de adunare se poate efectua

tab1[0]+tab2[0];

166

U9.3. iruri de caractere Tablourile unidimensionale cu elemente de tip char sunt folosite pentru memorarea irurilor de caractere. Pentru a marca sfritul unui ir de caractere, dup ultimul caracter se adaug un octet cu valoarea 0 (\0), numit i terminator de ir. Declararea unui ir de caractere se face, conform sintaxei specifice tablourilor unidimensionale, prin tipul elementelor (char), numele tabloului i dimensiune. char nume[6]; Declaraia poate fi fcut cu iniializare ca n exemplul urmtor: char nume[6] = { S, M, I, T, H, \0}; Tabloul este alocat n memorie ca n Fig. 9.2.

Fig.9.2. Exemplu de alocare n memorie a unui ir de caractere

Iniializarea se poate face i folosind iruri de caractere constante. char nume[6] =Smith; O list de caractere ncadrat ntre ghilimele reprezint o constant ir de caractere (de exemplu SMITH). Pentru o astfel de constant, compilatorul rezerv numrul de octei pe care i iniializeaz cu codurile ASCII corespunztoare caracterelor i un octet pe care l iniializeaz cu valoarea 0 ( adic terminatorul de ir \0). O constant ir de caractere poate fi utilizat i pentru iniializarea unei variabile ir de caractere. Exemple de declare de tablouri: char sir1[10]; char sir3[ ]=sir de caractere; sir3[0]=S; // se declar un tablou unidimensional, cu // elemente char (ir de caractere), fr iniializare // se declar un tablou cu 17 elemente char (ir de // caractere) cu iniializare (ultimul caracter depus // n tablou este terminatorul de ir \0 // primul caracter al irului primete valoarea S 167

Observaii n cazul unui ir vid, primul element al tabloului este chiar terminatorul de ir, de exemplu: nume[0]=\0; Dimensiunea precizat la declararea unui tablou ir de caractere trebuie s fie mai mare cu o unitate dect numrul caracterelor semnificative care pot intra n alctuirea coninutului irului pentru a permite memorarea terminatorului. Terminatorul de ir permite testarea facil a sfritului irului. Funciile definite pentru a opera cu iruri de caractere nu fac referire la dimensiunea acestora, ci folosesc terminatorul de ir pentru a indica sfritul irurilor. irurile de caractere pot fi tratate, ca orice tablou unidimensional, fcnd prelucrri element cu element, deci caracter cu caracter. n plus, exist definite n fiierele header standard o mulime de funcii definite pentru prelucrarea irurilor de caractere. De exemplu, se definete o secven n care se citete de la tastatur coninutul unui ir de caractere. Citirea se face caracter cu caracter pn la apsarea tastei Enter. char sir [20]; int i=0; do { fflush(stdin); sir[i]=getche(); i++; } while (sir[i-1]!=13); // ncheierea ciclului do-while se face la apsarea tastei // Enter care transmite dou caractere cu valoarea n // codul ASCII 13 (trecere la rnd nou \n) i respectiv // 10 (carriage return \r); prima valoare este preluat de // un element de tablou // dup finalizarea introducerii de caractere, se // memoreaz terminatorul de ir

// variabila i se folosete pentru desemnarea indexului // elementului de tablou; primul element are indexul 0 // secvena repetitiva prin care se citesc succesiv // caracterele

sir[i-1]='\0';

Secvena anterioar poate fi nlocuit cu apelul funciilor specifice gets() sau scanf(): char sir [20]; gets(sir); sau char sir [20]; scanf(%s, sir);

168

Pentru operaii de intrare/ieire de la consol se pot folosi funciile scanf, respectiv printf, cu specificatorul de format %s sau funciile gets(), respectiv puts() definite tot n fiierul header stdio.h. Exemple de folosire a funciilor de intrare/ieire cu iruri de caractere : char nume[30]; scanf(%s, nume); printf(Numele este: %s, nume); printf(Adresa sirului este: %p, nume);

// numele unui tablou este o adres, astfel // c n funcia scanf nu a fost necesar s // se utilizeze operatorul & // funcia printf, pentru specificatorul %s // nu afiseaza adresa la care se afl alocat // irul, ci afieaz coninutul acestuia // funcia printf, pentru specificatorul %p // afiseaza adresa la care se afl alocat // irul, // n specificatorul de format s-a precizat // numrul maxim de caractere care pot // fi introduse pentru sir1; cel de al // 10-lea octet e rezervat pentru // terminatorul de ir

char sir1[10]; scanf(%9s, sir1);

printf(Sirul citit de la tastatura este: %s, sir1); gets(nume); puts(nume); Deoarece irurile de caractere sunt construite ca tablouri unidimensionale, operatorii definii n mod standard nu pot opera cu acestea, ci se recurge la utilizarea de funcii definite n fiierele disponibile existente n biblioteca de funcii. Un fiier cu funcii destinate lucrului cu iruri de caractere este fiierul string.h. Cteva funcii uzuale definite n fiierul string.h sunt: strcpy(sir_destinatie, sir_sursa); strcat(sir_destinatie, sir_sursa); strlen(sir); strcmp(sir1, sir2); - copiaz coninutul irului surs n irul destinaie - adaug coninutul irului surs la irul destinaie (concateneaz cele dou iruri) - returneaz numrul de elemente ale irului (lungimea irului) - compar dou iruri, returnnd valoarea 0 dac irurile sunt egale, i valoare diferit de 0 dac sunt diferite (valoarea e dat de diferena dintre primele caractere diferite)

169

strupr(sir); strlwr(sir);

- transform literele mici ale irului n majuscule - transform majusculele n litere mici

Exemple de folosire a funciilor destinate sirurilor de caractere: //declararea sirurilor de caractere char sir1[10], sir2[10], sir3[20]; int i, l1, l2; //citirea de la tastatura a sirurilor scanf("%9s",sir1); scanf("%9s",sir2); //se determina lungimea sir1 l1=strlen(sir1); //copierea in sir3 a coninutului sir1 strcpy(sir3, sir1); //se transform irul n ir cu majuscule strupr(sir1)

U9.4. Tablouri multidimensionale Tablourile multidimensionale se declar, aa cum am vzut n paragraful 9.1, cu sintaxa: tip_element nume_tablou [dim_1][dim_2][dim_N]; Zona de memorie rezervat pentru tablou conine dim_1 x dim_2 x ... x dim_N elemente de tipul tip_element, adic: dim_1 x dim_2 x ... x dim_N x sizeof(tip_element) octei. Un tablou multidimensional este interpretat ca fiind un tablou unidimensional, fiecare element fiind la rndul su un tablou. n mod frecvent se folosesc tablouri cu dou dimensiuni, numite n mod uzual matrice. Matricele sunt interpretate ca tablouri unidimensionale care au elemente formate la rndul lor din tablouri unidimensionale. Se interpreteaz c fiecare linie a matricei reprezint un element al tabloului, la rndul lor liniile fiind formate din tablouri unidimensionale, cu dimensiunea dat de numrul de coloane. 170

Declaraia matricelor se poate face cu sau fr iniializare. Exemplu de declarare a unui tablou bidimensional, cu iniializare: int matrix[3][4] = { { 10, 20, 30, 40}, { 50, 60, 70, 80}, { 90, 100, 110, 120}};

Declaraia este fcut cu iniializarea elementelor. Alocarea de memorie se face ca n Fig. 9.3.

Fig.9.3. Exemplu de reprezentare a unei matrice

Matricea matrix este un tablou unidimensional cu 3 elemente, fiecare element fiind un tablou format din 4 ntregi. Numele matricei, matrix, reprezint adresa la care este alocat matricea, adres care coincide cu adresa primei linii a matricei, matrix[0], i cu adresa primului element de pe prima linie, &matrix[0][0]. Numele matricei nsoit de un index reprezint o adres de memorie (matrix[0], matrix[1], matrix[2]), i anume adresa la care este alocat linia corespunztoare. O linie a matricei este format dintr-un tablou unidimensional de 4 ntregi. Numele matricei nsoit de doi indeci reprezint un element al matricei i este un int (matrix[0][0], matrix[0][1], etc.). Un element al matricei poate fi utilizat asemeni oricrei variabile de tip int, adic poate fi utilizat n orice expresie valid pentru acest tip de date. Indecii pot fi specificai prin orice expresie care returneaz o valoare ntreag. Dac se dorete prelucrarea tuturor elementelor unei matrice, n mod uzual se folosesc instruciuni repetitive imbricate (de regul cicluri for). Se obine un cod compact i uor de citit i depanat. Se exemplific folosirea elementelor unei matrice; pentru a referi elementele matricei, se folosesc doi indeci desemnai de dou variabile:

171

int mat[3][4]; // declararea matricei int i, j; // se citesc de la tastatura elementele lui mat // variabila i se utilizeaz pentru desemnarea liniei matricei // variabila j se utilizeaz pentru desemnarea coloanei matricei for(i=0 ; i<3 ; i++) for(j=0 ; j<4 ; j++) { printf("mat1[%d][%d]=", i, j); scanf("%d",&mat1[i][j]); } //se afiseaza elementele matricei mat for(i=0 ; i<3 ; i++) { printf("\n"); for(j=0 ; j<4 ; j++) printf("%6d", mat [i][j]); }

Exemple

/**************************************************************************

Exemplu1 9.1. - S se ntocmeasc un program prin care se exemplific utilizarea tablourilor unidimensionale
**************************************************************************/

#include <stdio.h> #include <conio.h> void main() { //declaraie tablou de dimensiune 5, fr iniializare int tab1[5]; //declaraie tablou de dimensiune 7 cu iniializarea elementelor int tab2[7] = {9, 11, 25, 7, 44, 2,14}; int i; //se afieaz valorile elementelor tab1 valori reziduale printf("afisare elemente tab1-contine valori reziduale"); for(i=0 ; i<5 ; i++) printf("\ntab1[%d]=%d", i, tab1[i]); //se afieaz valorile elementelor tab2 valorile folosite la initializare printf("\n\nafisare elemente tab2-contine valorile de initializare"); 172

for(i=0 ; i<7 ; i++) printf("\ntab2[%d] = %d", i, tab2[i]); // se citesc de la tastatura valorile elementelor tab1 printf("\n\ncitire de valori de la tastatura pentru tab1"); for(i=0 ; i<5 ; i++) { printf("\ntab1[%d]=", i); scanf("%d", &tab1[i]); } //se afieaz valorile elementelor tab1 valorile sunt cele citite de la tastatura printf("\n\nafisare elemente tab1-contine valorile citite de la tastatura"); for(i=0 ; i<5 ; i++) printf("\ntab1[%d] = %d", i, tab1[i]); //se afieaz valorile elementelor tab2 divizibile cu 3 printf("\n\nafisarea elementelor tab2-divizibile cu 3"); for(i=0 ; i<7 ; i++) if (!(tab2[i]%3)) printf("\ntab2[%d] = %d", i, tab2[i]); }

/**************************************************************************

Exemplu1 9.2. - S se ntocmeasc un program prin care se exemplific utilizarea irurilor de caractere (tablouri unidimensionale cu elemente char). Se exemplific att prelucrarea element cu element, ct i utilizarea funciilor specifice.
**************************************************************************/

#include<stdio.h> #include<conio.h> #include<string.h> void main() { //declararea sirurilor de caractere char sir1[10], sir2[10], sir3[20]; int i, l1, l2; //citirea de la tastatura a sirurilor fflush(stdin); printf("\nNumele:"); scanf("%9s",sir1); fflush(stdin); printf("\nPrenumele:"); scanf("%9s",sir2);

173

/************************************************************** Exemple de copiere a sirurilor caracter cu caracter **************************************************************/ //se determina lungimea sir1 for( l1=0 ; sir1[l1]!=0 ; l1++); printf("\nsir1 este format din %d caractere", l1); //se determina lungimea sir2 for( l2=0; sir1[l2]!=0; l2++); printf("\nsir2 este format din %d caractere", l2); //preluarea in sir3 a coninutului sir1 for(i=0;i<l1;i++) sir3[i]=sir1[i]; //se adaug caracterul spaiu in sir3 sir3[l1]=' '; //se adaug coninutul lui sir2 in sir3 for(i=0 ; i<l2+1 ; i++) sir3[l1+1+i]=sir2[i]; //se adaug terminatorul de sir sir3[l1+l2+1]='\0'; printf("\nNumele complet este: %s", sir3); getch(); /*********************************************************************** Exemple de folosire a funciilor destinate sirurilor de caractere ***********************************************************************/ //citirea de la tastatura a sirurilor fflush(stdin); printf("\nNumele:"); scanf("%9s",sir1); fflush(stdin); printf("\nPrenumele:"); scanf("%9s",sir2); //se determina lungimea sir1 l1=strlen(sir1); printf("\nsir1 este format din %d caractere", l1); //se determina lungimea sir2 l2=strlen(sir2); printf("\nsir2 este format din %d caractere", l2); //copierea in sir3 a coninutului sir1 strcpy(sir3, sir1); //se adaug caracterul spaiu in sir3 strcat(sir3, " ");

174

//se adaug coninutul lui sir2 in sir3 strcat(sir3, sir2); printf("\nNumele complet este: %s", sir3); getch(); }

/**************************************************************************

Exemplu1 9.3. - S se ntocmeasc un program prin care se exemplific utilizarea tablourilor bidimensionale (matrice)
**************************************************************************/

#include<stdio.h> #include <conio.h> void main() { // Declararea matricelor int mat1[2][3], mat2[3][4], i; printf("Informatii despre mat1:\n"); //se afiseaza nr. de octeti alocati lui mat1 printf("\nmat1 ocupa : %d octeti", sizeof(mat1)); //se afiseaza nr. de octeti alocati unei linii a lui mat1 printf("\no linie a lui mat1 ocupa : %d octeti", sizeof(mat1[0])); //se afiseaza nr. de octeti alocati unui element al lui mat1 printf("\nun element al lui mat1 ocupa : %d octeti", sizeof(mat1[0][0])); //se afiseaza adresele la care e alocata mat1 printf("\n&mat1=%u", mat1); //expresiile mat1 si &mat1 sunt // echivalente

//se afiseaza adresele la care se afla liniile lui mat1 for(i=0 ; i<2 ; i++) printf("\nlinia %d se afla la adresa : %u", i, mat1[i]); printf("\n\nInformatii despre mat2:\n"); //se afiseaza nr. de octeti alocati lui mat2 printf("\nmat2 ocupa : %d octeti",sizeof(mat2));

// mat1[i] si &mat1[i] sunt // echivalente

//se afiseaza nr. de octeti alocati unei linii a lui mat2 printf("\no linie a lui mat2 ocupa : %d octeti",sizeof(mat2[0])); //se afiseaza nr. de octeti alocati unui element al lui mat2 printf("\nun element al lui mat2 ocupa : %d octeti", sizeof(mat2[0][0]));

175

//se afiseaza adresele la care e alocata mat1 printf("\n&mat2=%u", mat2);

//mat2 si &mat2 sunt echivalente

//se afiseaza adresele la care se afla liniile lui mat2 for(i=0 ; i<3 ; i++) printf("\nlinia %d se afla la adresa : %u", i, mat2[i]); }

// mat2[i] si &mat2[i] // sunt echivalente

/**************************************************************************

Exemplu1 9.4. - S se ntocmeasc un program n care: Se declar 3 matrice de dimensiuni egale. Se citesc de la tastatur dou dintre matrice i se calculeaz cea de a treia ca sum a lor. S se calculeze, pentru o matrice, suma elementelor pe fiecare linie si a tuturor elementelor matricei.
**************************************************************************/

#include<stdio.h> #include <conio.h> void main() { int mat1[3][4], mat2[3][4], mat3[3][4]; int i, j; int suma_linie, suma_matrice;

// declararea matricelor

// se citesc de la tastatura elementele lui mat1 // variabila i se utilizeaza pentru desemnarea liniei matricei // variabila j se utilizeaza pentru desemnarea coloanei matricei printf("Introduceti elementele matricei mat1:\n"); for(i=0;i<3;i++) for(j=0;j<4;j++) { printf("mat1[%d][%d]=",i,j); scanf("%d",&mat1[i][j]); } //se citesc de la tastatura elementele lui mat2 printf("\nIntroduceti elementele matricei mat2:\n"); for(i=0;i<3;i++) for(j=0;j<4;j++) { printf("mat2[%d][%d]=", i, j); scanf("%d",&mat2[i][j]); }

176

//se calculeaza matricea mat3 ca suma dintre mat1 si mat2 for(i=0;i<3;i++) for(j=0;j<4;j++) mat3[i][j]=mat1[i][j] + mat2[i][j]; //se afiseaza matricea mat3 obinuta printf("\nmat3:"); for(i=0;i<3;i++) { printf("\n"); for(j=0;j<4;j++) printf("%6d", mat3[i][j]); } //se calculeaza pentru mat3 pe fiecare linie si suma tuturor elementelor suma_matrice=0; for(i=0;i<3;i++) { suma_linie=0; for(j=0;j<4;j++) { suma_linie+=mat3[i][j]; suma_matrice+=mat3[i][j]; } printf("\npentru linia %d suma elementelor este: %d", i, suma_linie); } printf("\nsuma tuturor elementelor matricei mat3 este: %d", suma_matrice); getch(); }

Rezumat Tabloul de date este o colecie de date de acelai tip, plasate ntr-o zon contigu de memorie Elementele tabloului pot fi referite prin numele tabloului i indeci (valori numerice ntregi) Indecii reprezint poziia elementului n cadrul tabloului. La declararea unui tablou, dimensiunile se specific prin constante numerice ntregi literale sau cu nume. Referirea unui element de tablou se face folosind operatorul de indexare [ ].

177

Declaraia unui tablou se poate face cu iniializarea elementelor sale. Este permis declararea tablourilor fr precizarea dimensiunii, dac declaraia este cu iniializare. Valorile elementelor de tablou vor putea fi modificate pe parcursul execuiei programului. Dup alocarea memoriei necesare, nici la compilare nici la execuie, nu se mai fac verificri de dimensiune, deci nu se verific dac indecii utilizai au valori corecte. n funcie de numrul dimensiunilor precizate la declararea tablourilor, tablourile pot fi grupate n tablouri unidimensionale (se mai denumesc vectori) i tablouri multidimensionale, dintre care tablourile bidimensionale (matrice) sunt cel mai frecvent folosite. Numele tabloului (nensoit de indeci) reprezint adresa de memorie la care este alocat tabloul. Se poate determina spaiul de memorie alocat pentru un tablou folosind operatorul sizeof. n mod frecvent, dac se dorete prelucrarea mai multor elemente, sau chiar a tuturor elementelor tabloului, se folosesc instruciunile repetitive (for, while, dowhile). Tablourile unidimensionale cu elemente de tip char sunt folosite n mod uzual pentru memorarea irurilor de caractere. Pentru a marca sfritul unui ir de caractere se folosete un octet cu valoarea 0 (\0), numit i terminator de ir. irurile de caractere pot fi tratate, ca orice tablou unidimensional, fcnd prelucrri element cu element, deci caracter cu caracter. n plus, exist definite n fiierele header standard o mulime de funcii definite pentru prelucrarea irurilor de caractere. Deoarece irurile de caractere sunt construite ca tablouri unidimensionale, majoritatea operatorilor definii n mod standard nu pot opera cu acestea. Un tablou multidimensional este interpretat ca fiind un tablou unidimensional, fiecare element fiind la rndul su un tablou. Dac se dorete prelucrarea tuturor elementelor unui tablou, n mod uzual se folosesc instruciuni repetitive (de regul cicluri for); pentru tablouri multidimensionale se folosesc astfel de instruciuni imbricate.

178

Test de autoevaluare

1. Care din declaraiile de tablouri de mai jos este corecta? a. char nume[4] = {"d","o","r","u"}; b. #define n 10 float cheltuieli[n]; c. char array x[12]; d. #define n 5; int matrice[n]; 2. Care din referirile elementelor tabloului declarat astfel: int b[4] = {1, 2, 3, 4}; sunt corecte? a. float x = b[0]; b. b[4] = 7; c. b[5]; d. nici una din cele de mai sus 3. Care din referirile elementelor tabloului declarat astfel: int b[4] = {1, 2, 3, 4}; sunt corecte? a. int x = b[0]; b. b[3] = b[0]; c. b[4] = b[0]; d. nici una din cele de mai sus 4. Care din referirile elementelor tabloului declarat astfel: double b[4] = {1, 2, 3, 4}; sunt corecte? a. int b = b[2]; b. float x = b[3] + b[1]; c. int y = b[4]; d. nici una din cele de mai sus 5. Se considera declaratia: double tablou[4] = {1, 9, 2, 4}; care din afirmaiile de mai jos sunt adevrate? a. este posibila atribuirea: tablou = 0x1000 b. tablou[4] ntoarce valoarea 4 c. sizeof(tablou[0]) ntoarce 8 d. sizeof(tablou) determina o eroare de sintaxa 6. Un sir de caractere este: a. o secvena de tipul: 'Acesta este un sir' b. un tablou multidimensional ale crui elemente sunt caractere c. o succesiune de uniti alfanumerice pstrate in locaii de memorie succesive care se termina cu 0 d. nimic din cele de mai sus

179

7. Declaratia: char tablou[ ] = {"Sir de caractere"}; a. este greita pentru ca nu este specificat numarul de elemente ale tabloului b. este o declaraie cu initializare c. este greita sintaxa folosita pentru initializarea tabloului d. determina rezervarea in memorie a unei zone in functie de dimensiunea irului dintre ghilimele 8. Se considera programul: #include <stdio.h> void main(void) { char tablou[ ] = "buna ziua!"; tablou[0] = 'B'; tablou[5] = 'Z'; printf("%s\n", tablou); } acest program are ca efect: a. scrierea mesajului: "buna ziua!" pe ecran b. scrierea mesajului: "Buna Ziua!" pe ecran si mutarea cursorului cu un rnd mai jos c. scrierea mesajului: "buna ziua!" pe ecran si mutarea cursorului cu un rnd mai jos d. producerea unor erori de sintax 9. Se considera programul: #include <stdio.h> void main(void) { char tablou[] = "buna ziua!"; char ch; ch = tablou[5]; printf("%c%c\n", ch, ch); tablou[0] = 'B'; printf("%s\n", tablou); } acest program are ca efect: a. scrierea mesajului: "zz" pe un rnd si a mesajului "buna ziua!" pe al doilea rnd b. scrierea mesajului: "ZZ" pe un rnd si a mesajului "buna ziua!" pe al doilea rnd c. scrierea mesajului: "zz" pe un rnd si a mesajului "Buna ziua!" pe al doilea rnd d. scrierea mesajului: "ZZ" pe un rnd si a mesajului "Buna Ziua!" pe al doilea rnd

180

10. Exista vreo deosebire intre: 'c' si "c" ? a. nu exista nici o deosebire, ambele fiind iruri de cate un caracter fiecare b. 'c' este un caracter care este stocat intr-un octet de memorie, iar "c" este un sir format dintr-un singur caracter, fiind stocat in doi octeti de memorie c. "c" este un caracter ,iar 'c' este un sir format dintr-un singur caracter d. nici un rspuns din cele de mai sus nu este corect

ntrebri. Exerciii. Probleme.

1. Se citesc de la tastatur elementele unui tablou unidimensional. S se nlocuiasc toate valorile negative cu valoarea 0. Se afieaz elementele tabloului. 2. Se citesc de la tastatur elementele unui tablou unidimensional. S se afieze, n ordine cresctoare, valorile introduse i numrul lor de apariii. 3. Se citesc de la tastatur elementele a dou tablouri unidimensionale. Se are n vedere ca o valoare s nu se regseasc de mai multe ori ntr-un tablou. S se afieze valorile care se regsesc n ambele tablouri i indecii corespunztori acestora. 4. Se citete de la tastatur un ir de caractere format numai din cifre. S se converteasc n valoarea numeric ntreag corespunztoare. 5. S se ntocmeasc un program n care se citete de la tastatur un ntreg n baza 10. Se afieaz numrul reprezentat n baza 2. Nota: Cifrele binare obinute se vor memora n elementele unui tablou de ntregi. 6. Sa se scrie un program in care se declara o matrice cu 4 x 5 reali. Se citesc de la tastatura valori pentru elementele matricei i se afieaz. Se determin i se afieaz maximele de pe fiecare linie a matricei care se memoreaz ntr-un tablou unidimensional (dimensiunea=nr. de linii ale matricei) i maximul dintre toate elementele matricei.

181

Unitatea de nvare U.10. VARIABILE POINTERI. VARIABILE REFERINE.

Cuprins Introducere .................................................................................................................. 182 Obiectivele unitii de nvare ................................................................................... 182 U10.1. Variabile pointeri ............................................................................................ 183 U10.1.1. Declararea variabilelor pointeri de date ............................................ 183 U10.1.2. Operaii de atribuire cu pointeri ........................................................ 184 U10.1.3. Referirea obiectelor prin variabile pointer ........................................ 185 U10.1.4. Pointeri generici ................................................................................ 186 U10.1.5. Operaii aritmetice cu pointeri .......................................................... 187 U10.1.6. Tablouri i pointeri ........................................................................... 188 U10.2. Variabile referin ........................................................................................... 191 Exemple ...................................................................................................................... 192 Rezumat ...................................................................................................................... 195 Test de autoevaluare ................................................................................................... 195 ntrebri, exerciii i probleme .................................................................................... 198

Introducere Variabilele pointer sunt variabile care primesc ca valoare adrese de memorie. Din punct de vedere al coninutului zonei de memorie adresat prin variabilele pointer, se disting dou categorii: pointeri de date conin ca valori adrese de variabile sau constante; pointeri de funcii conin adrese de cod executabil ale funciilor. n aceast unitate de nvare vor fi prezentate noiuni referitoare la pointeri de date. De asemenea, vor fi prezentate variabilele referin a cror semnificaie fiind apropiat de pointerii de date, ele primind ca valoare adrese de memorie ale unor obiecte. Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Declararea variabilelor pointer; 182

Referirea variabilelor pointer; Semnificaia i folosirea pointerilor generici; Operaiile care pot folosi operanzi pointeri; semnificaia operaiilor aritmetice cu variabile pointer; Legtura dintre variabile pointer i tablouri de date; Semnificaia i modul de folosire a variabilelor referin.

Durata medie de parcurgere a celei de a zecea uniti de nvare este de 2 ore.

U10.1. Variabile pointeri U10.1.1. Declararea variabilelor pointeri de date Sintaxa declarrii unei variabile pointer de date este: tip * nume_variabila; unde: tip poate fi orice tip de date, fundamental sau definit de utilizator; nume_variabil este un identificator. Simbolul * precizeaz c variabila declarat este un pointer. Ea va putea primi ca valoare numai adrese de date de tipul tip. Exemple de declarare a variabilelor pointeri: int * p_i; float * p_f; int* tab_p[10]; float ** p_p; void * p_v; // pointer la tipul int // pointer la tipul float; // tablou de pointeri ctre ntregi // pointer la pointer // pointer la tipul void poate lua ca valoare adresa oricrui tip // de date

Declaraia unei variabile pointer, ca n cazul oricrei variabile, are ca efect alocarea de memorie, adresa putnd fi determinat cu operatorul &, numrul de octei alocai fiind determinat de tipul date (2 sau 4 octei) i se poate determina cu ajutorul operatorului sizeof. int * p_i; &p_i; sizeof(p_i); // pointer la tipul int // expresie care returneaz adresa la care este alocat variabila // expresie care returneaz numrul de octei alocai pentru // variabil

183

Declaraia unei variabile pointer poate fi fcut cu sau fr iniializare. int * p_i; float * p_r = 0; // declaraie fr iniializare // declaraie cu iniializare

U10.1.2. Operaii de atribuire cu pointeri Variabilele pointer pot prelua, prin atribuire, valoarea adreselor unor variabile sau constante alocate n memorie. Atribuirea se poate face numai dac tipul pointerului i tipul datei a crei adres o preia sunt identice. Variabilelor pointer nu li se pot atribui valori constante, cu excepia valorii 0. Exemple de atribuire de valori variabilelor pointeri: int var1; int *p1; p1=&var1; double var2; double *p2; p2=&var2; p2=&var1; p1=0; p1=NULL;

// eroare, se atribuie adresa unui int unui pointer de tip double // atribuire corect, valoarea 0 nu face referire la nici o adres de // memorie // atribuire corect, valoarea NULL este o constant cu valoarea // 0 definit n mai multe fiiere header, cum ar fi stdlib.h, // alloc.h, stdio.h etc. // eroare, nu se admite atribuirea dect a constantei 0 sau a unei // adrese a unui obiect

p1=0xFF00;

Observaii Constanta ntreag 0 se poate atribui oricrei variabil pointer. Aceast valoare este desemnat n mod frecvent prin constanta NULL. Adresele funciilor i obiectelor au valori diferite de 0. Valoarea 0 indic faptul c nu se face referire la nici o adres de memorie. Variabilele pointer neiniializate, ca orice variabil, iau valoarea 0 dac sunt declarate global sau static i valori reziduale n cazul variabilelor automatice. Este important ca orice variabil pointer s fie iniializat cu o valoare valid, 0 sau adresa unui obiect alocat n memorie, nainte de a fi utilizat, deoarece la

184

compilare sau execuie nu se fac verificri privind validitatea adreselor utilizate. Utilizarea incorect a adreselor poate produce efecte necontrolate n evoluia programului. La atribuire este important ca tipul variabilei pointer i tipul datei de la adresa preluat s fie identice, n caz contrar se obine un mesaj de eroare.

U10.1.3. Referirea obiectelor prin variabile pointer Se consider secvena: tip nume_obiect; tip*nume_pointer; nume_pointer = &nume_obiect; Referirea obiectului indirect, prin intermediul variabilei nume_pointer se face cu sintaxa: *nume_pointer Aceast expresie se citete: obiectul de la adresa nume_pointer. Expresia *nume_pointer poate fi folosit att ca rvalue, ct i ca lvalue, adic poate fi folosit att pentru a obine valoarea memorat la adresa indicat de pointer, ct i pentru atribuire. Tipul pointerului determin modul de interpretare a datelor de la adresa indicat. Se ia ca exemplu secvena: int var1=7; int * ptr1 = &var1; Modul de interpretare al acesteia este descris n fig. 10.1.

Fig. 10.1. Exemplu de utilizare a variabilei pointer

Dac variabila var1 este alocat la adresa 1003, variabila ptr1 preia ca valoare valoarea 1003. n continuare este prezentat un exemplu de folosire a variabilelor pointeri.

185

#include <stdio.h> main() { int var=100; // declaraie de variabil int int *ptr; // declaraie de variabil int * (pointer de int) printf("\nVariabila var se afla la adresa: %p\n", &var); printf("\nsi are valoarea var= %d\n", var); ptr=&var; printf("\nVariabila ptr are valoarea: %p\n", ptr); printf("\nsi adreseaza obiectul: %d\n",*ptr); *ptr=200; // se modific valoarea obiectului de la adresa memorat n ptr; // ptr conine adresa variabilei var, deci valoarea 200 este // preluat de var; prin *ptr se face referire n mod indirect la // variabila var, operaia se mai numete indirectare

printf("\nAcum var are valoarea %d\n", var); }

U10.1.4. Pointeri generici Se pot defini pointeri la tipul void. Ei constituie o categorie aparte de pointeri. Acetia pot primi ca valoare adresa oricrui tip de date i se numesc pointeri generici. Exemplu de folosire a pointerilor generici: int vi=10; double vr = 1.5; void * pv; pv = &vi; pv = &vr;

// corect, pv poate prelua adresa oricrui tip de date // corect, pv poate prelua adresa oricrui tip de date

Pentru referirea obiectelor prin intermediul unui pointer generic, este necesar s se precizeze, prin conversia pointerului, tipul obiectului referit, astfel nct compilatorul s aib informaia necesar despre reprezentarea obiectului referit. int vi=10; double vr = 1.5; void * pv; pv = &vi; printf(%d, *(int*)pv); pv = &vr; *(double*)pv = 9.5; printf(%lf, *(double*)pv); 186

U10.1.5. Operaii aritmetice cu pointeri Cu variabilele pointer, n afar de operaiile de atribuire, se pot face i operaii de adunare, scdere, inclusiv incrementare i decrementare i operaii de comparare. Valorile a doi pointeri pot fi comparate folosind operatorii relaionali, spre exemplu: int*p1, *p2; if(p1<p2) printf(p1<p2); if(p1==0) printf(pointerul p1 nu adreseaza nici un obiect); Operaiile de adunare i scdere sunt interpretate diferit fa de operaiile efectuate cu date numerice. Avnd variabila pointer tip * ptr; Expresia: ptr +n returneaz ca valoare adresa memorat n ptr la care se adaug n* sizeof(tip) Pentru situaia descris prin secvena: int var1, var2, *ptr; ptr = &var1; ptr = ptr +1; expresia (ptr + 1) reprezint deplasarea n memorie cu un ntreg, adic cu un numr de octei egal cu sizeof(int) (vezi Fig. 10.2.).

Fig. 10.2. Exemplu pentru operaia de adunare a unui ntreg la un pointer

Exemplu de expresii ce conin operaii aritmetice cu pointeri: 187

float *pf; pf +4; pf++; pf--;

// adresa se modific cu sizeof(float)*4, adic cu 20 de octei // pf i modific valoarea, crete cu 4 octei // pf i modific valoarea, scade cu 4 octei

U10.1.6. Tablouri i pointeri Numele unui tablou fr index este un pointer constant de tipul elementelor tabloului i are ca valoare adresa primului element al tabloului. char *str=STRING;

Fig.9.3. Legtura dintre pointeri i tablouri de date

Avnd n vedere semnificaia operaiilor de adunare i scdere cu variabile pointer, se pot referi elementele tabloului fie prin index, fie prin operaii cu pointeri ca n exemplele urmtoare. Exemple referitoare la legtura dintre pointeri i tablouri de date: float tab[20], *ptr; ptr=tab; &tab[0] = = tab ; &tab[2] = = tab+2 ; tab[0] = = *tab ; tab[2] = = *(tab+2) ; tab++ ; ptr++ ;

// atribuire valid, pointerul ptr va conine adresa // primului element al tabloului // expresie adevrat // expresie adevrat // expresie adevrat // expresie adevrat // eroare, tab este un pointer constant, deci nu se poate // incrementa // corect, ptr este un pointer la float, nu a fost // declarat constant

Tablourile multidimensionale reprezint tablouri cu elemente tablouri, astfel nct numele tabloului (fr index) este un pointer de tablouri. float mat[10][10]; float *p; p=mat; // mat reprezint un tablou de pointeri float // p este un pointer float // eroare, tipurile pointerilor difer, unul este pointer // de float, cellalt e pointer de pointer de float

188

p=(float*)mat; mat = = &mat[0][0]; mat+1 = = &mat[1][0]; *(mat+9) = = mat[9][0];

// corect, s-a folosit o conversie explicit de tip // expresie adevrat // expresie adevrat // expresie adevrat

Avnd n vedere aceste corespondene, se pot scrie secvene de cod echivalente, fie folosind referirea elementelor de tablou prin index, fie folosind expresii cu pointeri, ca n exemplele urmtoare. Secvena urmtoare: int tab[7]={9,11,25,7,44,2,14}; printf("\n\nafisarea elementelor tabloului tab); for( i = 0 ; i <7 ; i++) printf("\ntab[%d] = %d", i, tab[i]); poate fi rescris astfel: int tab[7] = {9,11,25,7,44,2,14}; printf("\n\nafisarea elementelor tabloului tab); for( i = 0 ; i <7 ; i++) printf("\ntab[%d] = %d", i, *(tab + i)); Sau secvena: printf("\n\ncitire de valori de la tastatura pentru elementele tabloului tab"); for( i = 0; i<7 ; i++) { printf("\ntab[%d]=",i); scanf("%d",&tab[i]); } poate fi nlocuit cu: printf("\n\ncitire de valori de la tastatura pentru elementele tabloului tab"); for( i = 0; i<7 ; i++) { printf("\ntab[%d]=",i); scanf("%d", tab + 1); // n funcia scanf() se precizeaz adresa la care // se depune valoarea citit de la tastatur } n mod similar se poate proceda i n cazul matricelor. Astfel, secvena de citire a elementelor matricei de la tastatur urmtoare: int mat[3][4], i, j; //se citesc de la tastatura elementele lui mat printf("Introduceti elementele matricei mat:\n"); for(i=0 ; i<3 ; i++) 189

// expresia tab+i reprezint ca valoare // adresa elementului de index i

for(j=0 ; j<4 ; j++) { printf("mat1[%d][%d]=", i, j); scanf("%d", &mat1[i][j]); } se poate scrie folosind operaii cu pointeri: printf("Introduceti elementele matricei mat:\n"); for(i=0;i<3;i++) for(j=0;j<4;j++) { printf("mat[%d][%d]=", i, j); scanf("%d",*(mat+i)+j); // expresia (*(mat+i)+j) reprezint adresa // elementului de pe linia i, coloana j }

Observaii Expresia (mat) reprezint adresa la care e alocat matricea; ca tip de dat este un pointer de pointer de int (dubl indirectare); Expresia (mat+i) reprezint adresa liniei de index i; ca tip de dat este un pointer de pointer de int (dubl indirectare); Expresia *(mat+i) reprezint adresa primului element de pe linia de index i; ca valoare este egal cu valoarea expresiei (mat+i) dar ca tip de dat este un pointer de int (simpl indirectare); Expresia *(mat+i)+j reprezint adresa elementului de index j al liniei de index i ; ca tip de dat este un pointer de int (simpl indirectare). Secvena de afiare a elementelor matricei: printf("\nmat:"); for(i=0;i<3;i++) { printf("\n"); for(j=0;j<4;j++) printf("%6d",mat[i][j]); } este echivalent cu secvena: printf("\nmat:"); for(i=0;i<3;i++) { printf("\n"); for(j=0;j<4;j++) printf("%6d",*(*(mat+i)+j)); } 190

U10.2. Variabile referin C++ ofer posibilitatea de a declara identificatori ca referine de obiecte (variabile sau constante). Referinele, ca i pointerii, conin adrese. Pentru a declara o referin la un obiect se folosete simbolul &, folosind sintaxa: tip & id_referinta = nume_obiect; unde: - tip este tipul obiectului pentru care se declar referina, - simbolul & precizeaz c id_referinta este numele unei variabile referin - nume_obiect este obiectul a crui adres va fi coninut n id_referinta. Exemplu de declarare i folosire comparativ a variabilelor pointeri i referin: int n; int * p=&n; int &r=n; n=20; *p=25; r=30; // se declar n de tip ntreg // se declar pointerul p cu iniializare adresa lui n // se definete r referina lui n // n primete valoarea 20 // n primete valoarea 25 // n primete valoarea 30

n exemplul anterior, att p, ct i r, acioneaz asupra variabilei n. Atunci cnd se acceseaz o variabil prin referina sa, nu este necesar s se foloseasc adresa, acest lucru realizndu-se automat. Spre deosebire de pointeri, care la un moment dat pot primi ca valoare adresa unei alte variabile, referinele nu pot fi modificate, ele fiind practic o redenumire a variabilei a cror adres o conin (se creeaz un alias al respectivei variabile). n utilizarea referinelor, trebuie avute n vedere urmtoarele restricii: referinele trebuie iniializate n momentul declarrii; referinelor nu li se pot modifica locaiile la care se refer; nu sunt permise referine la cmpuri de bii, referine la referine i pointeri la referine, deci nici tablouri de referine. int &r ; int &r=20 ; const int i = 20; int &r = i ; const int i = 20; const int &r = i ; // eroare, se declar o referin fr iniializare // corect, se declar o referin la o constant // eroare, se declar o referin ntreag la o constant // ntreag // corect, se declar o referin constant ntreag la o // constant ntreag

191

Observaii Referinele de sine stttoare sunt rar folosite. n schimb, utilizarea parametrilor formali referin permite transferul prin referin simplu i eficient, fr recurgerea la parametri formali pointeri.

Exemple

/*************************************************************************** Exemplul 10.1. Se exemplific legtura dintre tablouri i pointeri. Se folosete n paralel referirea elementelor unui tablou unidimensional prin indeci i, respectiv, folosind operaii cu pointeri. ***************************************************************************/ #include <stdio.h> #include <conio.h> void main() { float vect[]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; float *p; int i; p=vect; printf("\n"); //se afiseaza elementele tabloului vect - referirea elementelor se face prin index for(i=0 ; i<12 ; i++) printf("%6.2f", vect[i]); printf("\n"); //se afiseaza elementele tabloului vect - referirea elementelor se face prin adrese for(i=0 ; i<12 ; i++) printf("%6.2f", *(vect+i)); printf("\n"); //se afiseaza elementele tabloului vect - referirea elementelor se face prin adrese, folosind //pointerul p (p nu isi modifica valoarea) for(i=0 ; i<12 ; i++) printf("%6.2f", *(p+i)); printf("\n");

192

//se afiseaza elementele tabloului vect - folosind pointerul p, referirea se face prin index //(p nu isi modifica valoarea) for(i=0 ; i<12 ; i++) printf("%6.2f", p[i]); printf("\n"); //se afiseaza elementele tabloului vect - folosind pointerul p (p isi modifica valoarea prin //incrementare) for(i=0 ; i<12 ; i++) printf("%6.2f", *p++); getch(); }

/*************************************************************************** Exemplul 10.2. Se exemplific legtura dintre tablouri i pointeri. Se folosete n paralel referirea elementelor unui ir de caractere folosind operaii cu pointeri. ***************************************************************************/ #include <stdio.h> #include <conio.h> void main(void) { char sir[25] = "siruri si pointeri"; int i; // Se afiseaza, caracter cu caracter, toate caracterele in format %c si %d. for(i=0 ; i<25 ; i++) printf("\n %c - %d", *(sir+i), *(sir+i)); printf("\n"); // Se afiseaza, caracter cu caracter, toate caracterele, pana la intalnirea terminatorului de sir, // in format %c si %d . for(i=0 ; *(sir+i) != 0 ; i++) printf("\n %c - %d", *(sir+i), *(sir+i)); *sir = 'S'; *(sir+7) = 'S'; *(sir+10) = 'P'; printf("\nSirul este: %s", sir); getch(); }

193

/*************************************************************************** Exemplul 10.3. Se exemplific legtura dintre tablouri i pointeri. Se folosete n paralel referirea elementelor unui tablou multidimensional (matrice) prin indeci i, respectiv, folosind operaii cu pointeri. ***************************************************************************/ #include <stdio.h> #include <conio.h> void main() { int mat[3][4]={ {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; int *p, i, j; //afisarea elementelor matricii - referire prin cei doi indecsi for(i=0 ; i<3 ; i++) { printf("\n"); for(j=0 ; j<4 ; j++) printf("%5d", mat[i][j]); getch(); } //afisarea de informatii despre matrice printf("\nsizeof(*mat) = %d", sizeof(*mat)); printf("\n**mat = %d", **mat); printf("\n**(mat+1) = %d", **(mat+1)); printf("\n**(mat+2) = %d", **(mat+2)); //atribuire prin conversie explicita a pointerului p = (int*)mat; // afisarea elementelor tabloului, folosind pointerul p for(i=0 ; i++ ; i<12) printf("%5d", *(p+i)); getch(); // afisarea elementelor tabloului, folosind pointerul p cu specificarea liniei si coloanei // elementului for(i=0 ; i<3 ; i++) { printf("\n"); for(j=0 ; j<4 ; j++) printf("%5d", *(p+i*4+j)); 194

getch(); } for(i=0 ; i<3 ; i++) { printf("\n"); for(j=0 ; j<4 ; j++) printf("%5d", p[i*4+j]); getch(); } printf("\n"); getch(); }

Rezumat Variabilele pointer sunt variabile care primesc ca valoare adrese de memorie. Pentru a declara un pointer se folosete simbolul *. Declaraia unei variabile pointer, ca n cazul oricrei variabile, are ca efect alocarea de memorie; variabilele pointer sunt caracterizate de aceleai atribute ca orice variabil (clas de memorare, domeniu, durat de via). Declaraia unei variabile pointer poate fi fcut cu sau fr iniializare. Variabilele pointer pot prelua, prin atribuire, valoarea adreselor unor variabile sau constante alocate n memorie; atribuirea se poate face numai dac tipul pointerului i tipul datei a crei adres o preia sunt identice. Variabilelor pointer nu li se pot atribui valori constante, cu excepia valorii 0. Tipul pointerului determin modul de interpretare a datelor de la adresa indicat de acesta. Se pot defini pointeri la tipul void. Ei pot primi ca valoare adresa oricrui tip de date i se numesc pointeri generici. Cu variabilele pointer se pot face operaii aritmetice (adunare, scdere cu un ntreg, incrementare, decrementare) i operaii de relaionale. Numele unui tablou fr index este un pointer constant de tipul elementelor tabloului. Tablourile multidimensionale reprezint tablouri cu elemente tablouri, astfel nct numele tabloului (fr index) este un pointer de tablouri. Referinele, ca i pointerii, conin adrese. Pentru a declara o referin la un obiect se folosete simbolul &. Variabilele referin trebuie iniializate n momentul declarrii; referinelor nu li se pot modifica locaiile la care se refer.

195

Test de autoevaluare

1. Care din secvenele de mai jos este corecta? a. char nume[4], *p; p=nume; b. #define n 10 float cheltuieli[n]; cheltuieli++; c. char array[12]; array=100; d. #define n 5; int matrice[n]; *matrice = 10; 2. Se considera declaratia: int tablou[4] = {1, 9, 2, 4}; care din afirmaiile de mai jos sunt adevrate? a. sizeof(tablou[0]) ntoarce 4 b. sizeof(tablou) ntoarce 16 c. *(tablou+2) este acelai lucru cu tablou[2] d. *tablou[0] este acelai lucru cu tablou 3. Ce va afisa secvena de instruciuni C de mai jos? int x, a[4]; x = &a[2] - &a[0]; printf("%d", x); a. 6 b. 2 c. 3 d. Nimic din cele de mai sus, secvena fiind greita 4. Ce va afisa secvena de instruciuni C de mai jos? int x; float a[10]; x = &a[8] - &a[0]; printf("%d", x); a. 16 b. 32 c. 8 d. Un mesaj de eroare 5. Se considera secvena: float tabel[5] = {1, 2, 3, 4, 5}; float *pt; Care din instruciunile de mai jos sunt corecte? a. tabel = pt; b. pt = tabel; c. pt++; d. tabel++; e. tabel[2]--; 6. Se considera secvena: float tabel[5] = {1, 2, 3, 4, 5};

196

float *pt; Care din instruciunile de mai jos sunt corecte? a. --pt; b. tabel[4]--; c. (*(tabel+3))--; d. --tabel; 7. Care din atribuirile de mai jos sunt corecte? a. char *adr_sir; ... adr_sir = "Acest sir"; b. char tab[5] = {"Acest sir"}; c. char tab[10] = {"Acest sir"}; d. char tab[10]; tab = "Acest sir"; 8. Se considera programul: #include <stdio.h> void main(void) { char* adr_sir = "Sir de caractere"; char ch; ch = *(adr_sir+4); printf("%c", ch); } acest program are ca efect: a. scrierea caracterului d pe ecran b. citirea unui caracter de la tastatura c. nici un efect vizibil 9. Se considera programul: #include <stdio.h> void main(void) { char* adr_sir = "Sir de caractere"; char ch; ch=*(adr_sir+3); printf("%c",ch); } acest program are ca efect: a. scrierea caracterului d pe ecran b. producerea unor erori c. citirea unui caracter de la tastatura d. mutarea cursorului cu o pozitie la dreapta 10. Se considera declaraiile de mai jos: char* pointer_la_caracter; char caracter; care din secvenele de mai jos sunt corecte? a. &caracter = "a"; b. pointer_la_caracter = "b"; c. pointer_la_caracter = 'a'; d. *pointer_la_caracter = "b"; 197

11. Se considera programul de mai jos: #include <stdio.h> void main(void) { char sir[10] = "Mesaj"; int i; for(i=0 ; sir[i] ; i++); printf("Numar=%d\n", i); } Care din afirmaiile de mai jos sunt adevrate? a. ieirea din ciclul for se face la ntlnirea marcajului '\0' b. programul are ca efect afisarea pe ecran a mesajului: Numar=6 c. programul are ca efect afisarea pe ecran a mesajului: Numar=5 d. programul conine erori de sintaxa 12. Secvena urmtoare: void main (void) { char *adr; adr='h'; .... } are ca efect: a. se pune in pointer adresa irului 'h' b. la adresa din variabila adr se pune 'h' c. eroare, nu se poate pune un caracter intr-o variabila de tip adresa

ntrebri. Exerciii. Probleme.

1. Se citesc de la tastatur elementele unui tablou unidimensional. S se nlocuiasc toate valorile negative cu valoarea 0. Se afieaz elementele tabloului. Pentru referirea elementelor se vor folosi operaii cu pointeri. 2. Se citesc de la tastatur elementele a dou tablouri unidimensionale de aceeai dimensiune. Se calculeaz elementele unui al treilea tablou ca sum a elementelor de acelai index ale primelor dou i se afieaz. Pentru referirea elementelor se vor folosi operaii cu pointeri. 3. Se citesc de la tastatur dou iruri de caractere. Se determin un al treilea ir prin concatenarea primelor dou i se afieaz. Pentru referirea elementelor se vor folosi operaii cu pointeri.

198

Unitatea de nvare U.11.ALOCARE DINAMIC DE MEMORIE

Cuprins Introducere .................................................................................................................. 199 Obiectivele unitii de nvare ................................................................................... 200 U11.1. Alocare dinamic de memorie ........................................................................ 200 U11.2. Alocare dinamic de memorie folosind funcii specifice................................ 201 U11.3. Alocare dinamic de memorie folosind operatorii new i delete .................... 203 U11.4. Alocare dinamic de memorie pentru tablouri multidimensionale ................. 205 Exemple ...................................................................................................................... 207 Rezumat ...................................................................................................................... 211 Test de autoevaluare ................................................................................................... 212 ntrebri, exerciii i probleme .................................................................................... 215

Introducere Pentru toate tipurile de date descrise pn acum (simple sau structurate), memoria necesar la execuia programului este determinat de declaraiile fcute pentru variabile, deci ea este stabilit nainte de execuia programului. Variabilele sunt alocate n memorie n momentul declarrii lor i rmn alocate tot timpul execuiei programului n cazul variabilelor globale sau statice sau, n cazul variabilelor automatice, pn la ncheierea blocului n care au fost declarate. Sunt situaii n care, pentru o gestionare eficient a memoriei, este de dorit ca n momentul n care unele variabile nu mai sunt necesare s fie eliminate din memorie. De asemenea, la scrierea programelor se dorete s se dea un grad de generalitate ct mai mare, astfel nct s poat fi prelucrate, dup acelai algoritm, pachete de date de diferite dimensiuni. De exemplu, dac ntr-un program este declarat un tablou de date, pentru el este stabilit dimensiunea printr-o constant. Este posibil ca la execuia programului s fie necesar un numr mult mai mic de elemente, ceea ce nseamn c o parte din memorie este alocat inutil. Dac ns numrul de elemente necesar este mai mare dect dimensiunea stabilit, este necesar modificarea codului surs i recompilarea lui. Astfel de situaii pot fi evitate prin manevrarea n mod dinamic a variabilelor, adic, stabilirea dimensiunii memoriei necesare n momentul execuiei programului, alocarea ei n momentul n care variabilele devin necesare i eliminarea lor cnd utilitatea lor a ncetat. Memoria astfel eliberat va putea fi realocat n alt scop. 199

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Cum determin clasa de memorare a variabilelor declaraia acestora; Funcii folosite pentru alocarea dinamic de memorie; Utilizarea operatorilor new i delete; Alocarea dinamic a tablourilor uni i multi-dimensionale.

Durata medie de parcurgere a celei de a unsprezecea uniti de nvare este de 2 ore.

U11.1. Alocarea dinamic de memorie Pentru gestionarea memoriei, aceasta este mprit n segmente specializate. Microprocesoarele dispun de regitri n care se memoreaz adresele segmentelor. Se folosesc patru regitri de segment specializai (CS, DS, ES, SS), ceea ce permite adresarea simultan a patru segmente folosindu-se adresa de segment din registrul asociat: - segment de cod (instruciuni) - Code Segment (CS); - segment de date Data Segment (DS); - segment de date suplimentar ExtraSegment (ES) ; - segment de stiv Stack Segment (SS). Avnd n vedere acest mod de gestionare a memoriei, programele C/C++, la execuie, ncarc n memorie 4 tipuri de informaie: - codul executabil memorat n segmente de cod; - date statice memorate n segmente de date; - date automatice alocate n pe stiv sau regitri; - date dinamice alocate n zona heap. Se aloc static memorie pentru constante, variabilele globale i variabilele locale declarate n mod explicit static. Se aloc memorie pe stiv pentru variabilele locale. int a, b; double x; // a, b, x - variabile declarate global, alocate n segmentul de date // parametrii c, v alocai pe stiv // b variabil local funciei f1(), alocat pe stiv // z variabil local funciei declarat static, alocat n // segmentul de date

double f1(int c, double v) { int b; static double z; .... }

200

void main() { int k; printf(Sir constant); .... }

// k variabil local funciei main(), alocat pe stiv // constanta Sir constant este memorat n segmentul // de date

Este de dorit ca n cazul datelor a cror dimensiune nu este cunoscut a priori sau variaz n limite largi, s se utilizeze o alt abordare: alocarea memoriei n mod dinamic. n mod dinamic, memoria nu mai este alocat n momentul compilrii, ci n momentul execuiei. Alocarea dinamic elimin necesitatea definirii complete a tuturor cerinelor de memorie n momentul compilrii.

U11.2. Alocarea dinamic de memorie folosind funcii specifice Alocarea de memorie dinamic se realizeaz n mod explicit, cu ajutorul funciilor de alocare dinamica n limbajul C. C++ completeaz posibilitile de alocare dinamic prin operatorii new i delete care sunt adaptai programrii orientate pe obiecte. n limbajul C, alocarea memoriei n mod dinamic se face cu ajutorul funciilor malloc, calloc, realloc; eliberarea zonei de memorie se face cu ajutorul funciei free. Funciile de alocare/dealocare a memoriei au prototipurile n fiierele header <stdlib.h> i <alloc.h>: Alocarea de memorie se poate face cu funciile: void *malloc(size_t nr_octei_de_alocat); - Funcia malloc necesit un singur argument (numrul de octei care vor fi alocai) i returneaz un pointer generic ctre zona de memorie alocat (pointerul conine adresa primului octet al zonei de memorie rezervate). void *calloc(size_t nr_elemente, size_t mrimea_n_octei_ a_unui_elem); - Funcia calloc lucreaz n mod similar cu malloc; aloc memorie pentru un tablou de nr_elemente, numrul de octei pe care este memorat un element este mrimea_n_octei_a_unui_elem i returneaz un pointer ctre zona de memorie alocat. void *realloc(void *ptr, size_t mrime); - Funcia realloc permite modificarea zonei de memorie alocat dinamic cu ajutorul funciilor malloc sau calloc. Funciile malloc, calloc, realloc returneaz adresa de memorie la care s-a fcut alocarea. Valoarea ntoars este un pointer generic (void*). Aceasta, de regul, se memoreaz ntr-o variabil pointer de un tip oarecare, astfel c la atribuire este necesar conversia explicit ctre tipul variabilei situat n stnga operatorului de atribuire. 201

n cazul n care nu se reuete alocarea dinamic a memoriei (memorie insuficient), funciile malloc, calloc i realloc returneaz un pointer NULL ( valoare 0). Eliberarea memoriei (alocate dinamic cu una dintre funciile malloc, calloc sau realloc) se realizeaz cu ajutorul funciei free. void free(void *ptr); Exemple de folosire a funciilor de alocare dinamic: int *p; p=(int*)malloc(20*sizeof(int));

// se rezerv 20*sizeof(int) octei, adresa fiind // memorat n variabila p

sau p=(int*)calloc(20, sizeof(int)); Eliberarea de memorie se face: free(p);

Observaii Alocarea fcut n exemplele anterioare poate fi gestionat similar cu un tablou alocat prin declaraia int p[20]; Avantajul const n faptul c, n momentul n care alocarea nu mai este necesar, se poate folosi funcia free(), memoria respectiv putnd fi apoi folosit n alt scop. Pentru a se evita generarea unor erori, se recomand s se verifice dac operaiile de alocare au reuit: int *p; p=(int*)malloc(20*sizeof(int)); if ( p== NULL) { printf(\nAlocare imposibila !); exit(1); } .

// dac valoarea preluat de p este NULL // (0), operaia de alocare a euat, ceea ce // poate genera erori fatale

202

Dimensiunea, n octei, pentru memoria alocat poate fi exprimat nu doar printr-o constant, ci i prin variabile sau chiar expresii diverse care returneaz valoare ntreag pozitiv. int dimensiune; float*pr; printf(\nIntroducei dimensiunea :); scanf(%d, &dimensiune); pr = (float*)malloc( dimensiune * sizeof(float)) ; . free(pr) ; printf(\nIntroducei alta valoare pentru dimensiune:); scanf(%d, &dimensiune); pr = (float*)malloc( dimensiune * sizeof(float)) ; free(pr) ; Observaii Dimensiunea alocrii e stabilit n momentul execuiei programului prin citirea variabilei dimensiune. Alocarea de memorie poate fi repetat. Eliberarea memoriei alocat cu malloc, calloc se face numai cu funcia free; dac nu este apelat funcia free i pointerul pr i schimb valoarea, zona alocat nu va mai putea fi accesat, blocnd memorie n mod inutil; Dac operaiile de alocare se repet fr eliberare de memorie fcut ntre timp, se poate ajunge la ocuparea ntregii memorii.

U11.3. Alocarea dinamic de memorie folosind operatorii new i delete C++ introduce o nou metod pentru alocarea dinamic a memoriei adaptat programrii orientate ctre obiecte. Alocarea memoriei se face cu operatorul unar new, folosind urmtoarea sintax: var_ptr = new tip_var; var_ptr = new tip_var(val_init); var_ptr = new tip_var[dim]; unde: - var_ptr = o variabil pointer de un tip oarecare; - tip_var = tipul variabilei dinamice var_ptr; - val_init = expresie cu a crei valoare se iniializeaz variabila dinamic; Varianta 1 aloc spaiu de memorie corespunztor unei date de tip tip_var, fr 203 // 1 // 2 // 3

iniializare. Varianta 2 aloc spaiu de memorie corespunztor unei date de tip tip_var, cu iniializare. Varianta 3 aloc spaiu de memorie corespunztor unei tablou cu elemente de tip tip_var de dimensiune dim. Iniializarea tabloului nu este posibil. Dac alocarea de memorie a reuit, operatorul new returneaz adresa zonei de memorie alocate. n caz contrar, returneaz valoarea NULL (=0) (n cazul n care memoria este insuficient sau fragmentat). int n=3, * p1, *p2, *p3; p1=new int; p2=new int(15); p3=new int[n];

// variabil ntreag neiniializat // variabil ntreag iniializat cu valoarea 15 // tablou unidimensional int de dimensiune n

Eliminarea variabilei dinamice i eliberarea zonei de memorie se face cu operatorul delete, folosind sintaxa: delete var_ptr; sau delete [ ]var_ptr; // 2 unde var_ptr conine adresa obinut n urma unei alocri cu operatorul new. Utilizarea altei valori este ilegal, putnd determina o comportare a programului necontrolat. Varianta de dealocare (1) este folosit dac la alocare s-au folosit variantele de alocare (1) sau (2), iar varianta (2) dac la alocare s-au folosit varianta de alocare (3). int *p; p=new int(10); delete p; int *p,*q; p=new int(7); q=p; delete q; *p=17; int x=7; int *y=&x; delete y; // 1

// se aloc spaiul de memorie necesar unui int i se face // iniializarea cu valoarea 10 // se elimin variabila p din memorie

// se aloc spaiul de memorie necesar unui int i se face // iniializarea cu valoarea 7 // variabila pointer q primete ca valoare adresa coninut // n variabila p // se elibereaz zona de memorie de la adresa coninut // n variabila q // incorect, folosete o zona de memorie care a fost deja // dealocat // incorect, se cere dealocarea unei zone de memorie // care nu a fost alocat cu operatorul new

204

double * pr; pr= new double[10]; delete [ ] pr; double * pr; pr= new double[10]; delete pr;

// se aloc 10 elemente de tip double // eliberarea spaiului pentru cele 10 elemente // se aloc 10 elemente de tip double // se elibereaz doar spaiul ocupat de primul element, // celelalte 9 elemente rmnnd alocate n continuare n // memorie

U11.4. Alocarea dinamic de memorie pentru tablouri multidimensionale Funciile, respectiv operatorul new, destinate alocrii de memorie permit alocarea dinamic de tablouri, dar sintaxa permite stabilirea unei singure dimensiuni. Se pune problema construirii de tablouri multidimensionale. Dac se dorete alocarea unui tablou cu n dimensiuni (dim1, dim2,...,dimn), se poate aloca un tablou unidimensional cu un numr de elemente calculat prin produsul dim1*dim2*...*dimn, urmnd ca apoi s se gestioneze logic aceste elemente prin expresii care calculeaz indecii elementelor care s descrie parcurgerea tablourilor. De exemplu, pentru a construi o matrice (tablou bidimensional), cu n linii i m coloane, se aloc un tablou unidimensional de dimensiune n*m. Indecii elementelor se calculeaz cu expresia : (i * m) + j, unde i reprezint numr de linie, j reprezint numr de coloan. Acest mod de abordare se regsete n exemplul urmtor. int n, m; int * mat; int i, j; // n - nr. de linii ; m nr. coloane // pointer folosit pentru alocarea de memorie // variabile folosite pentru parcurgerea elementelor matricei

// citirea dimensiunilor matricei printf("\nNumarul de linii:"); scanf("%d", &n); printf("\nNumarul de coloane:"); scanf("%d", &m); // alocarea de memorie mat=new int[n*m.]; //... // dealocarea de memorie delete [ ]mat; O alt posibilitate de construire a matricei este folosirea unei duble indirectri (int**mat). Alocarea se face n dou etape. O prim etap n care se aloc un tablou

205

unidimensional cu elemente de tip int* de dimensiune egal cu numrul de linii. Elementele acestuia vor memora adresele obinute n a doua etap, cnd, ntr-o secven repetitiv se vor aloca tablouri unidimensionale cu elemente de tip int. Se aloc un numr egal cu numrul de linii de tablouri, fiecare avnd un numr de elemente egal cu numrul de coloane. int n, m; int ** mat; int i, j; //.... //alocarea tabloului de adrese mat=new int*[n]; // alocarea celor n linii ale matricei; alocarea se face distinct pentru fiecare linie for(i=0; i<n ; i++) mat[i]=new int[m]; //.... Eliberarea de memorie se va face tot n dou etape, ordinea dealocrii fiind invers celei de alocare. // dealocarea celor n linii ale matricei; se face distinct pentru fiecare linie for(i=0; i<n ; i++) delete [ ]mat[i]; // dealocarea tabloului de adrese delete [ ]mat;

Fig. 11.1. Reprezentarea alocrii dinamice de memorie a unei matrice folosind dubla indirectare (nr.linii = 5, nr.coloane = 6)

Aceast metod de lucru are dou avantaje fa de anterioara. Un prim avantaj, unul formal, l constituie faptul c referirea elementelor se face similar declaraiei statice a

206

tabloului (mat[i][j]). Cel de al doilea avantaj este faptul c, spre deosebire de alocarea ca tablou unidimensional, cnd toate elementele sunt alocate ntr-o zon contigu de memorie, n cazul alocrii prin dubla indirectare alocarea se face disparat, fiecare linie putnd fi alocat n alt zon a segmentului heap. Aceasta duce la o mai bun utilizare a memoriei. n Fig. 11.1. este reprezentat modul de alocare a memoriei pentru situaia n care numrul de linii este 5, iar numrul de coloane este 6.

Exemple

/**************************************************************************

Exemplu1 11.1. - Se scrie un program n care se exemplific folosirea alocrii dinamice de memorie. Se realizeaz alocare de blocuri de memorie n mod repetat, pn la ocuparea ntregii memorii. **************************************************************************/ #include<stdio.h> #include<conio.h> #include<malloc.h> void main() { int i, dim;

// variabila dim determin dimensiunea blocurilor de // memorie care se vor aloca

double *p; printf("\nIntroducei dimensiunea blocurilor: "); scanf("%d", &dim); // se folosete instruciunea for fr specificarea condiiei de ieire din ciclu; // ieirea se va face cu instruciunea "break" n momentul n care memoria a fost ocupat i // alocarea nu se mai poate face, deci p ia valoarea NULL for(i=1; ;i++) { p=(double *)malloc(dim*sizeof(double)); if( p != NULL) printf("\nS-a alocat blocul nr. %d la adresa %u", i, p); else { printf("\nAlocare imposibila - memorie insuficienta "); break; } } }

207

/**************************************************************************

Exemplu1 11.2. - Se scrie un program n care se exemplific folosirea alocrii dinamice de memorie. Sunt folosite, comparativ, secvene n care se folosesc tablouri unidimensionale de date alocate static i tablouri alocate dinamic. **************************************************************************/ #include<conio.h> #include<stdio.h> #include<malloc.h> void main() { float tab[10]; // tablou alocat static float *p, aux; int i, dim; //se citesc valori pentru elementele tabloului static for(i=0;i<10;i++) { printf("\n tab[%d]=", i); scanf("%f", &tab[i]); } // se afiseaza valorile elementelor tabloului static for(i=0;i<10;i++) printf("\n tab[%d]=%f", i , tab[i]); // alocare dinamica de memorie pentru un tablou de dimensiune stabilita de la tastatura printf("\nIntroduceti dimensiunea tabloului:"); scanf("%d", &dim); p=(float*)malloc(dim*sizeof(float)); // se citesc valori pentru elementele tabloului alocat dinamic for(i=0 ; i<dim ; i++) { printf("\np[%d] = ", i); scanf("%f", &aux); *(p+i)=aux; } // se afiseaza valorile elementelor tabloului alocat dinamic for(i=0;i<dim;i++) printf("\n tab[%d] = %f", i, *(p+i)); // se elimina tabloul dinamic din memorie free(p); // se face o realocare de memorie printf("\nIntroduceti dimensiunea tabloului care se realoc:"); scanf("%d", &dim); p=(float*)malloc(dim*sizeof(float));

208

// se citesc valori pentru elementele tabloului alocat dinamic for(i=0;i<dim;i++) { printf("\np[%d]=",i); scanf("%f", p+i); } // se afiseaza valorile elementelor tabloului alocat dinamic for(i=0;i<dim;i++) printf("\n tab[%d]=%f", i ,*(p+i)); // se elimina tabloul dinamic din memorie free(p); getch(); }

/**************************************************************************

Exemplu1 11.3. - Se scrie un program n care se exemplific folosirea alocrii dinamice de memorie. Se aloc un tablou unidimensional de date, elementele sale fiind interpretate din punct de vedere logic ca aparinnd unei matrice (se folosete simpla indirectare: int*mat). **************************************************************************/ #include <conio.h> #include <stdio.h> void main() { int n, m; int * mat; int i, j;

// n - nr. de linii ; m nr. coloane // pointer folosit pentru alocarea de memorie // variabile folosite pentru parcurgerea elementelor matricei

// citirea dimensiunilor matricei printf("\nNumarul de linii:"); scanf("%d", &n); printf("\nNumarul de coloane:"); scanf("%d", &m); // alocarea de memorie mat=new int[n*m]; //citirea elementelor matricei for(i=0;i<n;i++) for(j=0;j<m;j++) { printf("mat[%d][%d]=",i,j); scanf("%d", &mat[i*m+j]); }

209

// afiarea elementelor tabloului for(i=0 ; i<n ; i++) { printf("\n"); for(j=0;j<m;j++) printf("%5d",mat[i*m+j]); } //afiarea de informaii despre matrice printf("\nsizeof(*mat)=%d", sizeof(*mat)); printf("\n*(mat+0*m)=%d",*(mat+0*m)); if(n>1) printf("\n*(mat+1*m)=%d",*(mat+1*m)); if(n>2) printf("\n*(mat+2*m)=%d",*(mat+2*m)); delete [ ]mat; } // se afieaz primul // element de pe linia a treia // dealocarea memoriei // se afieaz primul // element de pe linia a doua // se afieaz numrul de // octei ocupai de matrice // se afieaz primul // element de pe prima linie

/************************************************************************** Exemplu1 11.4. - Se scrie un program n care se exemplific folosirea alocrii dinamice de memorie. Se folosete dubla indirectare: int**mat pentru a construi o matrice. **************************************************************************/ #include <conio.h> #include <stdio.h> void main() { int n, m; int ** mat; int i, j; printf("\nNumarul de linii:"); scanf("%d", &n); printf("\nNumarul de coloane:"); scanf("%d", &m); mat=new int*[n]; for(i=0 ; i<n ; i++) mat[i]=new int[m]; //citirea elementelor matricei for(i=0 ; i<n ; i++)

210

for(j=0 ; j<m ; j++) { printf("mat[%d][%d] = ", i, j); scanf("%d", &mat[i][j]); } //afiarea elementelor matricei for(i=0 ; i<n ; i++) { printf("\n"); for(j=0 ; j<m ; j++) printf("%5d", mat[i][j]); } //afiarea de informaii despre matrice printf("\nsizeof(*mat) = %d", sizeof(*mat)); printf("\n**mat = %d", **mat); if(n>1) printf("\n**(mat+1) = %d", **(mat+1)); if(n>2) printf("\n**(mat+2)=%d",**(mat+2)); for(i=0; i<n ; i++) delete [ ] mat[i]; delete [ ] mat; } // se afieaz numrul de // octei ocupai de matrice // se afieaz primul // element de pe prima linie // se afieaz primul // element de pe linia a doua // se afieaz primul // element de pe linia a treia // dealocarea memoriei

Rezumat Manevrarea n mod dinamic a variabilelor permite stabilirea dimensiunii memoriei necesare n momentul execuiei programului, alocarea ei n momentul n care variabilele devin necesare i eliminarea lor cnd utilitatea lor a ncetat. Memoria astfel eliberat poate fi realocat n alt scop. Se aloc static memorie pentru constante, variabilele globale i variabilele locale declarate n mod explicit static. Se aloc memorie pe stiv pentru variabilele locale. n limbajul C, alocarea memoriei n mod dinamic se face cu ajutorul funciilor (malloc, calloc, realloc); eliberarea zonei de memorie se face cu ajutorul funciei free.

211

n cazul n care nu se reuete alocarea dinamic a memoriei (memorie insuficient), funciile malloc, calloc i realloc returneaz un pointer NULL (valoare 0). Dimensiunea, n octei, pentru memoria alocat poate fi exprimat printr-o constant, prin variabile sau prin expresii diverse care returneaz valoare ntreag pozitiv. Dac operaiile de alocare se repet fr eliberare de memorie fcut ntre timp, se poate ajunge la ocuparea ntregii memorii. C++ introduce o nou metod pentru alocarea dinamic a memoriei folosind operatorii unari new i delete. Funciile, respectiv operatorul new, destinate alocrii de memorie permit alocarea dinamic de tablouri cu o singur dimensiune. Pentru alocarea tablourilor cu mai multe dimensiuni se folosesc multiple indirectri, alocarea de memorie fiind fcut n mai multe etape.

Test de autoevaluare

1. Se da secvena: ....... int *p; p=new int(7); ............ Ce se ntmpl la compilare? a. variabilei p i se atribuie valoarea 7; b. adresa memorat de p este 7; c. se aloca memorie pentru un ntreg si aceasta se initializeaza cu 7 d. lui p i se atribuie adresa unei zone de memorie constituita din 7 locaii consecutive de ntreg (7*2)octeti 2. Se da secvena: ......... int *p; p=new int[7]; ......... Ce se ntmpl la compilare? a. se aloc zona de memorie pentru 7 ntregi consecutivi (7*4)octeti b. secvena genereaz un mesaj de eroare c. lui p i se atribuie valoarea 7; d. se aloca 7 octeti de memorie pentru p.

212

3. Ce efect are ultima linie din secvena de program: ........ int *p; p=new int(10); delete p; .......... a. dealoca zona de memorie indicata de pointerul p; b. terge coninutul lui p; c. lui p i se atribuie valoarea 10 d. dealoca 10 octeti de memorie ncepnd cu adresa coninuta in p 4. Ce greeala exista in aceasta secvena de program? ......... int *p,*q; //1 p=new int(7); //2 q=p; //3 delete q; //4 *p=17; //5 ........... a. folosete o zona de memorie care a fost deja dealocat (//5) b. este necesara instruciunea "delete p" c. linia //3 din secvena este greita d. secvena este corecta 5. Unde este greeala in aceasta secvena de program? ......... int x=7; //1 int *y=&x; //2 delete y; //3 .......... a. in linia 1 b. in linia 2 c. in linia 3 d. secvena este corecta la compilare 6. Ce greeli apar in urmtoarea secvena de program? int x=7; //1 int *y; //2 delete y; //3 *y=7; //4 ......... a. in linia 1 b. in linia 2 c. in linia 3 d. in linia 4

213

7. Se da secvena: ....... int *p; &p=new int(7); ............ Ce se ntmpla la compilare? a. variabilei p i se atribuie valoarea 7; b. adresa memorata de p este 7; c. lui p i se atribuie adresa zonei de memorie alocate mai sus d. lui p i se atribuie adresa unei zone de memorie constituita din 7 locaii consecutive de ntreg (7*2)octeti 8. Se da secvena: ....... int **p; p=new int[2][3]; ............ Ce se ntmpla la compilare? a. se aloc o matrice cu 2 linii, 3 coloane; b. eroare de sintax; c. lui p i se atribuie adresa zonei de memorie alocate mai sus ; d. lui p i se atribuie adresa unei zone de memorie constituita din 7 locaii consecutive de ntreg (7*2*3) octeti. 9. Se da secvena: ....... int **p; int tab [2][3] = { 1, 2, 3}; p = tab ; ............ delete p ; Ce se ntmpla la compilare? a. lui p i se atribuie adresa zonei de memorie la care este alocat tab ; b. eroare de sintax produs de atribuire (p este pointer de int, iar tab este pointer de 3 int); c. eroare de sintax produs de faptul c o matrice nu se poate declara cu iniializare ; d. eroare de sintax produs de numrul prea mic al valorilor de iniializare; e. eroare la execuie produs de folosirea operatorului delete fr a se face anterior alocare de memorie. 10. Se da secvena: int n, m; int ** mat; int i, j;

214

....... mat=new int*[n]; for(i=0 ; i<n ; i++) mat[i]=new int[m]; Ce se ntmpl la compilare? a. eroare de sintax pentru c nu se pot aloca tablouri de pointeri; b. se aloc memorie pentru o matrice cu n linii i m coloane; c. eroare de sintax pentru c nu se pot face alocri de memorie n secvene repetitive.

ntrebri. Exerciii. Probleme.

1. Se citesc de la tastatur elementele unui tablou unidimensional. S se nlocuiasc toate valorile negative cu valoarea 0. Se afieaz elementele tabloului. Tabloul este alocat dinamic cu o dimensiune citit de la tastatur. 2. Se citesc de la tastatur elementele a dou tablouri unidimensionale de aceeai dimensiune. Se calculeaz elementele unui al treilea tablou ca sum a elementelor de acelai index ale primelor dou i se afieaz. Dimensiunea este citit de la tastatur, iar tablourile sunt alocate dinamic. 3. Se citesc de la tastatur dou iruri de caractere. Se determin un al treilea ir prin concatenarea primelor dou i se afieaz. Pentru referirea elementelor se vor folosi operaii cu pointeri. 4. Se aloc o matrice ptratica a crei dimensiune este citit de la tastatur. Se citesc de la tastatur valori pentru elementele matricei. S se afieze diagonala principal i cea secundar. 5. Sa se ntocmeasca un program n care se aloc dinamic 3 matrice cu dimensiuni citite de la tastatur. Pentru dou dintre acestea se citesc valorile elementelor de la tastatur. Se calculeaz a treia matrice ca sum a primelor dou i se afieaz.

215

Unitatea de nvare U.12. FUNCII N C/C++

Cuprins Introducere .................................................................................................................. 216 Obiectivele unitii de nvare ................................................................................... 217 U12.1. Definiii de funcii ........................................................................................... 217 U12.2. Declaraii de funcii. Prototipuri. .................................................................... 218 U12.3. Transferul parametrilor ................................................................................... 218 U12.3.1. Transferul prin valoare. Conversii de tip. ......................................... 218 U12.3.2. Transferul prin adres ....................................................................... 219 U12.3.3. Transferul prin variabile referin ..................................................... 220 U12.4. Rezultatul unei funcii. Instruciunea return. .................................................. 222 U12.5. Funcii recursive .............................................................................................. 222 U12.6. Pointeri de funcii ............................................................................................ 223 Exemple ...................................................................................................................... 224 Rezumat ...................................................................................................................... 228 Test de autoevaluare ................................................................................................... 229 ntrebri, exerciii i probleme .................................................................................... 232

Introducere n limbajul C++ (similar cu limbajul C standard) programul este o colecie de module distincte numite funcii, structura general a programului fiind: <directive preprocesor> <declaraii globale> funcii Un program C++ conine obligatoriu o funcie numit main() i aceasta este apelat la lansarea n execuie a programului. Programul surs poate fi partiionat n mai multe fiiere grupate ntr-un proiect (se utilizeaz meniul Project din mediul de programare utilizat). Fiecare fiier conine declaraii globale i un set de funcii, dar numai unul conine funcia main(). n C++, ca i n C, se utilizeaz declaraii (prototipuri) i definiii de funcii.

216

De regul, se declar prototipurile de funcii n zona declaraiilor globale, urmnd ca apoi s se fac definiiile funciilor. Definiiile se pot regsi n diferite fiiere surs. Apelul unei funcii produce lansarea n execuie a funciei respective i se poate face doar dac, cel puin prototipul funciei a fost deja stabilit. O funcie reprezint un bloc de instruciuni care este desemnat printr-un nume, care poate prelua date de intrare prin parametrii i poate returna un rezultat.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Sintaxa de declarare i definire a funciilor; Posibiliti de transfer al datelor ntre funcii prin parametri (transfer prin valoare, prin adres, prin referin); Rezultatul unei funcii. Instruciunea return i posibiliti de transfer al datelor prin cele trei modaliti (transfer prin valoare, prin adres, prin referin); Definirea funciilor recursive; Declararea i folosirea pointerilor de funcii.

Durata medie de parcurgere a celei de a dousprezecea uniti de nvare este de 2 ore.

U12.1. Definiii de funcii Sintaxa definiiei unei funcii este: tip_rez nume_funcie (<lista_parametri>) { <declaraii locale> secven de instruciuni } unde: - tip_rez - este un tip oarecare de dat i reprezint tipul rezultatului returnat de funcie. Dac nu este specificat, implicit tipul rezultatului returnat este int. Pentru funciile care nu returneaz rezultat trebuie s se specifice tipul void.

217

- nume_functie - este un identificator. - lista_parametri - reprezint enumerarea declaraiilor parametrilor sub forma: tip_parametru nume_parametru, <tip_parametru nume_parametru> Tipul parametrului poate fi orice tip valid de date. Nu este admis definirea unei funcii n blocul altei funcii i nu sunt permise salturi cu instruciunea goto n afara funciei. Apelul funciei const din numele funciei urmat de lista de constante, variabile sau expresii asociate parametrilor ncadrat ntre paranteze (). Att la definirea, ct i la apelul funciilor, parantezele () urmeaz ntotdeauna numele funciilor, chiar dac acestea nu au parametri. Se folosete denumirea de parametri formali pentru identificatorii din lista de argumente din definiia funciei i parametri efectivi (constantele, variabilele, expresiile) din lista unui apel al funciei. Parametrii formali reprezint variabile locale care au domeniu funcia i timpul de via corespunde duratei de execuie a funciei, deci valorile lor se memoreaz n stiv sau n registrele procesorului.

U12.2. Declaraii de funcii. Prototipuri. Apelul unei funcii nu se poate face nainte de definiia ei. Sunt situaii n care nu este posibil acest lucru (n cazul funciilor care se apeleaz unele pe altele, sau al funciilor definite n alte fiiere surs). Pentru a oferi compilatorului posibilitatea de a verifica corectitudinea apelului unei funcii (numrul i tipurile parametrilor, tipul rezultatului, eventualele conversii care apar), se pot folosi declaraii fr definire, numite prototipuri. Sintaxa general a unui prototip este: <tip> nume_functie (<lista_parametri>); Lipsa lista_parametri este interpretat n C++ ca funcie fr parametri, deci cuvntul void nu este necesar, spre deosebire de C standard care nu consider funcia fr parametri, ci cu orice list de parametri i, ca urmare, nu verific parametrii efectivi la apelare. n declaraia funciei este suficient ca n lista_parametri s se specifice tipurile parametrilor, fr identificatorii lor. Dac ns se specific identificatorii, acetia trebuie s fie identici cu cei folosii n antetul definiiei funciei. Prototipul funciei trebuie s fie plasat nainte de orice apel al funciei.

218

U12.3. Transferul parametrilor U12.3.1. Transferul prin valoare. Conversii de tip. La apelul unei funcii, valoarea parametrilor efectivi este ncrcat n zona de memorie corespunztoare parametrilor formali. Acest procedeu se numete transfer prin valoare. Dac parametrul efectiv este o variabil, ea nu este afectat de nici o operaie asupra parametrului formal, ceea ce poate constitui o protecie util. Transferul de valoare este nsoit de eventuale conversii de tip realizate de compilator, implicite sau explicite dac se folosete operatorul cast. Conversia se realizeaz de la tipul parametrului efectiv ctre tipul parametrului formal. Se folosete ca exemplu definirea i apelul unei funcii care preia dou variabile i realizeaz inversarea valorilor acestora ntre ele. #include <stdio.h> void schimba(int , int ); void main() { int i, j; float p, q; scanf(%d%d, &i, &j); schimba(i, j); // lista de parametri este format din variabile int

// apelul funciei include ca parametri efectivi // variabilele i, j de tip int, deci nu este necesar // conversia lor; pe parcursul execuiei funciei // schimba() se aloc variabilele locale a, respectiv // b, care sunt iniializate cu valorile i, respectiv j. // Inversarea valorilor se produce asupra // variabilelor locale a i b, variabilele i i j ne fiind // afectate // apelul funciei include ca parametri efectivi variabile // de tip float, deci va avea loc o conversie degradant, // implicit, float->int, care ns nu afecteaz variabilele // p i q, ci conversia se face la iniializarea variabilelor a // i b; la finalul execuiei funciei se constat c p i q // rmn nemodificate

printf(\ni=%d, j=%d, i, j); scanf(%f%f, &p, &q); schimba(p, q);

printf(\ni=%f, j=%f, p, q); } void schimba(int a, int b) { int temp ; temp=a; a=b; b=temp; }

// inversarea valorilor a dou variabile se face prin // atribuiri succesive, folosind o variabil auxiliar, temp

219

U12.3.2. Transferul prin adres Pentru ca o funcie s poat modifica valoarea unei variabile folosit ca parametru efectiv, trebuie folosit un parametru formal de tip pointer, iar la apelul funciei s se foloseasc ca parametru efectiv adresa variabilei. Se folosete pentru exemplificare tot definirea i apelul unei funcii care preia dou variabile i realizeaz inversarea valorilor acestora, dar parametrii funciei vor fi pointeri. #include <stdio.h> void schimba(int *, int *); void main() { int i, j; scanf(%d%d, &i, &j); schimba(&i, &j); printf(\ni=%d, j=%d, i, j); } void schimba(int *a, int *b) { int temp ; temp=*a; *a=*b; *b=temp; } Parametri tablou constituie o excepie de la transferul parametrilor prin valoare, deoarece funcia primete ca parametru adresa tabloului. Acest lucru este motivat de faptul c, n general, tablourile conin o cantitate mare de date al cror transfer prin valoare ar avea ca efect o scdere a vitezei de execuie i cretere a memoriei necesare prin copierea valorilor ntr-o variabil local. De altfel, numele tabloului este echivalent cu adresa sa. n prototip i antetul funciei, parametrul tablou se specific n lista de parametri sub forma: tip nume_tablou[ ] sau tip *nume_tablou // lista de parametri este format din pointeri la int

// la apelul funciei, parametrii efectivi sunt adrese de // variabile

U12.3.3. Transferul prin variabile referin Folosirea parametrilor formali variabile referin este similar folosirii parametrilor formali pointeri, asigurnd posibilitatea de a modifica valorile parametrilor efectivi.

220

Utilizarea referinelor prezint avantajul c procesul de transfer prin referin este efectuat de compilator n mod transparent, scrierea funciei i apelul ei fiind simplificate. Dac tipul parametrului efectiv nu coincide cu cel al parametrului formal referin, compilatorul efectueaz o conversie, ca n cazul transferului prin valoare. Pentru realizarea conversiei se creeaz un obiect temporar de dimensiunea tipului referin, n care se nscrie valoarea convertit a parametrului efectiv, parametrul formal referin fiind asociat obiectului temporar. Se pierd astfel avantajele folosirii referinelor ca parametri formali. #include <stdio.h> void schimba(int &, int &); void main() { int i, j; float p, q; scanf(%d%d, &i, &j); schimba(i, j); // lista de parametri este format din referine de // variabile int

// apelul funciei include ca parametri efectivi // variabilele i, j de tip int, deci nu este necesar // conversia lor; pe parcursul execuiei funciei // schimba() ele sunt redenumite, a, respectiv b, // inversarea valorilor avnd efect asupra // variabilelor din apel, i i j // apelul funciei include ca parametri efectivi variabile // de tip float, deci va avea loc o conversie degradant, // implicit, float->int, care are ca urmare crearea de // variabile temporare; referinele care se creeaz sunt // pentru aceste variabile temporare, i nu pentru p i q; // inversarea valorilor are efect asupra variabilelor // temporare, astfel c, la ieirea din funcie, se va // constata faptul c valorile variabilelor p i q au rmas // nemodificate

printf(\ni=%d, j=%d, i, j); scanf(%f%f, &p, &q); schimba(p, q);

printf(\ni=%f, j=%f, p, q); } void schimba(int &a, int &b) { int temp ; temp=a; a=b; b=temp; }

Este util folosirea parametrilor formali referin i n situaia n care parametrul are dimensiune mare i crearea n stiv a unei copii a valorii are ca efect reducerea vitezei de 221

execuie i creterea semnificativ a stivei. n aceast situaie, dac nu se dorete modificarea parametrului efectiv, acesta poate fi protejat prin folosirea modificatorului const la declararea parametrului formal referin.

U12.4. Rezultatul unei funcii. Instruciunea return. Instruciunea return determin ncheierea execuiei unei funcii i revenirea n funcia apelant. Ea a fost prezentat n Unitatea de nvare nr. 8. Valoarea expresiei reprezint rezultatul ntors de funcie, deci trebuie s fie compatibil cu tipul indicat n prototip i definiie. Dac tipul funciei este void, instruciunea return este necesar doar dac se dorete revenirea din funcie nainte de execuia ntregii secvene de instruciuni care alctuiete funcia. Transferul rezultatului se poate face utiliznd toate cele trei metode: prin valoare, pointer sau referin. n cazul transferului prin pointer sau referin, obiectul a crui adres se ntoarce nu trebuie s fie un obiect automatic, deoarece acesta dispare odat cu terminarea execuiei funciei. n cazul returnrii prin referin, o asemenea situaie e semnalat de compilator ca eroare, n schimb, n cazul pointerilor nu este semnalat eroarea. Adresa de memorie returnat va corespunde unei zone de memorie care nu mai este alocat i pot aprea efecte neateptate.

U12.5. Funcii recursive O funcie este numit funcie recursiv dac ea se autoapeleaz, fie direct (n definiia ei se face apel la ea nsi), fie indirect (prin apelul altor funcii). Limbajele C/C++ dispun de mecanisme speciale care permit suspendarea execuiei unei funcii, salvarea datelor i reactivarea execuiei la momentul potrivit. Pentru fiecare apel al funciei, parametrii i variabilele automatice se memoreaz pe stiv, avnd valori distincte. Variabilele statice ocup tot timpul aceeai zon de memorie (figureaz ntr-un singur exemplar) i i pstreaz valoarea de la un apel la altul. Orice apel al unei funcii conduce la o revenire n funcia respectiv, n punctul urmtor instruciunii de apel. La revenirea dintr-o funcie, stiva este curat (stiva revine la starea dinaintea apelului). Un exemplu de funcie recursiv este funcia de calcul a factorialului (n!), definit astfel: fact(n)=1, dac n=0; fact(n)=n*fact(n-1), dac n>0; Este prezentat n continuare programul care implementeaz aceast funcie.

222

#include <stdio.h> #include <conio.h> #include <stdlib.h> double fact(int n) { if (n<0) // valorile negative sunt invalide { printf("\nParametru negativ !"); exit(2); } if (n==0) return 1; else return n*fact(n-1); } void main() { int nr; double f; printf("\nIntrodu un numar: "); scanf("%d",&nr); f=fact(nr); printf("\n %d ! = %.0lf",nr,f); getch(); }

Fig. 12.1. Exemplificarea apelului funciilor recursive

Se observ c n corpul funciei fact se apeleaz nsi funcia fact. Spre exemplu, dac se dorete calcularea valorii 4!, se apeleaz funcia: fact(4). n interiorul su se calculeaz expresia 4*fact(3). Apelul funciei fact(3) va calcula la rndul su 3*fact(2), fact(2) calculeaz 2*fact(1) i n fine, fact(1) calculeaz 1*fact(0). Valoarea 0 a parametrului funciei are ca efect ntreruperea recursivitii. O funcie recursiv poate fi realizat i iterativ. Modul de implementare trebuie ales n funcie de problem. Dei implementarea recursiv a unui algoritm permite o descriere clar i compact, recursivitatea nu conduce la economie de memorie i nici la execuia mai rapid a programelor. n general, se recomand utilizarea funciilor recursive n anumite tehnici de programare, cum ar fi unele metode de cutare (backtracking).

U12.6. Pointeri de funcii Limbajul C++, ca i limbajul C, permite operarea cu variabile pointer care conin adresa de nceput a codului executabil al unei funcii. Aceste variabile permit: transferul ca parametru al adresei funciei asociate; apelul funciei prin intermediul pointerului. 223

Declaraia cu sintaxa: tip_r(*p_fct)(<lista_tip_param>); declar p_fct ca pointer cu tipul funcie cu rezultatul tip_r i parametri lista_tip_param.

Observaii n C standard, lista tipurilor parametrilor poate lipsi i nu se fac verificri ale parametrilor, n timp ce n C++ lipsa listei parametrilor indic o funcie fr parametri.

# include <stdio.h> int fct(int, float); void main() { int (*p_f)(int, float) int i = 5, j; float r = 3.5; p_f = fct; j = p_f(i, r); printf(\nj = %d, j); } int fct(int a, float b) { printf(\na = %d, a); printf(\nb = %f, b); return ( a + (int)b ); } // prototip de funcie

// p_f, pointer de funcie // se atribuie adresa funciei fct pointerului p_f // se apeleaz funcia fct prin pointerul p_f

Exemple

/*************************************************************************** Exemplul 12.1. Se scrie un program n care se compar dou iruri de caractere (prin funcia test()) folosind dou criterii diferite de comparare exprimate prin funciile comp1() i respectiv comp2(). Criteriul de comparare este precizat prin apelul uneia din funciile de comparare, apel fcut prin intermediul unei variabile pointer de funcie. ***************************************************************************/ 224

#include<stdio.h> #include<conio.h> void test(char*, char *, int(*)(char*, char*)); int comp1(char *, char *); int comp2(char *, char *); void main() { char s1[80], s2[80]; int (*p)(char*, char*); p=comp1; puts("Introduceti primul sir"); gets(s1); puts("Introduceti al doilea sir"); gets(s2); test(s1, s2, p); getch(); p=comp2; test(s1, s2, p); getch(); } void test(char*a, char*b, int(*comp)(char*, char*)) { if(!(comp)(a, b)) printf("\ns1 egal cu s2"); else printf("\ns1 diferit de s2"); } int comp(char *s1, char *s2) { return(s1[0]-s2[0]); } int comp1(char *s1, char *s2) { int i=0, j=0; while( s1[i] ) i++; while( s2[j] ) j++; return ( i - j ); }

// funcia test() are un parametru // de tip pointer de funcie

// se declar pointerul p de funcii cu // prototipul : int functie (char *, char *) // variabilei pointer p i se atribuie ca // valoare adresa funciei comp1()

// compar irurile folosind funcia comp1() // variabilei pointer p i se atribuie ca // valoare adresa funciei comp2() // compar irurile folosind funcia comp2()

// funcia compar primele caractere ale // irurilor // funcia compar lungimile irurilor

225

/*************************************************************************** Exemplul 12.2. S se ntocmeasc un program n care se definesc urmtoarele funcii: - o functie de citire a elementelor unui tablou de ntregi; - o functie de afisare a elementelor unui tablou de ntregi; - o functie care returneaza maximul dintre elementele unui tablou de ntregi; - o functie de ordonare a elementelor unui tablou de ntregi. In functia main se declara un tablou de ntregi si se exemplifica folosirea funciilor definite. Tablourile au dimensiunea stabilit cu ajutorul unei constante definit cu directiva #define. ***************************************************************************/ #include<stdio.h> #include<conio.h> #define N 5 void citire(int t[]); void afisare(int t[]); int maxim(int t[]); void ordonare(int t[]); void main() { int tab[N]; citire(tab); printf("\nSe afiseaza valorile elementelor de tablou"); afisare(tab); printf("\nValoarea maxima este: %d", maxim(tab)); ordonare(tab); printf("\nSe afiseaza valorile elementelor de tablou"); afisare(tab); getch(); } void citire(int t[]) { int i; for (i=0;i<N;i++) { printf("\nelementul [%d]=", i+1); scanf("%d",&t[i]); } } void afisare(int t[]) { int i; for (i=0;i<N;i++) printf("\nelementul [%d]= %d", i+1, t[i]); } int maxim(int t[]) 226 // constanta folosita pentru a stabili dimensiunea tablourilor

{ int i, max=t[0]; for (i=1;i<N;i++) if(max<t[i]) max=t[i]; return max; } void ordonare(int t[]) // se folosete algoritmul "bubble sort" { int i, k, aux; do { k=0; for(i=0;i<N-1;i++) if(t[i]>t[i+1]) { aux=t[i]; t[i]=t[i+1]; t[i+1]=aux; k=1; } } while(k!=0); }

Rezumat n limbajele C/C++ programul este o colecie de module distincte numite funcii. Un program C++ conine obligatoriu o funcie numit main() i aceasta este apelat la lansarea n execuie a programului. n C/C++ se utilizeaz declaraii (prototipuri) i definiii de funcii. Nu este admis definirea unei funcii n blocul altei funcii i nu sunt permise salturi cu instruciunea goto n afara funciei. Apelul funciei const din numele funciei urmat, ntre paranteze (), de lista parametrilor efectivi (constante, variabile sau expresii) asociai parametrilor formali. Parametrii formali reprezint variabile locale care au domeniu funcia i timpul de via corespunde duratei de execuie a funciei. Transferul datelor prin parametri sau ca valoare returnat din funcie se poate face prin valoare, adres sau referin. Transferul de valori este nsoit de eventuale conversii de tip realizate de 227

compilator, implicite sau explicite dac se folosete operatorul cast. Folosirea parametrilor formali pointeri i referin se folosesc n situaia n care parametrul are dimensiune mare i crearea n stiv a unei copii a valorii are ca efect reducerea vitezei de execuie i creterea semnificativ a stivei sau dac se dorete modificarea prin funcie a unor variabile care au ca domeniu funcia apelant. La returnarea prin pointer sau referin, trebuie avut n vedere ca obiectul a crui adres se ntoarce s nu fie un obiect automatic, deoarece acesta dispare odat cu terminarea execuiei funciei. Limbajele C/C++ permit utilizarea funciilor recursive (funcii care se autoapeleaz). Limbajele C/C++ permit operarea cu variabile pointer de funcii (conin adresa de nceput a codului executabil al unei funcii). Aceste variabile permit transferul ca parametru al adresei funciei asociate i apelul funciei prin intermediul pointerului.

Test de autoevaluare

1. Linia de program C: float cub(float a); a. reprezint antetul unei funcii b. poate fi nlocuita cu: float cub(float); c. genereaz eroare de sintaxa d. reprezint prototipul unei funcii e. nici o propoziie din cele de mai sus nu este adevrata 2. Functia care are prototipul: f(int a, float x); a. are 2 parametrii: un ntreg si un real b. ntoarce un rezultat ntreg c. nu ntoarce nici un rezultat d. prototipul de mai sus va genera o eroare de sintaxa 3. Consideram ca avem functia: int f (int number, int n) { int count, result; for(count=1 , result=1; count<=n ; count++) result*=number; return result; } 228

va returna, in urma apelului f(3, 2), valoarea: a. 1 b. 3 c. 9 d. 6 4. Programul: #include <stdio.h> #include <conio.h> void f(char*s) { if (!s[0]) return; f(s+1); putch(*s); } void main() { f("abcde"); } a. va produce o eroare de sintaxa b. va produce afisarea: edcba c. va produce afisarea: a d. definete o funcie recursiv e. nu va produce nici o afiare 5. Programul: #include <stdio.h> int f(char*s) { int i; for(i=0 ; s[i] ; i++); return i; } void main() { printf(\n%d, f(abcd)); } a. va produce o eroare de sintax b. afieaz culoarea 4 c. afisarea sirul: abcd d. afisarea unui rezultat 0 6. Programul: #include<stdio.h> int f(unsigned char); void main() { printf("%#x\n", f(0x33)); } int f(unsigned char c) { char mask=255; return (mask&&c); } va produce: a. o eroare de sintaxa

229

b. afisarea 0xff c. afisarea 0x1 d. afisarea 0x33 e. nici una din situaiile de mai sus 7. Programul: #include<stdio.h> int f(unsigned char); void main() { printf("%#x\n", f(0x33)); } int f(unsigned char c) { char mask=255; return (mask||c); } va produce: a. o eroare de sintaxa b. afisarea 0x1 c. afisarea 0xff d. afisarea 0x33 e. afisarea 0x00 8. Se considera functia in limbaj C: int functie(char *sir1, char *sir2) { for( ; *sir1==*sir2 ; sir1++, sir2++) if(!(*sir1)) return 1; return 0; } Ce realizeaz functia? a. compara cele doua iruri (sir1 si sir2) si returneaza 1 in caz de b. copiaza sir2 in sir1 c. copiaza sir1 in sir2 d. nimic deoarece conine erori identitate 9. Se considera functia in limbaj C: int functie(char sir1[],char sir2[]) { int i; for(i=0 ; sir2[i] ; i++) sir1[i] = sir2[i]; sir1[++i] = '\0'; return i; } Ce realizeaz functia? a. nimic deoarece conine erori b. copiaza sir1 in sir2 c. copiaza sir2 in sir1 d. returneaza numarul de caractere coninute in sir2, inclusiv 0 final

230

10. Se considera functia in limbaj C: void functie(char* sir1, char* sir2) { while(*sir1++ = *sir2++); } Ce realizeaz functia? a. nimic deoarece instruciunea while este greita b. copiaza sir1 in sir2 c. copiaza sir2 in sir1 d. compara irurile sir1 si sir2

ntrebri. Exerciii. Probleme.

1. Sa se scrie un program in care se defineste o functie care preia ca parametru un ntreg. Functia returneaza 1 daca numarul este prim, sau 0, daca numarul nu este prim. int prim(unsigned); In functia main() se citesc doua valori pentru a i b care reprezint capetele unui interval [a , b]. S se afieze toate valorile prime din intervalul dat. 2. S se ntocmeasc un program n care se definesc urmtoarele funcii: a. O funcie care copiaz coninutul unui ir de caractere n alt ir; b. O funcie care compar dou iruri de caractere; c. O funcie care concateneaz dou iruri. n funcia main() se exemplific folosirea acestor funcii. Not: Nu se folosesc funciile din fiierul string.h !

3. Sa se rescrie programul din exemplul 12.2., funciile fiind definite pentru tablouri alocate dinamic, dimensiunea acestora fiind citit de la tastatur la execuia programului.

231

Unitatea de nvare U.13. TIPURI DE DATE DEFINITE DE UTILIZATOR

Cuprins Introducere .................................................................................................................. 233 Obiectivele unitii de nvare ................................................................................... 234 U13.1. Enumerarea .................................................................................................... 234 U13.2. Structuri de date .............................................................................................. 235 U13.3. Cmpuri de bii................................................................................................ 242 U13.4. Uniuni.............................................................................................................. 240 Exemple ...................................................................................................................... 244 Rezumat ...................................................................................................................... 248 Test de autoevaluare ................................................................................................... 249 ntrebri, exerciii i probleme .................................................................................... 252

Introducere Reprezentarea informaia prelucrat de un program, reprezentat doar folosind tipurile predefinite i cele derivate, poate fi destul de dificil atunci cnd datele sunt complexe i trebuie structurate dup diferite criterii. Programatorul poate s-i defineasc propriile tipuri de date care s rspund ct mai eficient cerinelor aplicaiei. Limbajele C/C++, ofer urmtoarele posibiliti de definire de noi tipuri de date: declaraia typedef permite redenumirea tipurilor de date; prin aceasta crete lizibilitatea programului; enumerarea permite denumirea unui tip de date asociat cu tipul int simultan cu definirea unei liste de constante; structura definete colecii de date de diferite tipuri referite printr-un singur nume; cmpuri de bii reprezint membri ai unei structuri care nu sunt alocai la nivel de octet, ci alocai la nivel de bit; uniunea definete colecii de date de tipuri diferite care folosesc n comun o zon de memorie. Limbajul C++ ofer n plus fa de C posibilitatea definirii de clase, acestea

232

fiind tipuri de date care respect principiile programrii orientate pe obiecte.

Obiectivele unitii de nvare Dup parcurgerea acestei uniti de nvare trebuie s tii: Declararea de tipuri de date prin enumerare i utilizarea constantelor astfel definite; Declararea structurilor de date i manevrarea obiectelor de acest tip; Utilizarea cmpurilor de bii; Declararea uniunilor i manevrarea obiectelor de acest tip.

Durata medie de parcurgere a celei de a treisprezecea uniti de nvare este de 2 ore.

U13.1. Enumerarea Tipul enumerare const dintr-un ansamblu de constante ntregi, fiecare asociat unui identificator. Sintaxa declaraiei este: enum <id_tip_enum> {id_elem<=const>,} <lista_id_var>; unde: - id_tip_enum = nume tip enumerare ; - id_elem = nume element; - const = constant de iniializare a elementului. id_tip_enum reprezint un nume de tip de date, putndu-se folosi similar cu orice tip de date predefinit, putndu-se declara variabile, pointeri, tablouri, etc. din acel tip. Dac declaraia nu specific constante pentru id_elem, valorile implice sunt 0 pentru primul element, iar pentru celelalte valoarea elementului precedent incrementat cu o unitate. Identificatorii elementelor trebuie s fie unici n domeniul lor (diferii de numele oricrei variabile, funcie sau tip declarat cu typedef). enum boolean {false, true}; sau typedef enum {false, true} boolean; // declaraia este echivalent declaraiei // anterioare // valoarea identificatorului false este 0, iar a lui // true este 1

233

De exemplu, se poate scrie secvena: # include <stdio.h> enum boolean {false, true}; void main() { boolean op1=false, op2; op2=true; printf(\n op1=%d\nop2=%d, op1, op2); } Tipul enumerare faciliteaz operarea cu variabile care pot lua un numr mic de valori ntregi, asociindu-se nume sugestive pentru fiecare valoare. Programul devine mai clar i mai uor de urmrit. // valoarea identificatorului false este 0, iar a lui // true este 1

U13.2. Structuri de date Structura este o colecie de date referite cu un nume comun. O declaraie de structur precizeaz identificatorii i tipurile elementelor componente i constituie o definiie a unui nou tip de date. Sintaxa declaraiei unui tip structur este: struct id_tip_struct { tip_elem1 id_elem1; tip_elem2 id_elem2; tip_elemN id_elemN; } lista_id_var_struct; unde: - struct = cuvnt cheie pentru declararea tipurilor structur; - id_tip_struct = numele tipului structur declarat; - tip_elemK = tipul elementului K, unde K=1N; - id_elemK = numele elementului K; - lista_id_var_struct = lista cu numele variabilelor de tipul declarat, id_ti_struct. Pot s lipseasc, fie numele structurii, fie lista variabilelor declarate, dar nu amndou. De regul se specific numele tipului structur definit, aceasta permind declaraii ulterioare de obiecte din acest tip. Elementele structurii se numesc generic membrii (cmpurile) structurii. Pentru fiecare membru se precizeaz tipul datei i numele. Tipurile membrilor pot fi oarecare, mai puin

234

tipul structur care se definete, dar pot fi de tip pointer la structura respectiv. De exemplu, se poate defini urmtorul tip de date: struct ex_stru { int m1; char m2; float m3; }; O variabil de tip ex_stru se declar : ex_stru var1; Variabila var1 se aloc n memorie ca n fig.13.1.
Adresa variabilei (&var1)

Adrese memorie ...

999 Byte

1000 m1

1001

1002 m2

1003

1004 m3

1005

1006

1007 Byte

...

var1

Fig.13.1. Alocarea n memorie unei variabile de tip ex_stru

Membrii unei structuri pot fi de orice tip, deci pot fi la rndul lor de tip structur, spre exemplu: struct data { unsigned int zi; unsigned int luna; unsigned int an; }; struct persoana { char nume[15]; char prenume[15]; data data_n; } pers1, pers2 ; // se declar tipul de date persoana ca structur cu 2 // membri ir de caractere i un membru de tip data // odat cu declaraia tipului de date persoana, se // declar dou obiecte din acest tip de date // se declar tipul de date data, ca structur cu 3 membri // de tip unsigned int

235

stud1

nume

prenume

data_n

Adrese memorie ... A N D R E I \0

S T A N \0

10 zi

10 luna

2000 an

nume[0]

prenume[0]

Fig.13.2. Alocarea n memorie a unei variabile de tip persoana

O variabil de tip persoana se aloc n memorie ca n fig.13.2. Se poate declara un tip structur folosind cuvntul cheie typedef, sintaxa fiind: typedef struct { tip_elem1 id_elem1; tip_elem2 id_elem2; tip_elemN id_elemN; } id_tip_struct; unde semnificaia denumirilor este identic cu cea anterioar. Se reia exemplul anterior, utiliznd typedef pentru declaraia structurilor: typedef struct { unsigned int zi; unsigned int luna; unsigned int an; } data; typedef struct { char nume[15]; char prenume[15]; data data_n; } persoana; n cazul folosirii declaraiei cu typedef nu se pot face simultan i declaraii de variabile de tipul structurii. Acestea vor putea fi folosite ulterior. Declaraia unei variabile de tip structur se poate face cu iniializare prin enumerarea valorilor membrilor n ordinea n care apar n declaraie. persoana pers= {Ionescu, Adrian, 10, 10, 1975}; // declararea unui obiect persoana // cu iniializare

236

Dac declaraia nu se face cu iniializare, membrii variabilelor iau valoare 0 dac declaraiile sunt globale sau statice, sau valori reziduale dac declaraiile sunt locale. Referirea unui membru al unei variabile de tip structur se face folosind operatorul de selecie (.) (punct), sub forma: nume_variabil . nume_cmp De exemplu, printf(\nNumele: %s, pers.nume); printf(\nPrenume: %s, pers.prenume); printf(\nData nasterii: %d.%d.%d, pers.data_n.zi, pers.data_n.luna, pers.data_n.an); Se pot declara pointeri la structuri care pot prelua adresa oricrei variabile de tipul structurii respective. persoana * p_pers; p_pers = &pers; // se declar un obiect pointer la persoana // atribuire de valoare pointerului

Alocarea dinamic de memorie se poate face i pentru obiecte de tip structur, folosind att funciile specifice limbajului C, ct i operatorii specifici din C++. p_pers = (persoana*)malloc(sizeof(persoana)); sau: p_pers = (persoana*)malloc(dim*sizeof(persoana)); // alocarea unui tablou cu dim // elemente de tip persoana // alocarea unui element de tip persoana

Eliberarea de memorie se face folosindu-se funcia free. free(p_pers); Alocarea de memorie folosind operatorii specifice se face astfel: p_pers = new persoana[dim]; . delete [ ] p_pers; // alocarea unui tablou cu dim // elemente de tip persoana // dealocarea memoriei

Referirea unui membru al unei structuri indicate de un pointer se face folosind sintaxa: (* p_pers).nume; 237

sau folosind operatorul de selecie indirect (->) (sgeat). p_pers->nume; Exemple de folosire a cmpurilor unei structuri: puts("\nIntroduceti numele: "); scanf("%s", &p_pers->nume); puts("\nIntroduceti prenumele: ") scanf("%s", &p_pers->prenume); puts("\nIntroduceti data nasterii: "); scanf("%d.%d.%d", &p_pers->data_n.zi, &p_pers->data_n.luna, &p_pers->data_n.an); Operatorul de atribuire admite ca operanzi variabile structur de acelai tip, efectund toate atribuirile membru cu membru. persoana p1={"Popescu", "George", 5, 12, 1982}, p2; p2=p1; // p1 se declar cu // iniializare, p2 fr iniializare // prin atribuire, p2 preia, membru // cu membru datele din p1

printf("\nNumele:%s", p2.nume); printf("\nPrenume:%s", p2.prenume); printf("\nData nasterii: %d.%d.%d", p2.data_n.zi, p2.data_n.luna, p2.data_n.an);

Pot fi definite funcii care s realizeze transfer de informaie prin variabile de tip structur. Transferul unui parametru de tip structur se poate face att prin valoare, ct i prin adres sau variabile referin. Parametrii formali i cei efectivi trebuie s fie de acelai tip. Se consider spre exemplu o structur definit pentru a reprezenta numere complexe prin valorile pentru partea real i cea imaginar: struct complex { int re, im;} ; Pentru acest tip de date se defini funcii care transfer obiecte n diferite moduri. Spre exemplu se poate defini o funcie care afieaz informaia coninut ntr-o astfel de dat: void afisare(complex c) // funcie cu parametru de tip complex se { // face transfer prin valoare printf("\n\t%d + i * %d\n", c.re, c.im); } Definirea unei funcii care citete de la tastatur valori pentru o variabil complex se poate defini:

238

complex citire( ) { complex c; printf("\nre="); scanf("%d", &c.re); printf("\nim="); scanf("%d", &c.im); return c; } sau: void citire(complex * c) { printf("\nre="); scanf("%d", &c->re); printf("\nim="); scanf("%d", &c->im); }

// funcie care returneaz o dat de tip complex-

// funcie cu parametru pointer de complex// transfer prin adres

U13.3. Cmpuri de bii Cmpul de bii este un membru al unei structuri sau uniuni care are alocat un grup de bii n interiorul unui cuvnt de memorie. Declaraia unei structuri cu membrii cmpuri de bii se face sub forma: struct id_tip_struct { tip_elem1 id_elem1 : lungime; tip_elem2 id_elem2 : lungime; tip_elemN id_elemN : lungime; } lista_id_var_struct; unde lungime reprezint numrul de bii utilizai pentru reprezentarea n memorie a cmpului respectiv. Restriciile care se impun la declararea cmpurilor de bii sunt: tipul poate fi int signed sau unsigned; lungimea este o constant ntreag cu valoarea n domeniul 0-15; nu se poate evalua adresa cmpului, deci nu se poate folosi operatorul & pentru acel cmp, deci nu se pot folosi pointeri pentru aceste cmpuri; nu se pot folosi tablouri de cmpuri de bii. De exemplu, se consider declaraia: 239

struct ex_bit { unsigned m1 : 1; unsigned m2 : 4; unsigned m3 : 1; unsigned m4 : 10; }; Dac se declar o variabil: ex_bit variabila_mea; ea, va fi alocat n memorie ca n fig. 13.3.

Adrese memorie ...

999 Byte

1000 Byte

1001 Byte

1002 Byte

1003 Byte

1004 Byte

1005 Byte

1006 Byte

...

16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 m4 m3 variabila_mea
Fig.13.3. Alocarea n memorie a unei variabile de tip ex_bit

m2

m1

Aa cum se tie, unitatea de memorie cea mai mic direct adresabil este octetul. Folosirea cmpurilor de bii permite accesul la nivel de bit, ceea ce reprezint o facilitate oferit de C/C++. Un alt avantaj oferit de folosirea cmpurilor de bii este economia de memorie care se poate face. Dac unele date iau valori n domenii de valori restrnse, reprezentarea lor se poate face pe un numr de bii care permite reprezentarea acelor valori. Dac se folosesc n bii, se pot reprezenta 2n valori. De exemplu, dac se dorete folosirea datelor calendaristice, valoarea zilei este cuprins n intervalul 1...31, deci sunt necesari 5 bii (25 = 32)., valoarea lunii se poate reprezenta pe 4 bii, iar pentru an am putea folosi 12 bii. O astfel de reprezentare va folosi 3 sau 4 octei, depinde de compilatorul folosit, deci mai puin dect dac declaraiile ar fi fcute fr folosirea cmpurilor de bii. Este posibil ca o parte din bii s nu fie folosii. Acest lucru nu genereaz erori. Referirea membrilor se face ca pentru orice structur, folosind operatorii de selecie direct sau indirect (punct sau sgeat).

240

O problem apare, de exemplu, la citirea de valori pentru astfel de date, pentru c, pentru aceti membri nu se poate folosi operatorul adres (&). #include <stdio.h> struct DATA { unsigned int zi :5; unsigned int luna :4; unsigned int an :12; };

// se declar membrul zi cu reprezentare pe 5 bii // se declar membrul luna cu reprezentare pe 4 bii // se declar membrul an cu reprezentare pe 12 bii

void main() { DATA data_n; unsigned int aux1, aux2, aux3;

// se declar un obiect de tip DATE

puts(Introduceti data :) scanf(%2d.%2d.%4d, &aux1, &aux2, &aux3); // este necesar utilizarea unor // variabile auxiliare pentru citirea // valorilor, deoarece pentru // cmpurile de bii nu se poate // face referire la adres data_n.zi=aux1; data_n.luna=aux2; data_n.an=aux3; .... } Dac se dorete determinarea dimensiunii n octei a memoriei folosit pentru reprezentarea acestor date, se poate folosi operatorul sizeof(). printf(data_n ocupa %d octeti, sizeof(data_n));

U13.4. Uniuni Uniunea permite utilizarea n comun a unei zone de memorie de ctre mai multe obiecte de tipuri diferite. Sintaxa de declarare a unei uniuni este similar declaraiei unei structuri: union id_tip_uniune { tip_elem1 id_elem1; tip_elem2 id_elem2; tip_elemN id_elemN; } lista_id_var_uniune; 241

sau typedef union { tip_elem1 id_elem1; tip_elem2 id_elem2; tip_elemN id_elemN; } id_tip_uniune; Spaiul alocat n memorie corespunde tipului de dimensiune maxim, membrii uniunii utiliznd n comun zona de memorie. Se consider declaraia: union exemplu { char c; int i; float f; }; O variabil de tipul exemplu declarat, var1, se reprezint n memorie ca n fig.13.4. Reprezentarea se face pe 4 octei, adic numrul de octei necesar cmpului cu reprezentare n domeniul cel mai larg. Cmpul cel mai mare este cmpul f. exemplu var1;
Adresa variabil ( &var1) var1 999 1000 c i f 1001 1002 1003 1004 1005 1006 1007

Adrese memorie ...

...

Fig.13.4. Reprezentarea n memorie a unei uniuni

La un moment se folosete un membru al uniunii. Modificarea unui membru va produce modificri i asupra celorlali. Se consider urmtoarea aplicaie:

242

#include <stdio.h> struct octet { unsigned int b0:1; unsigned int b1:1; unsigned int b2:1; unsigned int b3:1; unsigned int b4:1; unsigned int b5:1; unsigned int b6:1; unsigned int b7:1; }; union intreg { char val; octet bit; }; void main () { intreg i; i.val=22; // se afieaz fiecare bit al uniunii separat folosindu-se cmpul i.bit: printf("\n0x%x se reprezinta in binar: %d%d%d%d%d%d%d%d", i.val, i.bit.b7, i.bit.b6, i.bit.b5, i.bit.b4, i.bit.b3, i.bit.b2, i.bit.b1, i.bit.b0); } Programul afieaz: 0x16 se reprezinta in binar 00010110 Programul realizeaz afiarea n format binar a unei valori reprezentat pe un octet, de tip char.

// se declar o structur care ocup un octet de memorie, // cu acces separat, prin membrii si, la fiecare bit n parte /

// se declar o uniune ce ocup un octet de memorie care poate // fi accesat ca i char prin membrul val, sau ca octet prin // membrul bit

Observaii Numrul de octei folosit n aceste aplicaii depinde de compilatorul folosit. De exemplu tipul int se reprezint fie pe 2 octei, fie 4.

243

Exemple

/*************************************************************************** Exemplu1 13.1. Se scrie un program n care se declar o structur pentru reprezentarea punctelor n plan prin coordonatele sale. Se exemplific folosirea variabilelor de tip structura, tablouri si a pointerilor de structuri. ***************************************************************************/ #include <stdio.h> #include <conio.h> #include <math.h> #define N 4 struct punct { int x, y;}; void main() { punct p1, p2; punct pct[N]; punct *pp; int i; double dist; printf("Introduceti coordonate pentru p1:"); printf("\np1.x="); scanf("%d", &p1.x); printf("p1.y="); scanf("%d", &p1.y); printf("Introduceti coordonate pentru p2:"); printf("\np2.x="); scanf("%d", &p2.x); printf("p2.y="); scanf("%d", &p2.y); // se calculeaza distana dintre dou puncte dist=sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); printf("\nDistanta dintre p1 si p2 este: %.2f\n", dist); getch(); // structur pentru reprezentarea punctelor n plan prin // coordonatele sale

// se declar variabile de tip punct // se declar un tablou cu elemente de tip punct // se declar un pointer la tipul punct

244

printf("Introduceti coordonate pentru cele 10 puncte:\n"); for(i=0 ; i<N ; i++) { printf("\npct[%d]:", i); printf("\nx="); scanf("%d", &pct[i].x); printf("y="); scanf("%d", &pct[i].y); } printf("Coordonatele sunt:\n"); for(i=0 ; i<N ; i++) printf("punctul %d - <%d , %d> \n", i, pct[i].x, pct[i].y); // se face referire la elementele tabloului cu elemente de tip punct in mod indirect, prin // pointerul pp pp=pct; printf("Coordonatele sunt:\n"); for(i=0;i<N;i++) printf("punctul %d - <%d , %d>\n", i, (pp+i)->x, (pp+i)->y); getch(); } /*************************************************************************** Exemplu1 13.2. Se scrie un program n care se declar o structur pentru reprezentarea numerelor complexe. Se definesc urmtoarele funcii: o funcie care citete de la tastatur valori pentru o dat de tip complex, o funcie care afieaz o dat de tip complex, o funcie care calculeaz i returneaz suma a dou numere complexe. Valoarea returnat de funcie este tot de tip complex. ***************************************************************************/ #include <stdio.h> struct complex { int re, im;} ; // declaraia tipului de dat complex

void afisare(complex c) // funcie cu parametru de tip complex se { // face transfer prin valoare printf("\n\t%d + i * %d\n", c.re, c.im); } void citire(complex * c) { printf("\nre="); scanf("%d", &c->re); printf("\nim="); scanf("%d", &c->im); // funcie cu parametru pointer de complex// transfer prin adres

245

} complex suma(complex & a, complex & b) { complex c; c.re=a.re+b.re; c.im=a.im+b.im; return c; } void main() { complex c1, c2, c3; printf("\nSe citesc valori pentru c1:"); citire(&c1); printf("\nSe citesc valori pentru c2:"); citire(&c2); printf("\nNumerele complexe sunt:"); afisare(c1); afisare(c2); c3=suma(c1, c2); printf("\nSuma numerelor complexe este:"); afisare(c3); } /*************************************************************************** Exemplu1 13.3. Se scrie un program prin care se citete o valoare ntreag de la tastatur. Se afieaz n binar valoarea citit. Se vor folosi cmpuri de bii i uniuni. (Se consider tipul int cu reprezentare pe 4 octei). ***************************************************************************/ #include <stdio.h> struct dword { unsigned b0:1; unsigned b1:1; unsigned b2:1; unsigned b3:1; unsigned b4:1; unsigned b5:1; unsigned b6:1; unsigned b7:1; unsigned b8:1; // structura permite accesul la fiecare bit // care intr n alctuirea unei reprezentri // pe 4 octei (32 bii). // funcia de afiare preia ca parametri // variabile de tip complex, transferul se // face prin valoare // funcia preia parametrii prin // referin i ntoarce o valoare // care e atribuit unei variabile // funcie care preia prin referin date de // tip complex i returneaz o dat de tip // complex

// declaraie de variabile complex // funcia preia adresa unei variabile de // tip complex

246

unsigned b9:1; unsigned b10:1; unsigned b11:1; unsigned b12:1; unsigned b13:1; unsigned b14:1; unsigned b15:1; unsigned b16:1; unsigned b17:1; unsigned b18:1; unsigned b19:1; unsigned b20:1; unsigned b21:1; unsigned b22:1; unsigned b23:1; unsigned b24:1; unsigned b25:1; unsigned b26:1; unsigned b27:1; unsigned b28:1; unsigned b29:1; unsigned b30:1; unsigned b31:1; }; union intreg { }; void print_dword( dword b) // afiarea binar a obiectului { printf("%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d", b.b31, b.b30, b.b29, b.b28, b.b27, b.b26, b.b25, b.b24, b.b23, b.b22, b.b21, b.b20, b.b19, b.b18, b.b17, b.b16, b.b15, b.b14, b.b13, b.b12, b.b11, b.b10, b.b9, b.b8, b.b7, b.b6, b.b5, b.b4, b.b3, b.b2, b.b1, b.b0); } void main() { intreg var1; printf("Introdu un intreg = "); scanf("%d", &var1.a); printf("\n %d se reprezinta in binar:", var1.d); print_dword(var1.d); } int a; dword d; // prin cei doi membrii ai uniunii, aceeai zon de // memorie poate fi interpretat fie ca int, fie la // nivel de bii prin membrul dword

247

Rezumat

Programatorul poate s-i defineasc propriile tipuri de date care s rspund ct mai eficient cerinelor aplicaiei. Se pot defini noi tipuri de date prin redenumire folosind cuvntul cheie typedef, definirea unui tip de date nsoit de o list de constante folosind cuvntul cheie enum, definirea unei colecii de date de diferite tipuri prin cuvintele cheie struct sau union. Tipul enumerare const dintr-un ansamblu de constante ntregi, fiecare asociat unui identificator. Structura este o colecie de date referite cu un nume comun. O declaraie de structur precizeaz identificatorii i tipurile elementelor componente i constituie o definiie a unui nou tip de date. Pentru elementele structurii, numite membrii sau cmpuri, se precizeaz tipul datei i numele. Tipurile membrilor pot fi oarecare, mai puin tipul structur care se definete, dar pot fi de tip pointer la structura respectiv. Membrii unei structuri pot fi alocai la nivel de bit, folosind cmpuri de bii. Pentru acetia nu se poate evalua adresa cmpului, deci nu se poate folosi operatorul & i nu se pot folosi pointeri pentru aceste cmpuri. Uniunea definete colecii de date de tipuri diferite care folosesc n comun o zon de memorie. Pentru referirea membrilor structurilor i uniunilor se folosesc operatorii de selecie (.) (punct) n referirea direct sau operatorul de selecie indirect (->) (sgeat) n referirea prin pointeri.

Test de autoevaluare

1. Care din afirmaiile de mai jos sunt adevrate: a. membrii unei structuri pot fi de orice tip b. membrii unei structuri se declara ca orice variabila specificandu-se numele si tipul cmpului c. membrii unei structuri pot fi de orice tip, chiar si de tip structura, dar nu de tipul curent declarat

248

2. Se da secvena urmtoare: void main (void) { struct pers { char nume[20]; pers adr; long tel; float nr_matricol; }; pers x; x.nume[10]="Popescu"; printf("%s", x.nume[10]); } care afiseaza: a. Popescu b. eroare in declararea structurii c. eroare, deoarece sirul a fost initializat greit 3. Care din afirmaiile de mai jos sunt corecte: a. o dat de tip strutura nu poate fi referita att ca right_value cat si ca left_value b. operaiile care pot fi fcute cu date de tip structur sunt copierea si atribuirea c. date de tip structur nu pot fi comparate folosind operatori relaionali 4. Fie secvena: struct ex{ char *sir; int i; }; struct ex *pt; ++pt->i; Aceasta secvena are ca efect: a. incrementarea pointerului pt b. incrementarea cmpului i al structurii c. incrementarea pointerului inaintea accesrii, urmata de incrementarea lui i 5. Ce afiseaza secvena de program urmtoare: void main (void) { struct complex { float re; float im;}; complex z1,z2,*pz; z2.re = 1.53; z2.im = 2.31; z1=z2; pz=&z1; printf("%f\t%f",z1.re,z1.im); } a. eroare, pentru ca unei date de tip structur nu i se poate atribui o alt dat de acelai tip. b. 1.530000 2.310000 c. eroare in declararea structurii

249

6. Este corecta referirea membrilor structurii struct ex{ int i; char str[20]; double d;}; struct ex s, *sp=&s; s.i = 3; sp.d = 1.23; a. da, deoarece i si d sunt membrii structurii b. nu, deoarece referirea membrilor structurii se face obligatoriu prin pointerul la structura c. nu, deoarece referirea cmpului d este incorecta 7. Fie secvena: struct complex { float re; float im;}; struct complex x,y,z; Aceasta declaraie rezerva spaiu de memorie de: a. 8 octeti b. 24 octeti c. 3 octeti 8. Ce va afisa secvena de program urmtoare: void main(void) { struct complex{ float re; float im;}; struct complex tab[10]={{1,2},{1,4},{1,5}}; float a,b; a=tab[0].re; b=tab[0].im; printf("%f\t%f", a, b); } a. eroare, datorita declararii incorecte a tabloului b. 1 2 c. 111 245 9. Ce efect produce secventa urmtoare: typedef struct { char nume[10]; char adr[20]; long tel;}pers; pers student; .... student.nume[0]='A'; a. eroare, nu se poate pune un caracter intr-o variabila de tip structura b. adresa cmpului nume este 'A' c. prima litera a cmpului nume este 'A'

250

10. Se considera secvena: void main(void) { struct candidat{ char nume[80]; float nota1,nota2;}; candidat *px; px=(candidat*)malloc(sizeof(candidat)); .....} Ce efect produce aceasta secvena: a. initializeaza structura candidat cu valoarea px; b. elibereaz zona de memorie rezervata la declararea structurii c. alocarea efectiva a memoriei, iar px va conine adresa de memorie rezervata 11. Se considera secvena: struct adr{ char nume[30], strada[20]; int nr,bl,ap; long cod; }adresa, lista[100];

main() { lista[10]=adresa; ...... } Ce efect produce aceasta secvena: a. copiaza toate valorile din variabila adresa in elementul de index 10 al tabloului de adrese lista[]; b. aloca aceeai zona de memorie att pentru structura adresa cat si pentru structura lista; c. initializeaza structura adresa cu elementul 10 din structura lista 12. Care din urmtoarele afirmaii sunt adevrate? a. structura este o colecie de date, neaprat de acelai fel, grupate mpreuna sub un singur nume in scopul unei utilizri convenabile b. structura este o colecie de date de tipuri diferite, grupate mpreuna sub un singur nume in scopul unei utilizri convenabile c. structurile sunt tipuri de date derivate d. structurile sunt tipuri de date fundamentale 13. Se considera declaratia: typedef struct{ char nume[20]; char adresa[50]; int virsta; } persoana; persoana student; Care din afirmaiile de mai jos sunt adevrate? a. student este o variabila de tip persoana, pentru care se rezerva memorie (74 de octeti) b. persoana este o variabila de tip structura, pentru care se rezerva memorie (74 de octeti) c. persoana este un nou tip de date, pentru care nu se rezerva memorie d. declaratia este greita

251

14. Care din afirmaiile de mai jos sunt adevrate? a. o structura poate fi transmisa ca argument unei funcii b. in limbajul C, nu se pot folosi pointeri la structuri c. un pointer la o structura poate fi transmis ca argument unei functii d. cmpurile unei structuri nu pot fi transmise ca argumente unei functii

ntrebri. Exerciii. Probleme.

1. S se rescrie exemplul nr. 13.1 n care se definete o funcie pentru citirea de la tastatur a unei date de tip punct, una pentru afiare i o a treia care calculeaz distana dintre dou puncte preluate ca parametri. Apelurile lor se vor folosi n funcia main. 2. S se scrie un program n care se definete o structur pentru reprezentarea unui triunghi prin lungimile laturilor sale. Se definete o funcie pentru citirea de la tastatur a unei date de tip triunghi, una pentru afiare i o a treia care calculeaz aria triunghiului. Apelurile lor se vor folosi n funcia main.

252

Unitatea de nvare U.14. EXEMPLE

Cuprins Introducere .................................................................................................................. 253 Obiectivele unitii de nvare ................................................................................... 253 Exemple ...................................................................................................................... 254

Introducere n primele 13 uniti de nvare au fost prezentate noiuni de baz referitoare la utilizarea unor limbaje de programare. Noiunile prezentate au vizat tipuri de date utilizate n reprezentarea datelor, care pot fi tipuri predefinite, ca de exemplu char, int, float, double, tipuri derivate, cum sunt pointerii, referinele i tablourile, sau cele definite de programator folosind structuri sau uniuni. De asemenea, au fost prezentai operatorii definii n C/C++ i instruciunile disponibile. Un aspect important care trebuie avut n vedere n construirea unui program este modularizarea acestuia prin utilizarea funciilor. n formarea unui programator este important formarea unui stil de programare, aplicarea unor tehnici de programare, aspecte care ns nu au constituit subiectul acestui curs dect n msura n care au fost necesare scrierii exemplelor prezentate. Pentru fixarea noiunilor, n prezenta unitate de nvare vor fi prezentate cteva exemple care ncearc s sublinieze o dat n plus modul de utilizare a noiunilor analizate pn la acest moment.

Obiectivele unitii de nvare Prin parcurgerea acestei uniti de nvare se exemplific utilizarea tuturor elementelor de baz ale limbajelor C/C++ prezentate n acest curs, astfel nct studentul s tie, la final, modul de transpunere a unor probleme din diverse domenii ntr-un program.

Durata medie de parcurgere a celei de a paisprezecea uniti de nvare este de 2 ore.

253

Exemple

/*************************************************************************** Exemplul 14.1. S se ntocmeasc un program n care se definete funcia de calcul a radicalului de ordin 2. Se va folosi calculul termenilor seriei Newton: nr ) X 0 = nr , x n = 1 / 2( x n 1 + x n 1
Limita seriei astfel definit este

nr , calculul termenilor se va finaliza n

momentul n care diferena a doi termeni alturai se ncadreaz n precizia propus ( x n x n 1 < ). De la tastatur se vor citi numrul pentru care se calculeaz radicalul i precizia de calcul. Observaie: Nu se va folosi funcia sqrt() definit n fiierul header math.h ***************************************************************************/ #include<conio.h> #include<stdio.h> double sqrt(double, double); // preia ca parametru numrul pentru care se calculeaz radicalul // i precizia de calcul; returneaz valoarea radicalului. double abs(double); // returneaz valoarea absolut a parametrului void main() { double nr, eps, rad; // se citete numrul pentru care se calculeaz radicalul do { puts("\nIntrodu numarul (valoare pozitiva):"); scanf("%lf", &nr); } while(nr<0); // valoarea citit trebuie s fie pozitiv // se citete precizia de calcul do { puts("\nIntrodu precizia de calcul (valoare cuprinsa in intervalul (0,0.1)):"); scanf("%lf", &eps); } while ((eps<=0)||(eps>0.01)) ); // valoarea citit trebuie s fie pozitiv // se calculeaz radicalul, folosind funcia definit rad=sqrt(nr,eps); printf("\nValoarea radicalului ptrentru n=%lf este: %lf", nr, rad); getch(); }

254

// definiia funciei de calcul al radicalului double sqrt(double n,double e) { double r, x; r=n; do { x=r; r=1./2 * (x + n/x); printf("\nval.intermediara:%.10lf",r); // se afieaz valorile termenilor calculai } while (abs(x-r)>e); return r; } // funcie care returneaz valoarea absolut a unei valori preluat ca parametru double abs(double a) { if (a>0) return a; return -a; }

/***************************************************************************

Exemplul 14.2. S se scrie un program in care se afiseaza tabla nmulirii de la 1 la 10 cu afisare in formatul:

***************************************************************************/ #include <stdio.h> #include <conio.h> void main(void) { int i, j; printf (" | "); for(i=1; i<=10 ; i++) printf("%5d", i);

//afisarea unor spatii goale // se afiseaza deinmultitul

255

printf("\n--------------------------------------------------------"); for(i=1 ; i<=10 ; i++) { printf("\n%3d | ", i); // se afiseaza inmultitorul for( j =1 ; j<=10 ; j++) // se afiseaza valorile produselor i*j printf("%5d", i*j); } printf("\n"); getch(); }

/***************************************************************************

Exemplul 14.3. S se rescrie exemplul 7.1. n care se rezolv ecuaia de gradul II: a x2 + b x + c = 0
Coeficienii a, b i c se citesc de la tastatur. Se va folosi schema logic din figura alturat.

***************************************************************************/ #include <stdio.h> #include <conio.h> #include <math.h>

256

void main() { float a, b, c, delta, x1, x2; printf("coeficientul lui x^2:"); scanf("%f", &a); printf("coeficientul lui x:"); scanf("%f", &b); printf("termenul liber:"); scanf("%f", &c); if (a==0) if (b==0) if (c==0) printf("Ecuatie nedeterminata !\n"); else printf("Ecuatie imposibila !\n"); else { printf("Ecuatie de grad I"); printf("\nSolutia este: x = %.2f !\n", -c/b); } else { delta= b*b - 4*a*c; if ( delta<0) { printf("radacini complexe\n"); printf("x1= %.2f + i* %.2f !\n", -b/(2*a), sqrt(-delta)/(2*a)); printf("x2= %.2f - i* %.2f !\n", -b/(2*a), sqrt(-delta)/(2*a)); } else if ( delta==0 ) { x1 = x2 = -b/(2*a); printf("Radacini reale si egale:\n"); printf("x1=x2=%.2f", x1 ); } else { printf("Radacini reale si distincte:"); x1 = (-b+sqrt(delta))/(2*a); x2 = (-b-sqrt(delta))/(2*a); printf("\nx1=%.2f\n", x1 ); printf("\nx2=%.2f\n", x2 ); } } getch(); }

257

/*************************************************************************** Exemplul 14.4. Sa se scrie un program in care se definesc urmtoarele funcii:


-

o functie de afiare a divizorilor unui ntreg, ntregul fiind preluat ca parametru; o funcie care returneaz c.m.m.d.c. a doi ntregi preluai ca parametri; o funcie care returneaz c.m.m.m.c. a doi ntregi preluai ca parametri.

n funcia main() se citesc doi ntregi de la tastatur, a si b. Se afiseaza un meniu prin care se permite alegerea intre urmtoarele opiuni:
-

afisarea divizorilor lui a afisarea divizorilor lui b afisarea c.m.m.d.c. pentru a si b afisarea c.m.m.m.c. pentru a si b ieirea din program

***************************************************************************/ #include<stdio.h> #include <conio.h> void af_div(int); int cmmdc (int, int); int cmmmc(int, int); void meniu(void); void main() { int nr1, nr2, optiune; do { printf("nr1 = "); scanf("%d", &nr1); } while (nr1<=1); do { printf("nr2 = "); scanf("%d", &nr2); } while (nr2<=2); // se verifica daca valoarea citita este >1 // se verifica daca valoarea citita este >1 // functie de afisare a divizorilor unui numr // calcul cmmdc a doi ntregi // calculul cmmmc a doi ntregi // functie de afisare a meniului

// secvena de afiare a meniului se va executa in mod repetat, pn la alegerea opiunii // desemnat prin valoarea 5 do { meniu(); // apelul functiei de afisare a meniului 258

printf("\n\nIntrodu optiunea: "); scanf("%d", &optiune); switch(optiune) { case 1: printf("\nDivizorii numarului %d sunt: ", nr1); af_div(nr1); getch(); break; case 2: printf("\nDivizorii numarului %d sunt: ", nr2); af_div(nr2); getch(); break; case 3: printf("\nCMMDC = %d ", cmmdc(nr1, nr2) ); getch(); break; case 4: printf("\nCMMMC = %d ", cmmmc(nr1, nr2) ); getch(); break; case 5: printf("\nSfarsit de program !\n"); getch(); break; default: printf("\nOptiunea dumneavoastra este gresita !"); getch(); } } while(optiune != 5); } void af_div(int nr) // se afieaz toi divizorii ncepnd cu valoarea 2 { int i; for(i=2; i<=nr ; i++) if (!(nr%i)) printf("%d ", i); } int cmmdc(int n1, int n2) { // calcul cmmdc se face folosind algoritmul lui // Euclid descris n figura alturat while(n1!=n2) { if (n1>n2) n1=n1-n2; else n2=n2-n1; } return n1; }

259

int cmmmc(int n1,int n2) { return n1*n2/cmmdc_1(n1,n2); } void meniu(void) { printf("\n\n--------------------------- MENIU ------------------------------\n\n"); printf("\n1. Afisarea divizorilor primului intreg introdus."); printf("\n2. Afisarea divizorilor celui de al doilea intreg introdus."); printf("\n3. Afisarea cmmdc pentru cei doi intregi introdusi(varianta 1)."); printf("\n4. Afisarea cmmmc pentru cei doi intregi."); printf("\n5. Iesire din program."); }

/***************************************************************************

Exemplul 14.5. Forma generala a unui polinom este: a n x n + a n 1 x n 1 + ... + a 1 x + a 0


Sa se ntocmeasca un program pentru reprezentarea polinoamelor prin gard si valorile coeficienilor. Coeficienii se vor memora n tablouri unidimensionale. Se citesc de la tastatura datele pentru dou polinoame (grad si coeficient) Se afieaz cele dou polinoame. Se determin un al treilea polinom ca sum a primelor dou i se afieaz. ***************************************************************************/ #include <stdio.h> int citire_pol(float *coef) { int grad; float aux; do { // functia citeste de la tastatura gradul, memorat in // variabila grad si coeficienii memorai in tabloul coef // si returneaza valoarea gradului polinomului // se folosete ca variabil intermediar la citirea coeficienilor // de tip float ai polinomului

printf("\nGradul polinomului= "); scanf("%d", &grad);

} while(grad<0 || grad >= 19); // se verific valoarea gradului; dimensiunea tablourilor // de coeficieni este 20, deci gradul trebuie s fie <=19 for(int i=0 ; i<=grad ; i++) { printf("Coeficientul monomului de grad %d = ", i); scanf("%f", &aux); coef[i] = aux; } return grad; }

260

void afisare_pol(float coef[], int grad) { int i; for(i=grad ; i>0 ; i--) // se face afiarea n ordine descresctoare a gradelor // monoamelor { if(coef[i]!=0) printf("%.2f*X^%d ", coef[i], i); if(coef[i-1]>0) printf("+"); } if(coef[0]!=0) // monomul de grad 0 se afieaz distinct printf("%.2f\n", coef[0]); } int suma_pol(float*coef1, int gr1, float*coef2, int gr2, float*coef) //functia returneaza valoarea gradului polinomului suma { int gr3; int i; if(gr1>gr2) // polinoamele nsumate pot fi de grade diferite { gr3=gr1; for(i=0;i<=gr1;i++) coef3[i]=coef1[i]; for(i=0;i<=gr2;i++) coef3[i]=coef3[i]+coef2[i]; } else { gr3=gr2; for(i=0;i<=gr2;i++) coef3[i]=coef2[i]; for(i=0;i<=gr1;i++) coef3[i]=coef3[i]+coef1[i]; } return gr3; // se returneaz gradul polinomului rezultat } void main() { float p1[20], p2[20], p3[20]; int gr1, gr2, gr3;

// tablourile pentru memorarea coeficientilor // a trei polinoame // variabile pentru memorarea gradelor a // 3 polinoame (<=19)

printf("Introduceti date pentru primul polinom:\n"); gr1 = citire_pol(p1); printf("\nPolinomul este:\n"); afisare_pol(p1, gr1); printf("\nIntroduceti date pentru al doilea polinom:\n");

261

gr2 = citire_pol(p2); printf("\nPolinomul este:\n"); afisare_pol(p2, gr2); gr3 = suma_pol(p1, gr1, p2, gr2, p3); printf("\nPolinomul suma este:\n"); afisare_pol(p3, gr3); }

Observaii
Funcia de determinare a cmmdc poate fi scris folosind i ali algoritmi. Sunt prezentate n continuare dou versiuni: a. Se parcurg, n ordine cresctoare toate valorile cuprinse n intervalul [2, min(n1, n2)], verificndu-se dac reprezint divizor comun pentru n1 i n2. Variabila div va pstra valoarea maxim dintre divizorii comuni ai celor dou numere. int cmmdc (int n1, int n2) { int min, div, i; min = n1<n2 ? n1 : n2; // minimul dintre valorile n1 si n2 for(i=2; i<=min ; i++) { if(!(n1%i)&&!(n2%i)) div=i; } return div; } b. Se parcurg, n ordine descresctoare valorile cuprinse n intervalul [ min(n1, n2), 2], verificndu-se dac reprezint divizor comun pentru n1 i n2. Prima valoare determinat ca divizor comun pentru n1 i n2 va reprezenta cel mai mare divizor comun al celor dou. int cmmdc (int n1, int n2) { int min, i; min = n1<n2 ? n1 : n2; // minimul dintre valorile n1 si n2 for(i=min; i>=2 ; i--) { if(!(n1%i)&&!(n2%i)) break; } return i; } 262

/***************************************************************************

Exemplul 14.6. S se ntocmeasc un program n care se definesc structurile: struct data { int zi, luna, an;};
struct student { char nume[15], prenume[20]; data data_n; int gr; int note[8]; float media; }; Folosind aceste structuri s se memoreze datele unei grupe de studeni. Datele vor fi citite de la tastatur, vor fi memorate ntr-un tablou de tip student i vor fi afiate. ***************************************************************************/ #include <stdio.h> #include <conio.h> #define N 50 struct data { int zi, luna, an;}; struct student { char nume[15], prenume[20]; data data_n; int gr; int note[8]; float media; }; void citire(student & s); void afisare(student & s); void main() { student grupa[N]; int nr_stud, k; // se citete numrul studenilor <=50 do { printf("\nIntroduceti numarul studentilor:"); scanf("%d", &nr_stud); } while (nr_stud<1 || nr_stud>50); // se citesc datele studenilor printf("Introduceti datele studentilor:\n"); // prototipul funciei de citire a datelor unui student // prototipul funciei de afiare a datelor unui student

263

for(k=0 ; k<nr_stud ; k++) { printf("\nIntroduceti datele studentului %d:",k+1); citire(grupa[k]); // apelul funciei de citire } // se afieaz datele studenilor printf("\nDatele citite sunt:\n"); for(k=0;k<nr_stud;k++) { afisare(grupa[k]); // apelul funciei de afiare getch(); } getch(); } void citire(student & s) // definiia funciei de citire a datelor unui student { int i; printf("\nnumele:"); scanf("%14s", s.nume); printf("prenumele:"); scanf("%19s", s.prenume); printf("data nasterii:"); scanf("%d%*c%d%*c%d", &s.data_n.zi, &s.data_n.luna, &s.data_n.an); printf("grupa:"); scanf("%d", &s.gr); printf("Notele:\n"); s.media=0; for(i=0; i<8; i++) { printf("nota[%d]=",i+1); scanf("%d", &s.note[i]); s.media += s.note[i]; } s.media /=8; } void afisare(student & s) // definiia funciei de afiare a datelor unui student { printf("\n----------------------------------------------------"); printf("\nNumele: %s %s", s.nume, s.prenume); printf("\nGrupa: %d", s.gr); printf("\nData nasterii: %d.%d.%d", s.data_n.zi, s.data_n.luna, s.data_n.an); printf("\nNotele: "); for(int i=0 ; i<8 ; i++) printf("%d ", s.note[i]); printf("\nMedia: %.2f", s.media); printf("\n----------------------------------------------------\n"); }

264

Rezolvarea testelor de autoevaluare

Unitatea de nvare U3 1. c d 2. d Unitatea de nvare U4 1. a b e 2. b c d 3. b c e Unitatea de nvare U5 1. b c 2. a 3. d Unitatea de nvare U6 1. a b c 2. a b d e 3. e 4. a c d Unitatea de nvare U7 1. a 2. a Unitatea de nvare U8 1. b 2. c Unitatea de nvare U9 1. b c d 2. a 3. a b 4. b 5. c 6. c 265 7. b d 8. b 9. a 10. b 3. a 4. e 5. d 6. c 7. e 3. a c 4. a c d 5. 5. a c d 6. b 7. 8. e 9. a 10. b d 11. b 12. d 13. b 14. a 15. a 4. a 5. a 6. d 7. c 8. d 9. c 10. b 11. b 12. d 4. a 5. a d 6. a c 7. a d 8. c 9. b d 10. b c 11. a b 12. c d 3. a d 4. a e 5. a b d 6. a c 7. a c d 8. b c d

Unitatea de nvare U10 1. a d 2. a b c 3. b Unitatea de nvare U11 1. c 2. a 3. a Unitatea de nvare U12 1. a b d 2. a b 3. c Unitatea de nvare U13 1. b c 2. c 3. b c 4. b 5. b 6. c 7. b 8. b 9. c 10. c 11. a 12. 13. b c 14. a c 15. a c 4. b 5. b 6. c 7. b 8. a 9. c 10. c 4. a 5. c 6. c d 7. 8. b 9. b e 10. b 4. c 5. b c e 6. a b c 7. a c 8. a 9. d 10. b 11. c 12. c

266

Bibliografie.

[1] [2] [3] [4] [5] [6] [7] [8] [9]

Jamsa, K., Klander, L., Totul despre C i C++, Editura Teora, 2000 Eckel, B., Thinking in C++ 2nd edition, version TICA12, Prentice Hall, 2000, http://www.BruceEckel.com/ThinkingInCPP2e.html Knuth, D.E., Tratat de programarea calculatoarelor, vol.3: Algoritmi seminumerici, Editura Tehnic, Bucureti, 1985. Popa, M., Popa, M., Elemente de algoritmi i limbaje de programare, Editura Universitii din Bucureti, 2005. Schildt, H.: C++ Manual complet, Editura Teora, Bucureti, 2000 Schildt, H., C++ - manual complet, Editura Teora, Bucureti, 2001 Ungureanu, A, Ungureanu, D., s.a., Informatica la ndemna oricui, Editura Universitii Naionale de Aprare Carol I, Bucureti, 2006. Ungureanu, D., Programare obiectual folosind C++, Editura Universitii Transilvania, Braov, 2009 Ungureanu, D., Programare procedural folosind C/C++, Editura Universitii Transilvania, Braov, 2008

.a.: Programarea calculatoarelor ndrumar C++, [10] Ungureanu, D., Universitatea Transilvania din Braov 2001. [11] Negrescu, L.: Limbaje de programare C/C++ pentru nceptori, Vol. I, II, Ed. MicroInformatica Cluj-Napoca2000. [12] http://www.cprogramming.com/tutorial.html [13] http://www.intap.net/~drw/cpp/index.htm [14] http://www.icce.rug.nl/documents/cplusplus [15] http://www.uow.edu.au/~nabg/ABC/ABC.html [16] *** Borland C++ Version 3.1, Programming Guide, Borland International, 1992 [17] *** Borland C++ Version 3.1, Library Reference, Borland International, 1992 [18] *** Borland C++ Version 3.1, Users Guide, Borland International, 1992 [19] *** C Programming and C++ Programming, http://www.cprogramming.com

267

You might also like