Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

188
UNIVERSITATEA PETROL-GAZE DIN PLOIEŞTI PROGRAMAREA CALCULATOARELOR Curs destinat specializării Automatică şi Informatică Aplicată, Anul I domeniul de studii de licenţă Automatică - Învăţământ cu frecvenţă redusă - PLOIEŞTI 2012

Transcript of Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

Page 1: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

UNIVERSITATEA PETROL-GAZE DIN PLOIEŞTI

PPRROOGGRRAAMMAARREEAA CCAALLCCUULLAATTOOAARREELLOORR

 

Curs destinat specializării

Automatică şi Informatică Aplicată, Anul I

domeniul de studii de licenţă

Automatică

- Învăţământ cu frecvenţă redusă -

PLOIEŞTI 2012

Page 2: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

 

Page 3: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

Introducere

Acest curs face parte din primele cursuri prezentate studenţilor în programul de pregătire şi are ca obiective principale prezentarea conceptelor de bază din informatică şi prgătirea cursanţilor în domeniul progamării calculatoarelor.

Competenţele generale urmărite se referă la cunoaşterea arhitecturii calculatoarelor, a sistemelor de operare, a conceptelor fundamentale ale informaticii şi ale algoritmicii.

Competenţele specifice se referă la:

abilitatea de a transpune datele unei probleme de rezolvat într-un program, de a proiecta algoritmi care să rezolve corect şi eficient problema şi de a interpreta corect rezultatele obţinute;

abilitatea de a înţelege algoritmii aflaţi în spatele diverselor aplicaţii software (inginereşti sau generale), în vederea întreţinerii sau îmbunătăţirii lor, a testării şi a corectării eventualelor erori.

Cursul este structurat în cinci unităţi de învăţare (UI):

UI1. Introducere în informatică

Concepte de bază ale informaticii

Arhitectura calculatoarelor

Sisteme de operare

UI2. Baze de numeraţie. Reprezentarea informaţiei în

calculator

Baze de numeraţie

Reprezentarea informaţiei în calculator

UI3. Rezolvarea problemelor cu calculatorul

Etapele rezolvării problemelor cu calculatorul

Tipuri de date si operatii elementare

Structuri de date

Algoritmi – caracteristici şi descriere

Page 4: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

UI4. Introducere în limbajul de programare C

Introducere în limbajul de programare C

Elemente de bază ale limbajului C

Expresii în C. Funcţii de intrare/ieşire uzuale pentru

consolă

UI5. Programare în limbajul C

Instrucţiuni de control ale programului

Tablouri şi şiruri de caractere

Resursele complementare care vor fi utilizate pe parcursul studiului sunt: calculatoarele şi aplicaţia-program Borland C++ care va permite crearea şi testarea programelor create de studenţi în limbajul de programare C şi diverse programe coduri sursă scrise în acest limbaj.

Evaluarea cunoştinţelor se realizează prin:

autoevaluarea cu ajutorul sarcinilor de învăţare incluse în fiecare UI şi al testelor aflate la finalul fiecărei UI pentru care se oferă rezultatele;

o lucrare de verificare asistată de tutore susţinută la finalul programului de pregătire.

Criteriile de evaluare sunt: notele obţinute la verificarea asistată (proporţie 60%) şi nota acordată la examinarea finală (proporţie 40%).

Page 5: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

Cuprinsul cursului

UI1. Introducere în informatică Obiectivele unităţii de învăţare – pag 5

Concepte de bază ale informaticii – pag 5 Arhitectura calculatoarelor – pag 10  Sisteme de operare – pag 21 Răspunsurile testelor de autoevaluare – pag 26 Lucrarea de verificare – pag 27 UI2. Baze de numeraţie. Reprezentarea informaţiei în calculator

Obiectivele unităţii de învăţare – pag 29 Baze de numeraţie – pag 29 Reprezentarea informaţiei în calculator – pag 37

Răspunsurile testelor de autoevaluare – pag 46 Lucrarea de verificare – pag 46

UI3. Rezolvarea problemelor cu calculatorul

Obiectivele unităţii de învăţare – pag 49 Etapele rezolvării problemelor cu calculatorul – pag 49 Tipuri de date si operatii elementare – pag 53 Structuri de date – pag 55 Algoritmi – caracteristici şi descriere – pag 63 Răspunsurile testelor de autoevaluare – pag 79 Lucrarea de verificare – pag 80 UI4. Introducere în limbajul de programare C

Obiectivele unităţii de învăţare – pag 83 Introducere în limbajul de programare C – pag 83 Elemente de bază ale limbajului C – pag 90 Expresii în C. Funcţii de intrare/ieşire uzuale pentru consolă – pag 98 Răspunsurile testelor de autoevaluare – pag 129 Lucrarea de verificare – pag 129 UI5. Programare în limbajul C

Obiectivele unităţii de învăţare – pag 133 Instrucţiuni de control ale programului – pag 133 Tablouri şi şiruri de caractere – pag 168 Răspunsurile testelor de autoevaluare – pag 181 Lucrarea de verificare – pag 182

Page 6: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I
Page 7: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

5

UI1. Introducere în informatică

Obiectivele unităţii de învăţare – pag 5

Concepte de bază ale informaticii – pag 5

Test de autoevaluare – pag 10

Arhitectura calculatoarelor – pag 10

Test de autoevaluare – pag 21

Sisteme de operare – pag 21

Test de autoevaluare – pag 26

Răspunsurile testelor de autoevaluare – pag 27

Lucrare de verificare – pag 26

Rezumat – pag 27

Bibliografie – pag 28

Obiectivele unităţii de învăţare

cunoaşterea conceptelor fundamentale ale informaticii;

cunoaşterea arhitecturii calculatoarelor;

cunoaşterea sistemelor de operare.

Durata: 4 ore

Concepte de bază ale informaticii

Prin dată se înţelege un număr, mărime, relaţie etc., reprezentarea unui fenomen, lucru sau fapt, fiind susceptibilă de a fi memorată, transformată sau vehiculată [5].

În sens larg, informaţia desemnează un element nou, necunoscut anterior. În sens restrâns informaţia poate fi definită ca o măsură a incertitudinii înlăturată prin realizarea unui eveniment dintr-un set de evenimente posibile [5].

Page 8: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

6

O informaţie este o dată căreia i s-a asociat o semnificaţie. Spre exemplu, valoarea 3, care este o dată memorată în calculator, poate reprezenta într-un caz numărul de obiecte dintr-un şir, iar în alt caz preţul unui produs.

Calculatorul este sistemul fizic care prelucrează datele introduse într-o formă prestabilită şi furnizează rezultate fie într-o formă accesibilă utilizatorului, fie ca semnale destinate acţionării unor echipamente [5].

În funcţie de modul de reprezentare a datelor există:

calculatoare numerice, unde datele sunt codificate numeric;

calculatoare analogice, unde pentru codificare se utilizează elemente de tip continuu;

calculatoare hibride, care îmbină elemente de tip numeric cu elemente de tip continuu.

În acest curs ne referim la calculatoarele numerice. Principalele clase de calculatoare numerice sunt cele IBM şi compatibile IBM (reunite generic sub denumirea de PC1-uri) şi calculatoarele MacIntosh (iMac). Atunci când un calculator face parte dintr-o reţea, acesta se numeşte staţie de lucru sau server de reţea, după rolul pe care îl îndeplineşte în cadrul reţelei.

După manevrabilitate, calculatoarele sunt:

staţionare (sau de tip desktop) sau

portabile.

Principalele tipuri de calculatoare portabile sunt: calculatoarele laptop, notebook, palmtop (PDA2), handheld şi alte aparate "inteligente“. Caracteristicile acestora se referă la: puterea de calcul, portabilitate (dimensiuni, greutate, durata de viaţă a bateriilor), conectivitate şi fiabilitate (condiţii de utilizare mobilă, medii critice, rezistenţa la şocuri mecanice).

Informatica este ştiinţa pluridisciplinară având ca scop proiectarea, dezvoltarea şi exploatarea unor tehnici şi sisteme, pentru organizarea, memorarea şi distribuirea mai eficientă a informaţiei.

                                                            1 engl. Personal Computers 2 Personal Digital Assistant 

Page 9: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

7

Evoluţia maşinilor de calcul - scurt istoric

Ideea efectuării calculelor cu ajutorul unor dispozitive nu este de dată recentă. Astfel, abacul, unul din primele dispozitive de calcul realizat de om şi care este folosit şi astăzi, este cunoscut din timpul civilizaţiilor antice, greacă şi romană. Stocarea datelor se face în cazul abacului manual prin poziţionarea unor bile pe sârmele unui cadru dreptunghiular, iar rezultatele se obţin prin observarea poziţiilor finale ale bilelor.

Mult mai târziu apare ideea reprezentării datelor cu ajutorul unor roţi dinţate. Valorile de intrare se marcau manual prin poziţionarea corespunzătoare a roţilor, se declanşa angrenajul de roţi dinţate şi la oprire se interpretau poziţiile finale ale roţilor. Legat de această tehnologie, cele mai importante nume sunt: Blaise Pascal (1623-1662, francez), Gottfried Wilhem Leibniz (1646-1716, german), Charles Babbage (1792-1871, englez).

Spre deosebire de invenţiile predecesorilor săi, maşina inventată de Babbage tipărea rezultatele direct pe hârtie, evitând astfel erorile de transcriere. În 1801, Joseph Jacquard (Franţa), un producător de războaie de ţesut, avusese ideea de a comanda paşii pe care trebuia să-i realizeze maşina pentru a realiza un anumit model de ţesătură folosind perforaţiile de pe cartelele de hârtie. Babbage aplică această idee în cazul maşinii sale de calcul: paşii algoritmului nu mai sunt integraţi în structura maşinii, ci sunt preluaţi de pe cartele perforate. În felul acesta, funcţie de configuraţia perforaţiilor, maşina lui Babbage putea să execute diferiţi algoritmi. Ideile folosite de Babbage în construcţia maşinii sale, cum ar fi tipărirea rezultatelor şi mai ales memorarea paşilor algoritmilor vor fi folosite şi mai târziu, în epoca modernă a calculatoarelor.

La recensământul efectuat în 1890 în S.U.A., Herman Hollerith (1860-1929) utilizează pentru memorarea datelor cartelele perforate, fapt ce reduce spectaculos timpul de procesare a informaţiilor. Legat şi de rezultatele obţinute de Hollerith, în 1924 apare compania IBM (International Business Machine Corporation), care va juca un rol important în evoluţia tehnicii de calcul pe plan mondial. În 1940, George Stibitz construieşte la Bell Laboratories o maşină de calcul electronică. Patru ani mai târziu, în 1944, Howard Aiken de la Universitatea din Harvard construieşte calculatorul Mark I, care utilizează relee mecanice comandate electronic. Primul calculator electronic

Page 10: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

8

bazat pe tuburi electronice este considerat a fi ENIAC (Electronic Numerical Integrator And Calculator) construit de John Mauchly şi J. Presper Eckert, de la Universitatea din Pensylvania, în perioada 1942-1945.

Unii cercetători ai istoriei evoluţiei calculatoarelor consideră că prima maşină care foloseşte integral în construcţia sa elemente electronice este calculatorul construit de John Atanasoff şi de asistentul său Clifford Berry în perioada 1937-1941.

Revenind la ENIAC, se poate spune că, faţă de calculatoarele din ziua de azi, era un gigant care se “mişca” însă foarte lent. Avea în structura sa aproape 20 000 de tuburi electronice, ocupa 160m2 şi avea o greutate de aproximativ 30 tone. Viteza de calcul putea ajunge până la 5000 de adunări pe secundă. O problemă dificilă era introducerea datelor şi a programului. Această activitate dura mai multe zile şi se făcea cu ajutorul fişelor celor 40 de panouri special construite în acest scop.

Matematicianul american de origine germană John von Neumann publică în 1946, în SUA proiectul primului calculator cu prelucrare secvenţială a instrucţiunilor şi datelor, memorate împreună într-o zonă specială numită memoria calculatorului. Aceste principii folosite de von Neumann au stat la baza dezvoltării calculatoarelor moderne. Prima aplicare a acestor principii este datorată profesorului M. Wilkes de la Universitatea Cambridge din Anglia, care în 1949 a construit primul calculator cu program stocat într-o memorie cu întârziere, calculator ce a primit numele EDSAC (Electronic Delay Storage Automatic Calculator).

Perioada care a urmat este împărţită în etape de evoluţie cunoscute sub numele de generaţii de calculatoare. Prezentăm în continuare limitele (aproximative în timp) ale fiecărei generaţii, precum şi caracteristicile sale principale.

Generaţia I de calculatoare este cuprinsă între anii 1946-1958 şi foloseşte drept tehnologie de bază tuburile electronice. Alte caracteristici ale acestor calculatoare sunt:

memorie de capacitate redusă şi timp de acces mare;

viteză de calcul redusă (maxim 104 operaţii/sec);

se programează în cod maşină şi în limbaje de asamblare.

Page 11: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

9

Generaţia a II-a de calculatoare este localizată în timp între anii 1958-1964 şi se bazează pe tehnologia tranzistoarelor şi a diodelor semiconductoare. Caracteristicile de bază ale acestei generaţii de calculatoare sunt:

memorie internă cu capacitate sporită şi timp de acces mai redus;

viteză de calcul sporită (maxim 105 operaţii/sec);

apar limbajele de programare: FORTRAN (FORmula, TRANslator), COBOL (Common Business Oriented Language) şi ALGOL (ALGOrithmic Language);

apar sistemele de operare.

Generaţia a III-a de calculatoare se întinde de-a lungul perioadei 1964-1981 şi are la bază tehnologia circuitelor integrate. Printre caracteristicile celei de-a III-a generaţii amintim:

volum redus, capacitate mare de memorare;

viteza de calcul mare (106 adunări/sec) ;

se dezvoltă limbajele de programare de nivel înalt: PL/1, Pascal, LIST, Basic etc. şi de nivel mediu (limbajul C).

Generaţia 3.5 - 4 acoperă perioada 1982-1989 şi se bazează pe tehnologia circuitelor integrate pe scară largă şi foarte largă (până la un milion de tranzistoare pe circuit integrat).

Concomintent cu progresele obţinute în domeniul tehnologiei folosite, se dezvoltă puternic componentele logice de bază ale calculatorului. Astfel, în preţul unui calculator, costul software-ului creşte sensibil în raport cu costul datorat hardware-ului. Se dezvoltă modul de lucru interactiv, sistemele de gestiune a bazelor de date, apar limbajele de programare concurente.

Generaţia a V-a de calculatoare cuprinde perioada 1980-1990 şi se remarcă atât prin progrese tehnologice deosebite (grad ridicat de minituarizare datorat circuitelor integrate pe scară foarte largă, viteze de ordinul miliardelor de operaţii pe secundă, memorii externe de ordinul Gigaocteţilor la preţuri tot mai mici), cât şi prin dezvoltarea impresionantă a elementelor de inteligenţă artificială. Acest lucru a permis apariţia unor limbaje specializate (de exemplu PROLOG – PROgramare LOGică) şi elaborarea mai eficientă a unor sisteme expert care imită modul de raţionament

Page 12: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

10

al experţilor umani.

Generaţia a VI-a de calculatoare se dezvoltă în prezent şi are la bază rezultatele obţinute în optoelectronică şi mai ales bioelectronică.

� Test de autoevaluare

1.1. Care este deosebirea dintre date şi informaţii?

1.2. Care dintre următoarele sunt clasificări valide ale calculatoarelor?

a. calculatoare numerice, analogice şi portabile;

b. calculatoare numerice, analogice şi hibride;

c. calculatoare staţionare şi portabile.

Arhitectura calculatoarelor

Calculatorul, ca sistem fizic destinat implementării şi prelucrării automate a unor modele logico-matematice are la bază trei tipuri de resurse:

resurse fizice (procesoare, memorie, dispozitive de intrare-ieşire) numite resurse hardware;

resurse logice (sisteme de operare, programe utilitare, programe utilizator) numite resurse software;

resurse informaţionale (date organizate şi memorate pe suporţi de memorie externă).

Funcţionarea calculatorului devine posibilă prin activarea unui anumit tip de conexiuni existente între unităţile sale cu destinaţie specială numite unităţi funcţionale. Arhitectura unui calculator cuprinde reprezentarea unităţilor sale funcţionale şi a legăturilor dintre ele. Există diverse tipuri arhitecturale, funcţie de o serie de criterii care iau în calcul aspecte privind timpul şi costul prelucrărilor, necesităţile de prelucrare şi transmitere a datelor, tipul problemelor care sunt rezolvate etc.

Arhitectura clasică (serială) e reprezentată de sistemul de calcul monoprocesor sau maşina de calcul John von Neumann.

Page 13: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

11

La modul cel mai general, un sistem de calcul von Neumann are la bază următoarele unităţi funcţionale:

mediu de intrare – unitate de intrare (UI);

mediu de ieşire – unitate de ieşire (UE);

memorie – unitate de memorie (UM);

ansamblu de prelucrare – unitate aritmetică şi logică (UAL) sau unitate de execuţie;

element de comandă şi control – unitate de comandă şi control (UCC).

Unitatea de intrare (UI) preia sub controlul unităţii de comandă şi control informaţia de la diverse dispozitive (periferice) de intrare, o aduce la forma standard de reprezentare şi o transferă în unitatea de memorie. Informaţia poate fi reprezentată de date sau instrucţiuni de executat. Exemple de dispozitive de intrare: tastatură, mouse, scanner, creion optic etc.

Unitatea de ieşire (UE) preia sub controlul UCC informaţia din memorie şi o transferă într-o formă adecvată dispozitivelor periferice de ieşire: videomonitor, imprimantă, boxe audio etc.

Unitatea de memorie (UM) are rolul de stocare primară şi secundară în locaţii (celule) de memorie - identificabile după adrese - date de intrare, seturi de instrucţiuni destinate execuţiei (programe) şi rezultate ale execuţiei acestora.

Memoria RAM3 este o memorie volatilă, care îşi pierde conţinutul la întreruperea alimentării cu energie electrică a calculatorului. De exemplu, datele înscrise într-un document înainte de salvare sunt păstrate în memoria RAM a calculatorului. Odată cu salvarea documentului, datele sunt transferate pe un dispozitiv de stocare de tip memorie ROM4, care este o memorie nevolatilă, adică îşi păstrează conţinutul şi după încetarea alimentării cu energie electrică a calculatorului.

Unitatea aritmetică şi logică (UAL) permite efectuarea unor operaţii aritmetice sau logice conform instrucţiunilor programului.

Citirea instrucţiunilor din memorie, decodificarea lor şi

                                                            3 Random Access Memory ‐ memorie cu acces aleator 4 Read Only Memory 

Page 14: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

12

transmiterea semnalelor de comandă pentru execuţia lor, către UAL sau unităţile de intrare-ieşire (I/O), precum şi controlul bunei funcţionări a întregului sistem de calcul, cad în sarcina unităţii de comandă şi control (UCC). Unitatea de comandă şi control (UCC) împreună cu unitatea aritmetică şi logică (UAL) formează unitatea centrală de prelucrare (UCP) sau procesorul calculatorului. Procesorul împreună cu unitatea de memorie alcătuiesc unitatea centrală a calculatorului (UC).

Între elementele funcţionale de bază ale calculatorului există căi de comunicaţie care permit circulaţia informaţiei reprezentată prin adrese, date de prelucrat, comenzi. Din punct de vedere funcţional, sistemul de calcul John von Neumann se poate reprezenta sub forma schemei din Figura 1.1.

Figura 1.1. Arhitectura maşinii de calcul John von Neumann

Modul de funcţionare al acestui tip de calculator se poate rezuma astfel. Datele în forma lor primară (neprelucrată) precum şi programul sunt preluate cu ajutorul dispozitivelor de intrare, aduse la forma standard de reprezentare şi transferate în memorie unde sunt memorate în locaţii identificabile prin adrese. Fiecare instrucţiune a programului este preluată de UCC, care decodifică operaţia ce trebuie executată, trimite UAL comanda corespunzătoare şi solicită memoriei transferul către UAL a datelor aflate la adresele specificate în instrucţiune. UAL execută operaţiile cerute şi depune sub controlul UCC rezultatele temporar în memorie sau le transmite dispozitivelor de ieşire.

Prezentăm mai jos arhitectura unităţii de memorie.

Arhitectura unităţii de memorie (UM)

Memoria calculatorului poate fi privită ca un ansamblu de

UI UE

UM

UAUCprocesor

UC

Page 15: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

13

locaţii de memorie identificabile prin adrese. Se spune că memoria este adresabilă.

Componenta fizică de bază în construcţia memoriei o reprezintă bistabilul – element care poate lua doar două stări stabile. Stările bistabililor se asociază în mod tradiţional cu cifrele binare 0 sau 1 numite şi biţi – pluralul termenului bit (binary digit5). În calculatoare, bistabilii se realizează cu ajutorul inelelor de ferită sau cu circuite integrate, iar cele două stări corespund perechii de tensiuni (0V, 5V). Ca exemple de bistabili enumerăm perechile de stări: perforat-neperforat, stins-aprins, magnetizat-nemagnetizat. Prezenţa bistabililor în construcţia memoriei a impus codificarea binară a informaţiei în calculator.

O locaţie de memorie poate fi privită ca o succesiune de bistabili, iar la nivel formal ca o configuraţie binară (succesiune de biţi). Prin urmare, pe m biţi consecutivi se pot reprezenta 2m configuraţii binare diferite.

Bitul reprezintă cea mai mică unitate de date care poate fi reprezentată şi prelucrată de calculator. Pentru exprimarea unui bit se foloseşte litera b.

O succesiune de 8 biţi formează un octet (sau byte). Acesta este cea mai mică unitate de date adresabilă. Pentru exprimarea unui byte se foloseşte litera B.

Multiplii folosiţi în exprimarea capacităţii memoriei sunt: Kilo, Mega, Giga, Tera, Peta, Exa, Zetta şi Yotta:

1 Kilo byte (KB) = 1024 bytes (210 bytes)

1 Mega byte (MB) = 1024 KB (220 bytes)

1 Giga byte (GB) = 1024 MB (230 bytes)

1 Tera byte (TB) = 1024 GB (240 bytes)

1 Peta byte (PB) = 1024 TB (250 bytes)

1 Exa byte (EB) = 1024 PB (260 bytes)

1 Zetta byte (ZB) = 1024 EB (270 bytes)

1 Yotta byte (YB) = 1024 ZB (280 bytes)

Deşi pentru măsurarea capacităţii memoriei şi a dimensiunii fişierelor multiplii unităţilor sunt puteri ale lui 2 (deoarece se

                                                            5 care în traducere din limba engleză semnifică “cifră binară”

Page 16: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

14

lucrează în sistem binar), pentru vitezele de transfer al informaţiei, se obişnuieşte să se folosească multipli care nu mai sunt puteri ale lui 2, ci ale lui 10 [3]:

1 Kilo bit pe secundă (Kbps) = 1 000 bps (103 bps)

1 Mega bit pe secundă (Mbps) = 1 000 000 bps (106 bps)

1 Giga bit pe secundă (Gbps) = 1 000 000 000 bps (109 bps)

Aşadar, un fişier de 1 MB memorează 1024 (210) octeţi de informaţie, însă o linie de comunicaţie de 1Mbps transmite 1 000 000 (106) biţi pe secundă.

Doi, trei sau patru octeţi consecutivi formează un cuvânt. Lungimea cuvântului diferă de la un tip de calculator la altul. Reprezentarea în memorie a informaţiei se realizează la nivel de cuvânt sau de multipli ai acestuia.

Accesul la o locaţie de memorie se face pe baza adresei sale. Dacă adresa se formează pe o configuraţie de m biţi, se poate explora un spaţiu de adresare în memorie de 2m cuvinte.

Timpul de acces reprezintă timpul scurs de la cererea unei date din memorie până la obţinerea acesteia. Accesul la o locaţie de memorie este aleator (direct), iar timpul de acces este aproximativ acelaşi pentru orice locaţie.

Transferul informaţiei în memorie se numeşte scriere, iar extragerea datelor din memorie se numeşte citire. Executarea unei operaţii de citire-scriere se poate face doar cunoscând adresa locaţiei de memorie implicate.

✎ Descrieţi pe scurt arhitectura unităţii de memorie.

Unităţile de stocare a datelor sunt formate din:

mediile de stocare (suporturile fizice)

+

interfeţele de comunicare ale acestora cu UC,

împreună cu protocoalele logice aferente.

Page 17: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

15

Principalele medii de stocare sunt:

harddisc-urile,

memoriile flash (stick memory),

discurile optice şi discurile magneto-optice,

dischetele (floppy disk),

benzile magnetice,

memoriile holografice,

memoriile moleculare.

Interfeţele (controller-ele) unităţilor de stocare gestionează schimbul de informaţie între UC şi unităţile de stocare. Arhitecturile de bază sunt:

IDE6, numită mai târziu ATA7 şi apoi PATA (parallel ATA) pentru a o distinge de SATA (serial ATA). Are o lăţime de 16 biţi şi permite două dispozitive pe fiecare canal.

EIDE8, cu rate de transfer de 4-16.6 MB/s, poate suporta dispozitive de stocare de până la 8.4 GB (Fast ATA sau Fast IDE sau ATA-2). ATA-3 sau Ultra ATA suportă transferuri de 33 MB/s.

SATA9, cu rate de transfer de 3 Gb/s per dispozitiv, permite îndepărtarea sau adăugarea de dispozitive în timpul operării. SATA 300 de exemplu asigură o viteză de transfer de 300 MB/s.

SCSI10 foloseşte comunicarea paralelă şi oferă o lăţime de bandă maximă per dispozitiv de 320 MB/s şi rate de transfer de până la 80 MB/s, mai mari decât alte porturi seriale şi paralele.

SAS11, o generaţie mai nouă de protocoale de comunicare serială, creată pentru a permite viteze mai mai de transfer al datelor, compatibil cu SATA. Oferă o viteză de transfer

                                                            6 Integrated Drive Electronics 7 Advanced Technology Attachment 8 Enhanced IDE 9 Serial Advanced Technology Attachment 10 Small Computer System Interface 11 Serial Attached SCSI 

Page 18: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

16

de 375 MB/s şi permite 4 dispozitive pe fiecare canal.

Mediul de stocare este suportul (detaşabil) de memorare, iar unitatea de stocare aferentă este, din punct de vedere fizic, întregul ansamblu care asigură memorarea. Denumirea unităţii de stocare include termenul “drive” pe lângă numele mediului de stocare pe care îl suportă. De exemplu:

Mediu de stocare Unitate de stocare

HD (Harddisk) HDD (Harddisk Drive)

CD-ROM CD-ROM Drive

Caracteristicile mediilor de stocare sunt: tipul interfeţei suportate (IDE, SCSI etc.), viteza maximă (teoretică) de citire/scriere a informaţiei, capacitatea, timpul de acces, fiabilitatea şi viteza de acces (în rotaţii pe minut).

✎ Enumeraţi principalele medii de stocare a datelor.

În continuare se vor prezenta mai detaliat mediile de stocare (suporturile de memorie) după principiul de memorare.

Suporturile magnetice sunt dischetele, harddisc-urile şi memoriile RAM magnetorezistive (MRAM) şi sunt suporturi nevolatile.

Suporturile optice sunt de asemenea suporturi nevolatile. Acestea se clasifică astfel:

Discuri read only (care pot fi doar citite, nu şi scrise):

- CD-ROM (Compact Disk)

- DVD-ROM (Digital Video Disk sau Digital Versatile Disk)

- BD-ROM (Blu-ray Disk)

Discuri write once (care pot fi scrise numai o dată):

- CD-R, DVD-R, DVD+R, BD-R

Discurile rewritable (reînregistrabile):

- CD-RW, DVD-RW, DVD+RW, DVD-RAM, BD-RE

Discuri UDO (Ultra Density Optical), similare în

Page 19: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

17

capacitate cu BD-R sau BD-RE, dar folosite la stocarea terţiară sau off-line. Oferă un timp de acces de 35 ms, o capacitate de 60-120 GB (chiar 500 GB pe discuri de 13.3 cm în diametru) şi au durată de viaţă de aprox. 50 de ani.

Etichetele suporturilor optice conţin: tipul suportului, viteza de scriere/citire, capacitatea, numărul de feţe utile şi numărul de straturi. Un disc etichetat SS (Single Side) are o singură faţă utilă, unul etichetat DS (Double Side) are două feţe utile, unul SL (Single Layer) un singur strat, iar unul DL (Double Layer) două straturi.

Capacitatea, de exemplu, a unui disc optic de 8 cm diametru etichetat DVD-1 SS SL este de 1.46 GB, iar a unuia de 12 cm diametru etichetat DVD-18 DS DL este de 17.08 GB.

Viteza (teoretică) de transfer a informaţiei se etichetează sub forma 10x, 14x etc., raportat la o viteză standard 1x, care în cazul discurilor de tip CD este de 150 kB/s. Pentru discurile de tip DVD, viteza de scriere 1x este 1350 kB/s.

Generaţiile de suporturi optice sunt următoarele:

I. CD, discuri laser, discuri magneto-optice;

II. DVD, DVD-Audio, DualDisc, Digital Video Express (DIVX), Super Audio CD, Video CD, Universal Media Disc;

III. BD, BD-RE (cu o capacitate de 50 GB pe un strat dublu), Forward Versatile Disc, Digital Multilayer Disk sau Fluorescent Multilayer Disc, UDO;

IV. Holographic Versatile Disc (HVD, cu o capacitate de 3.9 TB, care echivalează cu cea a 5 800 de CD-ROM-uri) şi Protein-coated disc (cu o capacitate de 50 TB).

✎ Ce sunt unităţile de stocare a datelor şi care este relaţia

acestora cu unitatea de memorie? Dar cu suporturile fizice de memorare?

* * *

Reamintim că unitatea de comandă şi control (UCC) împreună cu unitatea aritmetică şi logică (UAL) formează unitatea centrală de prelucrare (UCP), reprezentată de procesorul calculatorului (microprocesor). Puterea de calcul a unui

Page 20: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

18

microprocesor se măsoară în MIPS12 sau în FLOPS13 şi este determinată de: lărgimea magistralelor de date şi a magistralelor de adrese (număr de biţi), de tipul soclului utilizat, de viteza maximă de lucru (măsurată în Hz), de capacitatea maximă de memorie pe care o poate accesa şi de tehnologia de fabricaţie14 (măsurată în microni, μm).

✎ Care sunt unităţile funcţionale care alcătuiesc

arhitectura unui calculator serial?

Calculatorul serial este construit după principiile stabilite de John von Neumann. Conform acestor principii, calculatorul este alcătuit din cele cinci unităţi funcţionale (unitatea de intrare, unitatea de ieşire, unitatea de memorie care conţine programul şi datele, unitatea aritmetică şi logică, unitatea de comandă şi control). Calculatorul serial are un singur procesor care execută o singură instrucţiune la un moment dat.

Viteza de lucru a procesoarelor actuale este de peste 109 operaţii pe secundă şi, evident, se doresc viteze şi mai mari. Se apreciază însă că limita fizică a numărului de operaţii este în jur de 1010 operaţii pe secundă. Acest rezultat este impus de limita vitezei de propagare a semnalului electric, care este de aproximativ un metru într-o nanosecundă (10-9 secunde). Pragul de 1010 operaţii pe secundă ar putea fi depăşit numai dacă s-ar micşora foarte mult dimensiunea componentelor calculatorului, lucru practic imposibil, deoarece unele componente ale calculatorului nu pot avea dimensiuni sub ordinul milimetrilor.

Alternativa la această situaţie o reprezintă folosirea mai multor procesoare în construcţia unui calculator. Această idee a prins contur în jurul anilor 1970. Abandonarea principiului lui John von Neumann – un singur procesor care execută o singură instrucţiune la un moment dat – a însemnat de fapt apariţia calculatorului paralel.

Calculatorul paralel reprezintă o colecţie de procesoare, de obicei de acelaşi tip, interconectate într-o anumită reţea care permite coordonarea activităţilor lor şi schimbul de date.                                                             12 Million Instructions per Second – milioane de instrucțiuni pe secundă  13 Floating Operations per Second – operații în virgulă mobilă pe secundă 14 dimensiunea componentei elementare a procesorului 

Page 21: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

19

Distanţele dintre procesoare sunt reduse, iar întreg ansamblul obţinut contribuie la rezolvarea unor probleme de regulă dificile sau/şi de dimensiuni mari. Aceste caracteristici sunt esenţiale pentru a deosebi un calculator paralel de un sistem distribuit.

Astfel, deşi un sistem distribuit este văzut tot ca o colecţie de procesoare, diferenţa este că, în acest caz, ele sunt distribuite pe o arie geografică mare, sunt de obicei de tip diferit, iar scopul urmărit este utilizarea în comun a resurselor disponibile, precum şi colectarea şi transmiterea informaţiilor.

Eficienţa calculatorului paralel se datorează procesării paralele a datelor. Acest lucru permite reducerea timpului de rezolvare a unei probleme utilizând procesoare cu viteze nu foarte mari şi în consecinţă ieftine. Din acest motiv, un calculator paralel nu este neapărat mai scump decât unul serial. În ciuda acestei realităţi şi a faptului că la ora actuală cel puţin 25 de mari companii produc calculatoare paralele, totuşi, penetrarea lor pe piaţa calculatoarelor este destul de slabă. Motivul esenţial îl constituie tehnologia software relativ primitivă a calculatoarelor paralele. De-a lungul timpului fondurile pentru cercetare în software au vizat în special sectorul calculatoarelor seriale. Un software eficient pentru un calculator serial nu este obligatoriu eficient şi pentru calculatoare paralele. Crearea unor biblioteci performante de software destinat calculatoarelor paralele necesită timp şi bineînţeles fonduri.

Calculatoarele Cray şi Ciber (apărute în anii 1970) s-au numărat printre primele calculatoare din lume care au utilizat paralelismul. Ele au la bază un procesor vectorial care implementează tehnica pipeline. Originea termenului pipeline o găsim în industria petrolieră, unde desemnează o linie de selecţie pentru hidrocarburile dintr-un produs petrolier de bază. Această tehnică este asemănătoare cu ansamblarea unui produs pe o bandă rulantă: la fiecare unitate de timp fiecare diviziune de operaţii este în lucru.

Urmează apoi o dezvoltare rapidă de noi generaţii de supercalculatoare care cunosc îmbunătăţiri substanţiale: dispar buffer-ele (zonele tampon) de mare viteză, o parte din memorie e distribuită între procesoare, iar o parte este accesibilă tuturor unităţilor, se imaginează şi se pun în practică noi modalităţi de interconectare a procesoarelor etc.

Page 22: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

20

Calculatoarele paralele îşi găsesc utilitatea mai ales în rezolvarea problemelor care necesită soluţii rapide sau sunt de dimensiuni mari. Iată câteva exemple: probleme de procesarea imaginilor, probleme de modelare şi simulare (de exemplu simularea numerică a zăcămintelor de petrol), probleme de previziune a fenomenelor meteorologice etc.

✎ Daţi o scurtă definiţie a calculatorului paralel.

✎ Care sunt avantajele unui calculator paralel?

✎ Motivaţi de ce, în ciuda performanţelor, calculatoarele

paralele nu cunosc o răspândire aşa de mare ca maşinile de calcul seriale.

Clasificarea sistemelor paralele se poate face după mai multe criterii cum ar fi: numărul de procesoare, viteza de lucru a procesoarelor, mecanismul de control al sistemului, modul de organizare al memoriei, topologia dispunerii procesoarelor.

În legătură cu numărul de procesoare apare termenul de granulaţie. Granulaţia poate fi:

fină - aproximativ 1000 de procesoare, fiecare tratând date puţine;

grosieră - aproximativ 16 procesoare care tratează multe date;

medie - aproximativ 64 de procesoare.

O modalitate clară de a clasifica calculatoarele paralele o datorăm lui Flynn (1966). Conform acestei clasificări există patru categorii de calculatoare paralele [4]:

SISD (Single Instruction Single Data) - un singur set de instrucţiuni şi un singur set de date (calculatorul serial) ;

SIMD (Single Instruction Multiple Data) – un singur set de instrucţiuni şi mai multe seturi de date;

MISD (Multiple Instruction Single Data) – mai multe seturi de instrucţiuni şi un singur set de date;

MIMD (Multiple Instruction Multiple Data) – mai multe

Page 23: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

21

seturi de instrucţiuni şi mai multe seturi de date.

✎ Ce este arhitectura unui calculator?

� Test de autoevaluare

1.3. Ce fel de resurse se află la baza funcţionării calculatoarelor ?

a. resurse fizice, logice şi informaţionale;

b. resurse hardware, software şi informaţionale;

c. resurse fizice, software şi informaţionale.

1.4. Ce tipuri arhitecturale cunoaşteţi ?

1.5. Enumeraţi câteva domenii în care îşi găsesc utilitatea calculatoarele paralele.

1.6. Care este clasificarea lui Flynn?

1.7. Câţi biţi poate memora un CD-ROM cu capacitatea de 700 MB ?

Sisteme de operare

Sistemul de operare este o interfaţă între componenta hardware şi utilizator, reprezentat prin programele sale, numite şi programe de aplicaţie. Mai precis, un sistem de operare este un ansamblu de programe de control care ghidează un calculator în executarea sarcinilor sale şi asistă programele de aplicaţie şi utilizatorul prin intermediul anumitor funcţiuni [7]. Rolul sistemului de operare ca interfaţă om-calculator este evidenţiat în figura de mai jos (Figura 1.2).

Figura 1.2. Sistemul de operare ca interfaţă om-calculator [7]

Hardware Sistem de operare

Programe de aplicaţie Utilizator

Page 24: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

22

Un sistem de operare este alcătuit din două categorii de programe:

programe de comandă şi control;

programe de servicii.

Programele de comandă şi control coordonează şi controlează toate funcţiile sistemului de operare. Principalele componente ale sistemului de programe de comandă şi control sunt [7]:

supervizorul

sistemul de gestiune a intrărilor/ieşirilor.

Sarcinile supervizorului sunt următoarele:

coordonează toate componentele sistemului de operare;

planifică, lansează şi urmăreşte execuţia programelor;

depistează şi tratează evenimentele care apar la execuţie.

Rutinele de bază sau frecvent folosite, ale supervizorului, sunt rezidente în memoria internă. Celelalte sunt tranziente, adică sunt stocate în memoria auxiliară şi încărcate la nevoie în memoria internă.

Sistemul de gestiune al intrărilor/ieşirilor coordonează modul de afectare al dispozitivelor periferice programelor, precum şi transferul datelor dintre dispozitivele de intrare/ieşire şi memorie.

Cea de-a doua componentă a unui sistem de operare, programele de servicii, cuprinde [7]:

translatoare (asambloare, compilatoare, interpretoare);

editoare de legături (linkeditoare);

încărcătoare;

editoare de text;

programe utilitare;

programe bibliotecar;

programe pentru gestiunea operaţiilor de intrare/ieşire pentru fişiere şi baze de date.

Deoarece sarcina de bază a unui sistem de operare este de a

Page 25: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

23

pune la dispoziţia utilizatorului mijloace prin care să poată crea, stoca, prelucra, regăsi şi distruge informaţia, funcţiile sale de bază urmăresc realizarea acestor obiective.

✎ Daţi o definiţie scurtă a sistemului de operare.

Prezentăm mai jos lista funcţiilor de bază ale unui sistem de operare [7]:

pregătirea şi lansarea în execuţie a programelor de aplicaţie;

alocarea resurselor necesare executării programelor;

planificarea execuţiei lucrărilor după anumite criterii, cum ar fi: timp de execuţie, priorităţi etc.;

folosirea utilitarelor pentru crearea unor facilităţi de sortare (ordonare), creare biblioteci de programe, catalogare (depunere programe în bibliotecă) etc.;

coordonarea execuţiei mai multor programe, crearea unor facilităţi de depanare etc.;

asistarea execuţiei programelor de aplicaţie folosind posibilităţile de comunicare om - calculator.

Există patru tipuri de sisteme de operare [7]:

secvenţiale;

cu multiprogramare;

cu prelucrare multiplă;

în timp real.

În sistemele de operare secvenţiale (batchprocessing) prelucrarea programelor se face serial. Execuţia programului poate să înceapă numai după ce a fost încărcat complet în memorie împreună cu datele. Din acest motiv gradul de ocupare al procesorului este mic în raport cu timpul total folosit pentru execuţia programului (pentru câteva secunde de folosire a unităţii centrale se pierd mai mult de 5 minute).

Sistemele de operare cu multiprogramare (multi programming) au apărut tocmai din nevoia de a mări gradul de utilizare al procesorului. În acest scop, în memoria partajată corespunzător pot fi încărcate mai multe programe. Execuţia lor

Page 26: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

24

se realizează prin multiplexarea unităţii centrale. Dacă, de exemplu, în timpul execuţiei programului P1, se solicită o operaţie de intrare/ieşire, se execută o întrerupere I/O (Input/Output), iar procesorul va continua să execute instrucţiuni ale unui alt program P2 şi aşa mai departe. Acest tip de execuţie (programare concurentă) este, evident, mai eficient din punct de vedere al gradului de utilizare al procesorului, iar viteza cu care se execută programele creează percepţia execuţiei lor simultane. Gestiunea corectă a memoriei partajate, a accesului programelor la resurse (memorie, procesor, unităţi de intrare/ieşire) sunt doar două din problemele majore care apar în plus la aceste tipuri de sisteme de operare.

Sistemele de prelucrare multiplă se implementează pe calculatoarele cu mai multe procesoare (calculatoare paralele). Mai multe procesoare pot executa simultan acelaşi program dacă este descompus în mai multe sarcini (multitasking).

Sistemele de operare în timp real se folosesc pentru conducerea operativă a unor dispozitive ai căror parametrii se modifică continuu.

Exemple de sisteme de operare sunt: UNIX, Windows, Linux, MS-DOS şi MacOS.

✎ Enumeraţi şi caracterizaţi tipurile de sisteme de operare.

✎ Enumeraţi funcţiile de bază ale unui sistem de operare.

Fazele execuţiei unui program

Programul poate fi privit ca o unitate de operare. Indiferent în ce limbaj este scris, pentru a fi executat, programul trebuie translatat (tradus) în cod-maşină. Există două tipuri mari de translatoare: compilatoarele şi interpretoarele.

Modul de lucru al compilatorului este următorul. Se analizează sintactic programul sursă şi se furnizează o listă de erori. După eliminarea erorilor de către programator, se obţine forma binar translatabilă (BT) a programului. Formatul BT înseamnă un număr de module obiect fără legătură între ele. Programul care realizează legăturile dintre module este editorul

Page 27: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

25

de legături (linkeditorul). Se obţine forma IMT (Imagine Translatabilă a Memoriei). Este forma care va fi preluată de programul încărcător şi va fi încărcată la o adresă concretă de memorie obţinându-se formatul IMA (Imagine Absolută a Memoriei). În această formă programul poate fi executat.

Compilatorul limbajelor de asamblare se numeşte asamblor.

Fazele execuţiei unui program translatat prin compilare sunt prezentate mai jos (Figura 1.3):

Figura 1. 3. Fazele execuţiei unui program translatat prin compilare

Modul de lucru al interpretorului este următorul. Se analizează sintactic linie cu linie programul. Dacă linia de program analizată este corectă din punct de vedere sintactic atunci se şi execută înainte de a trece la analiza următoarei linii. Se observă că diferenţa esenţială dintre compilator şi interpretor se referă la momentul când se face execuţia în raport cu analiza sintactică a programului. La compilator execuţia se face după ce tot programul a fost translatat, la interpretor analiza sintactică a unei linii de program este urmată obligatoriu de execuţia ei.

Fiecare din cele două metode de translatare prezintă avantaje şi dezavantaje. Când se foloseşte compilatorul, necesarul de memorie este mai mare (memoria trebuie să conţină atât codul sursă cât şi codul obiect), dar modulele obiect rezultate pot fi catalogate în biblioteci şi folosite la nevoie.

În cazul interpretorului este nevoie de memorie relativ puţină, dar execuţia programului este mai anevoioasă deoarece presupune pentru fiecare linie, la fiecare rulare, atât translatarea cât şi execuţia.

cod sursă

format BT

format IMT

format IMA

compilator linkeditor încărcător execuţie

Page 28: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

26

� Test de autoevaluare

1.8. Care sunt cele două categorii de programe care alcătuiesc un sistem de operare?

1.9. Care sunt sarcinile supervizorului?

1.10. Enumeraţi funcţiile de bază ale unui sistem de operare.

1.11. Care sunt fazele de execuţie ale unui program translatat prin compilare?

Răspunsurile testelor de autoevaluare

1.1. Informaţie = dată + semnificaţie.

1.2. b, c

1.3. a, b, c

1.4. Arhitectura serială şi arhitectura paralelă.

1.5. Procesarea imaginilor, modelare şi simulare, previziune (economică, meteorologică etc.).

1.6. Clasificarea calculatoarelor paralele în categoriile: SISD, SIMD, MISD şi MIMD.

1.7. 700 MB = 700 * 8 * 1024 b.

1.8. Programele de comandă şi control şi programele de servicii.

1.9. Coordonează toate componentele sistemului de operare, planifică, lansează şi urmăreşte execuţia programelor, depistează şi tratează evenimentele care apar la execuţie.

1.10. Compilarea (sau analiza sintactică) a codului sursă, editarea legăturilor între modulele obiect rezultate, încărcarea formei IMT la o adresă concretă de memorie şi execuţia programului.

Page 29: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

27

Lucrare de verificare ...................................................✍

Realizaţi o sistematizare a cunoştinţelor dobândite în această unitate de învăţare.

Rezumat

Calculatoarele sunt sisteme fizice care prelucrează date pentru a furniza rezultate fie într-o formă accesibilă utilizatorului, fie ca semnale destinate acţionării unor echipamente.

Resursele pe care se bazează funcţionarea calculatoarelor sunt resurse fizice (sau hardware), logice (sau software) şi informaţionale. Resursele fizice se referă la componentele tangibile, cele software la sistemul de operare şi programele de aplicaţie, iar cele informaţionale reprezintă “materia“ prelucrabilă la un moment dat.

Sistemul de operare se defineşte ca un ansamblu de programe de control care ghidează calculatorul în executarea sarcinilor şi asistă programele de aplicaţie şi utilizatorul prin intermediul anumitor funcţiuni speciale. Sarcina de bază a unui sistem de operare este de a pune la dispoziţia utilizatorului mijloace prin care acesta să poată crea, stoca, prelucra, regăsi şi distruge informaţia.

Unităţile dedicate ale unui calculator împreună cu conexiunile ce se stabilesc între ele pentru asigurarea funcţionabilităţii sale se numeşte arhitectură de calcul. Cele două mari arhitecturi de calcul sunt: arhitectura serială, clasică (sistem de calcul monoprocesor sau maşină de calcul von Neumann) şi cea paralelă, care presupune conlucrarea simultană a mai multor procesoare în vederea rezolvării sarcinilor într-un timp mult mai redus.

Arhitectura serială cuprinde unitatea de intrare, unitatea de ieşire, unitatea de memorie, unitatea de execuţie şi unitatea de comandă şi control, plus conexiunile între acestea prin magistralele de adrese, de date şi de comenzi.

Cea mai mică unitate de date care poate fi reprezentată şi

Page 30: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

28

prelucrată de calculator este bit-ul (o valoare binară asociată unui bistabil). Un grup de opt biţi, numit octet sau byte, este cea mai mică unitate de date adresabilă, iar reprezentarea în memorie a informaţiei se realizează de regulă la nivel de cuvânt (care este un grup de 2, 3 sau 4 octeţi consecutivi).

Bibliografie

1. J. Glenn Brookshear, Introducere în Informatică, Ed. Teora,

Bucureşti, 1998.

2. Gheorghe Dodescu, Radu Mârşanu, Floarea Năstase,

Calculatoare – Elemente fundamentale de structură. Iniţiere în

utilizarea PC-urilor, Editura ALL EDUCATIONAL, Bucureşti, 2000.

3. Andrew Tanenbaum, Computer Networks, fourth edition, Pearson

Education International, 2003.

4. Dana Petcu, Calcul Paralel, Editura de Vest, Timişoara, 1994.

5. Tiberiu Popescu (coordonator), Dicţionar de Informatică, Editura

Ştiinţifică şi enciclopedică, Bucureşti, 1981.

6. A. Petrescu, N. Ţăpuş, T. Moisa, Gh. Rizescu, V. Hărăbor, N.

Mârşanu, Tr. Mihu, abc de calculatoare personale şi … nu doar atât

…, Vol.I, Ed. Tehnică, Bucureşti, 1990.

7. Florin Păunescu, Analiza şi concepţia sistemelor de operare,

Editura Ştiinţifică şi Enciclopedică, Bucureşti, 1982.

Page 31: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

29

UI2. Baze de numeraţie. Reprezentarea informaţiei în calculator

Obiectivele unităţii de învăţare – pag 29

Baze de numeraţie – pag 29

Test de autoevaluare – pag 37

Reprezentarea informaţiei în calculator – pag 37

Test de autoevaluare – pag 45

Răspunsurile testelor de autoevaluare – pag 46

Lucrare de verificare – pag 46

Rezumat – pag 46

Bibliografie – pag 47

Obiectivele unităţii de învăţare

înţelegerea şi operarea facilă cu diverse baze de numeraţie şi cunoaşterea principiilor de conversie a numerelor întregi şi reale dintr-o bază de numeraţie în alta;

cunoaşterea modalităţilor de reprezentare a informaţiei în calculator, după tipul acesteia.

Durata: 4 ore

Baze de numeraţie

Orice număr natural 2q poate fi considerat o bază de numeraţie. Cifrele în baza de numeraţie q sunt 0, 1, 2, …, q-1. Baza 10 este evident cea mai cunoscută bază şi are cifrele 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Datorită utilizării bistabililor în construcţia memoriei calculatoarelor, în informatică se utilizează reprezentarea numerelor în baza 2 sau puteri ale acesteia (baza 8

Page 32: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

30

şi baza 16). Rezultatele obţinute în analiza matematică ne arată că orice număr real se poate scrie într-o bază oarecare 2q sub

forma .......... 3210121 innn aaaaaaaaa , unde ia sunt

cifre ale bazei q, adică 1...,,2,1,0 qai . În informatică, bazele uzuale sunt 2, 8 şi 16. Cifrele în baza 2 sunt {0, 1}, în baza 8, {0, 1, 2, 3, 4, 5, 6, 7}, iar în baza 16 sunt {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F}.

Exemple :

în baza 10 396.83, -25691, 48

în baza 2 1101.11, 111001.11, 110101

în baza 8 675.02, 0.36, -475

în baza 16 69A, DEA.AB5, CAD.39A

✎ Care sunt cifrele bazei de numeraţie 6?

Calea cea mai simplă de conversie a unui număr dintr-o bază în alta este utilizarea bazei 10 ca bază intermediară. Din acest motiv, în continuare prezentăm conversia numerelor din baza 10 într-o bază oarecare şi invers.

Conversia numerelor dintr-o bază în alta

Conversia numerelor întregi

Conversia numerelor întregi din baza oarecare q în baza 10

Conversia unui număr întreg din baza oarecare q în baza 10 se face utilizând dezvoltarea polinomială. Mai precis, dacă numărul întreg N se reprezintă în baza q sub forma

0121 ... aaaaaN nnnq

atunci reprezentarea în baza 10 va rezulta din dezvoltarea

012

21

110 ... aqaqaqaqaN nn

nn

nn

.

Exemple

10012345

2 35212120202021100011

10012

01216

302816416131611

16416164

DBBD

Page 33: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

31

Conversia numerelor întregi din baza 10 în baza oarecare q

Pentru a înţelege algoritmul de conversie dintr-o bază q în baza 10 să considerăm dezvoltarea polinomială

(1) 011

110 ... aqaqaqaN nn

nn

.

Sarcina algoritmului de conversie este să identifice cifrele

021 ...,,,, aaaa nnn , practic a numărului convertit în baza q,

011 ... aaaaN nnq .

Împărţind relaţia (1) prin q obţinem:

q

aaqaqa

q

N nn

nn

01

21

110 ...

.

Ţinând cont că expresia

12

110

10 ... aqaqaN nn

nn

este întreagă, iar qa 00 deoarece 0a este cifră în baza q,

rezultă că 0a se obţine ca rest al împărţirii numărului 10N la q,

iar )0(10N este câtul acestei împărţiri. Procedăm analog cu expresia

)0(10N şi obţinem

q

aN

q

aaqaqaN n

nn

n1)1(

101

23

120

10 ...

.

Printr-un raţionament similar deducem că cifra 1a se obţine

ca rest al împărţirii câtului anterior )0(10N la baza q.

În general, obţinem în ordine cifrele 0a , 1a , 2a , …, na pentru fiecare pas i aplicat relaţiei

q

aN

q

N iii

)(10

110

, ni ...,,2,1,0 , unde 10

110 NN .

Algoritmul de conversie se termină când se obţine câtul )(

10iN egal cu zero.

Exemple:

Convertim din baza 10 în baza 2, numerele 35 şi 3028 obţinute în exemplul precedent, aplicând algoritmul descris.

Page 34: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

32

35 2 3028 16 34 17 2 3024 189 16 1 16 8 2 4 176 11 1 8 4 2 13 0 4 2 2 0 2 1 0

Figura 2.1. Ilustrarea algoritmului de conversie a numerelor întregi din baza 10 în baza 2

Cifrele numerelor convertite se obţin citind de la sfărşit spre început resturile (cifrele încercuite). Se obţin rezultatele aşteptate: 210 10001135 şi 1610 43028 BD .

Conversia numerelor reale

Conversia părţii întregi a unui număr real se face după algoritmii prezentaţi mai sus. În continuare prezentăm conversia părţii fracţionare a unui număr real. Partea fracţionară Fq a unui număr real pozitiv este:

.......0 321 mq aaaaF

Conversia părţii fracţionare a unui număr real pozitiv dintr-o bază oarecare q în baza 10

Ca şi în cazul numerelor întregi, conversia dintr-o bază oarecare q în baza 10 a unei fracţii Fq se face utilizând dezvoltarea sa polinomială, adică:

......22

1110

m

m qaqaqaF

Exemple:

1021

16

104321

2

64453.0165105.0

6875.0212120211011.0

AA

Conversia părţii fracţionare a unui număr real pozitiv din baza 10 într-o bază oarecare q

Pentru a afla cifrele numărului F10 în baza q se porneşte de

Page 35: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

33

la dezvoltarea sa polinomială, adică:

(2) ......22

1110

m

mqaqaqaF

Înmulţind relaţia (2) cu q obţinem:

...... 112110

m

mqaqaaFq

şi deci 101 Fqa unde prin x înţelegem partea întreagă a numărului x.

Cifra a-2 se obţine printr-un procedeu analog pornind însă de la fracţia:

...... 112

)1(10

m

mqaqaF

Deci )1(102 Fqa şi analog )2(

103 Fqa ,

unde,

...... 224

13

)2(10

m

m qaqaqaF

şi aşa mai departe.

Dacă există un număr i întreg astfel încât )(

10iF este număr

întreg, atunci algoritmul se opreşte. În caz contrar fracţia este periodică.

Exemple:

Fie numărul 64453.010 F . Se doreşte conversia acestuia în baza 16. Aplicăm procedeul explicat mai sus şi avem:

551631248.0

1664453.0

2

1

a

Aa

Se obţine rezultatul 165.0 A .

Considerăm fracţia 0.7 şi dorim conversia ei în baza 4. Obţinem succesiv:

08.042.0

32.348.0

28.247.0

3

2

1

a

a

a

08.042.0

32.348.0

5

4

a

a

Se observă repetarea rezultatelor şi drept urmare obţinem fracţia periodică mixtă 0.2(30)4.

Page 36: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

34

✎ Convertiţi în bazele 2, 8, 16 numerele în baza 10:

62.845, 261.38 şi 1254.2968.

Procedee de conversie rapidă între bazele 8, 16 şi baza 2

Conversia binar – octal

Fiecare din cifrele bazei 8 se reprezintă în baza 2 (pe baza algoritmilor prezentaţi) prin configuraţiile binare următoare, numite triade ( Tabelul 2.1):

Tabelul 2.1. Triadele corespunzătoare reprezentării în baza 2 a cifrelor din baza 8

octal binar

0 0 0 0 1 0 0 1 2 0 1 0 3 0 1 1 4 1 0 0 5 1 0 1 6 1 1 0 7 1 1 1

Conversia rapidă unui număr din octal în binar se face scriind în locul fiecărei cifre octale triada corespunzătoare.

Exemplu:

Numărul 47.368 se scrie în baza 2 făcând înlocuirile:

4 cu 1 0 0 7 cu 1 1 1 3 cu 0 1 1 6 cu 1 1 0

Se obţine 28 011110.10011136.47 .

triade

Page 37: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

35

Conversia rapidă a unui număr binar în octal se face astfel:

pentru partea întreagă se marchează triadele începând de la virgulă spre stânga;

pentru partea fracţionară se marchează triadele începând de la virgulă spre dreapta;

fiecare triadă este înlocuită cu valoarea corespunzătoare din baza 8.

Exemplu:

1 111 101.011 101 12 = 175.3748

Conversia binar-hexazecimal

Prezentăm mai jos (Tabelul 2.2) valorile cifrelor hexazecimale în binar, numite tetrade.

Tabelul 2.2. Tetradele corespunzătoare reprezentării în baza 2 a cifrelor din baza 16

hexazecimal binar hexazecimal binar

0 0 0 0 0 9 1 0 0 1 1 0 0 0 1 A 1 0 1 0 2 0 0 1 0 B 1 0 1 1 3 0 0 1 1 C 1 1 0 0 4 0 1 0 0 D 1 1 0 1 5 0 1 0 1 E 1 1 1 0 6 0 1 1 0 F 1 1 1 1 7 0 1 1 1 8 1 0 0 0

În conversia binar-hexazecimal rolul triadelor este luat de tetrade, iar paşii algoritmului sunt identici cu cei ai conversiei binar-octal.

Exemplu :

1111000.1110 11112 = 78.ED16

Observaţie. Procedeele de conversie prezentate, binar-octal şi binar-hexazecimal se fac mecanic, fără calcule, şi din acest motiv sunt foarte rapide. O altă raţiune pentru care sunt preferate

Page 38: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

36

bazele 8 şi 16 bazei 2 rezultă din aspectul evident al faptului că numerele binare, datorită lungimii lor, sunt mai greu de manipulat.

Reguli de calcul în baza 2 şi baza 8

În baza 2 adunarea şi înmulţirea se fac conform tabelului 2.3:

Tabelul 2.3. Regulile de calcul pentru adunare şi înmulţire în baza 2

+ 0 1 x 0 1 0 0 1 0 0 0 1 1 10 1 0 1

La adunare se observă că apare cifra de transport (bitul 1 din 10 = 1+1).

În baza 8 tabelele pentru adunare şi înmulţire sunt după cum urmează (Tabelul 2.4):

Tabelul 2.4. Regulile de calcul pentru adunare şi înmulţire în baza 8

+ 0 1 2 3 4 5 6 7 0 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 10 2 2 3 4 5 6 7 10 11 3 3 4 5 6 7 10 11 12 4 4 5 6 7 10 11 12 13 5 5 6 7 10 11 12 13 14 6 6 7 10 11 12 13 14 15 7 7 10 11 12 13 14 15 16

x 0 1 2 3 4 5 6 7 0 0 0 0 0 0 0 0 0 1 0 1 2 3 4 5 6 7 2 0 2 4 6 10 12 14 16 3 0 3 6 11 14 17 22 25 4 0 4 10 14 20 24 30 34 5 0 5 12 17 24 31 36 43 6 0 6 14 22 30 36 44 52 7 0 7 16 25 34 43 52 61

Page 39: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

37

� Test de autoevaluare

2.1. Care este reprezentarea în baza 2 şi 16 a numerelor: 3265, 28, 293 şi 526 scrise în baza 10?

2.2. Care este valoarea în baza 10 a numerelor binare: 00110101, 01110101, 00010011?

2.3. Convertiţi în baza 10 numerele: 0. 111012, 11.0101112, 10.01112, A3.26716, ABA.BA16.

2.4. Convertiţi în bazele 2, 8, 16 numărul 30.310.

2.5. Convertiţi în baza 8 numărul 110111001.10102.

2.6.Convertiţi în baza 2 numerele A4216, 148.F16 şi 331.508.

Reprezentarea informaţiei în calculator

Reprezentarea numerelor întregi

Reprezentarea numerelor întregi în memoria calculatorului se poate realiza în trei moduri:

reprezentare în modul şi semn (cod direct);

reprezentare în complement faţă de 1 (cod invers);

reprezentare în cod complement faţă de 2 (cod complementar).

În reprezentarea în modul şi semn (cod direct), bitul din extremitatea stângă este folosit pentru codificarea semnului. Convenţia este următoarea:

dacă numărul este pozitiv, bitul de semn trebuie să aibă valoarea 0;

dacă numărul este negativ, bitul de semn trebuie să aibă valoarea 1.

Exemplu. Cifrele 6 şi –6 sunt reprezentate în binar pe 8 biţi sub forma:

011000016

011000006

Modul de reprezentare în modul şi semn are următoarele

Page 40: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

38

dezavantaje:

există două reprezentări pentru zero. De exemplu, într-o reprezentare pe 8 biţi avem:

00 000001 0

000000000

Acest lucru creează probleme în realizarea circuitelor electronice pentru adunare, deoarece:

biţii de semn trebuie trataţi separat cand se efectuează operaţii;

trebuie definită operaţia de scădere a numerelor astfel reprezentate.

Complementul faţă de 1 (cod invers) al unui număr reprezentat în binar se obţine prin înlocuirea fiecărei cifre binare cu complementul ei faţă de 1. Complementul faţă de 1 al cifrei 0 este 1, iar al cifrei 1 este 0.

Exemplu. Valorile 6 şi –6 sunt reprezentate în binar, pe 8 biţi sub forma:

100111116

011000006

Operaţia de scădere se reduce la o operaţie de adunare prin reprezentarea scăzătorului în cod invers. Dacă rezultatul este negativ atunci el va fi reprezentat tot în cod invers. Dacă apare transport în stânga rangului de semn aceasta se va aduna la rangul cel mai puţin semnificativ (cel mai din dreapta) al rezultatului.

Exemple:

Într-o reprezentare pe 8 biţi operaţia 6-5 se efectuează astfel:

210 011000006 în cod direct

210 101000005 în cod direct

210 010111115 în cod invers

Page 41: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

39

(+6) 0 0 0 0 0 1 1 0 +(-5) +1 1 1 1 1 0 1 0 1 1 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1

Se observă cum transportul din stânga rangului de semn se adună la ultimul bit.

În aceeaşi reprezentare pe 8 biţi operaţia 6-7 se efectuează astfel:

(+6) 0 0 0 0 0 1 1 0 +(-7) +1 1 1 1 1 0 0 0 - 1 1 1 1 1 1 1 1 0

Se observă că 1 1 1 1 1 1 1 0 este reprezentarea cifrei 1 în cod invers pe o configuraţie de 8 biţi.

Observaţie. Şi în acest tip de reprezentare se menţine dezavantajul reprezentării valorii zero sub două forme, întâlnit la codul direct.

Exemplu:

(+4) 0 0 0 0 0 1 0 0+(-4) 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1

Se observă cele două reprezentări pentru zero

0 0 0 0 0 0 0 0şi

1 1 1 1 1 1 1 1

Pentru a înţelege reprezentarea în cod complementar să scriem, de exemplu, operaţia 5-3 sub forma

21012107510)310(5 .

Observăm că rezultatul se poate obţine în felul următor:

se adună la descăzut complementul faţă de 10 al scăzătorului, adică se face operaţia 1275

Page 42: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

40

rezultatul final (2) se obţine ignorând transportul care apare (adică 1).

Acest exemplu sugerează ideea ca un număr negativ în binar să fie reprezentat în cod complement faţă de 2 (cod complementar). Complementul faţă de 2 al unui număr se obţine astfel:

se obţine complementul faţă de 1 al numărului;

se adună valoarea 1 la rangul cel mai semnificativ al numărului.

Dacă apare transport la stânga rangului de semn acesta se ignoră, iar dacă rezultatul este negativ aceasta este reprezentat tot în cod complementar faţă de 2.

Observaţie. Folosind acest cod, zero are o unică reprezentare.

Exemplu:

7 are valoarea 0 0 0 0 0 1 1 1 în binar

7 are codul invers 1 1 1 1 1 0 0 0

-7 are codul complementar 1 1 1 1 1 0 0 1

(+7) 0 0 0 0 0 1 1 1 +(-7) +

1 1 1 1 1 0 0 1

0 1 0 0 0 0 0 0 0 0 se neglijează

Se constată unicitatea reprezentării pentru zero.

Calculatoarele moderne utilizează pentru reprezentarea numerelor întregi negative codul complementar.

Reprezentarea numerelor reale

Reprezentarea numerelor reale se poate face sub două moduri:

în virgulă fixă;

în virgulă mobilă.

Page 43: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

41

Reprezentarea în virgulă fixă

În acest tip de reprezentare, virgula care desparte partea întreagă de partea subunitară are poziţie fixă. De exemplu, dacă într-o reprezentare pe 8 biţi, virgula este plasată după 4 biţi, numărul N reprezentat în baza 2 are valorile extreme după cum urmează:

1111.11110000.0000 2 N

sau, corespunzător în baza 10,

9375.150.0 10 N .

În cazul în care primul bit este folosit pentru codificarea semnului, plaja de reprezentare pentru N10 va fi:

9375.79375.8 10 N .

Se observă că puterea de reprezentare a numerelor reale în cazul folosirii virgulelor fixe este extrem de mică. Din acest motiv folosirea virgulei fixe în calculatoarele moderne se face numai după ultimul rang, reprezentându-se practic în această manieră numai numerele întregi.

Reprezentarea în virgulă mobilă

În reprezentarea în virgulă mobilă se porneşte de la un rezultat matematic cunoscut şi anume: orice număr real poate fi reprezentat în mod unic sub forma (numită virgulă mobilă normalizată):

bqa , unde 1||/1 aq , 2q număr natural, b număr întreg.

q este baza de reprezentare,

a se numeşte mantisă, b se numeşte exponent.

De exemplu, numărul 208.1423 în baza 10 are reprezentarea în virgulă mobilă normalizată:

4101423208.0 .

Aici b are valoarea 4, q valoarea 10, iar mantisa 1423208.0a .

Condiţia 1||/1 aq este esenţială pentru asigurarea

Page 44: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

42

unicităţii reprezentării. Pentru 10q condiţia se scrie 1||1.0 a , ceea ce este echivalent cu faptul că prima cifră

după virgulă să fie diferită de 0. În cazul în care se renunţă la această restricţie asupra mantisei, există o infinitate de reprezentări echivalente. De exemplu, numărul de mai sus se poate scrie echivalent:

5424 1001423208.0,101423208,1023208.14,101423208.0 etc.

Denumirea de virgulă mobilă vine tocmai de la deplasarea virgulei, funcţie de valoarea exponentului.

Pentru a aduna două numere scrise sub formă normalizată trebuie ca ele să aibă acelaşi exponent. Dacă exponenţii sunt diferiţi, numărul cu exponent mai mic este scris în virgulă mobilă nenormalizată astfel încât noul exponent obţinut să fie egal cu cel mai mare dintre cei doi exponenţi. Înmulţirea se face înmulţind mantisele şi adunând exponenţii.

Din cauza restricţiilor privind lungimea mantisei, aritmetica virgulei mobile diferă de aritmetica obişnuită.

Pentru a ilustra acest lucru, să presupunem că mantisei i se rezervă patru cifre zecimale şi să considerăm exemplele:

4

4434

106742.0

100210.0106532.01021.0106532.0

;

se observă că nu se pierde nici o cifră.

444 100001234.0106532.0101234.0106532.0

444 106533.0100001.0106532.0 ; se observă că se pierd ultimele trei cifre ale numărului

0001234.0 . 4444 101216.0102164.1105632.0106532.0 ;

se observă că se pierde ultima cifră a numărului 2164.1 datorită operaţiei de normalizare.

3314 101371.010137172.01021.0106532.0 ; se observă că se pierd ultimele două cifre ale numărului 0.137172.

Page 45: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

43

În programele în care calculele au un grad ridicat de complexitate, erorile se pot propagă, iar efectul este obţinerea unui rezultat afectat de erori. Acest efect nedorit se poate contracara prin utilizarea unor metode numerice speciale, care inhibă propagarea erorilor.

✎ Ce se înţelege prin virgulă mobilă normalizată?

Reprezentarea în virgulă mobilă se poate face sub două forme: reprezentarea în virgulă mobilă simplă precizie şi reprezentarea în virgulă mobilă dublă precizie.

Reprezentarea în virgulă mobilă simplă precizie se face pe 32 de biţi şi are structura:

32 31 … 24 23 … 1 S Caracteristică (c) Fracţie (f)

S reprezintă semnul numărului reprezentat, ocupă un bit (bitul 32), iar valorile sale au semnificaţia următoare:

0S când numărul reprezentat are semnul negativ;

1S când numărul reprezentat are semnul pozitiv.

Caracteristica c ocupă 8 biţi (biţii 24-31) şi conţine valoarea exponentului la care se adaugă valoarea 127, adică:

127 ec .

Folosirea acestei formule permite economisirea unui bit care ar fi necesar pentru memorarea semnului exponentului. Zona de 8 biţi destinată caracteristicii este considerată totdeauna pozitivă şi deci:

255120 8 c .

Din acest motiv, valorile minime şi maxime ale exponentului sunt –127 respectiv 128.

Cu alte cuvinte:

dacă 127c atunci 0e ;

dacă 127c atunci 0e .

Fracţia (f) este reprezentată în zona biţilor 1-23. Alinierea se

Page 46: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

44

face la stânga, iar dacă este cazul spaţiile libere se completează cu cifra zero.

Reprezentarea în virgulă mobilă dublă precizie se face pe 64 de biţi şi are structura:

64 63 … 53 52 … 1 S Caracteristică (c) Fracţie (f)

Câmpurile din structură au aceeaşi semnificaţie ca la reprezentarea în virgulă mobilă simplă precizie. Diferă doar lungimea caracteristicii (11 biţi) şi a fracţiei (52 biţi). Relaţia dintre exponentul e şi caracteristica c este:

1023 ec

şi evident c are drept limite de reprezentare

2047120 11 c .

Valorile minime şi maxime ale exponentului sunt –1023 şi 1024, ceea ce arată o putere de reprezentare deosebit de mare în cazul folosirii virgulei mobile în dublă precizie.

Reprezentarea caracterelor alfanumerice

Calculatoarele prelucrează atât informaţie numerică, cât şi informaţie nenumerică (texte). Pentru reprezentarea informaţiei numerice se folosesc algoritmii şi convenţiile prezentate.

Reprezentarea informaţiei nenumerice (litere mari şi mici, cifre zecimale, semne de punctuaţie, operatori aritmetici şi logici, simboluri pentru controlul comunicaţiei şi editare etc.) se face pe baza unor coduri. Aceste coduri asociază fiecărui semn utilizat o configuraţie binară. Pentru o mulţime de m semne sunt necesare 2n configuraţii binare unde n este cel mai mic număr natural cu proprietatea mn 2 . De exemplu, fiecare element al unei mulţimi de 30 de semne poate fi codificat utilizând una din cele

3225 configuraţii binare distincte, cu lungimea de la 5 biţi. Se observă că două din cele 32 configuraţii binare posibile nu sunt folosite (sunt cuvinte fără sens).

Convenţia de reprezentare a caracterelor alfanumerice, în calculatoarele moderne este codul ASCII (American Standard

Page 47: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

45

Code for Information Interchange). O configuraţie binară din codul ASCII are 8 biţi (se pot codifica 25628 semne). Plajele de reprezentare sunt următoarele:

0 – 31 : codificarea caracterelor de control.

32 – 127: codificarea literelor mari şi mici, a cifrelor zecimale şi a semnelor speciale.

128 – 255: codificarea semnelor cu utilizare specială.

Există şi alte coduri folosite în sistemele de calcul. Dintre acestea amintim codul EBCDIC (Extended Binary Coded Decimal Interchange Code).

� Test de autoevaluare

2.7. Care este reprezentarea în virgulă mobilă normalizată a numărului în baza 10, 207.022? Dar a numărului 0.00446?

2.8. Care este structura reprezentării în virgula mobilă simplă precizie?

a.

64 63 … 53 52 … 1 S Caracteristică (c) Fracţie (f)

b.

32 31 … 24 23 … 1 S Caracteristică (c) Fracţie (f)

c.

64 63 … 24 23 … 1 S Caracteristică (c) Fracţie (f)

2.9. Ce este codul ASCII?

Page 48: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

46

Răspunsurile testelor de autoevaluare

2.1. 326510 = 1100110000012 = CC116, 2810 = 111002 = 1C16, 29310 = 1001001012 = 12516, 52610 = 10000011102 = 20E16.

2.2. 53, 117, 19.

2.3. 0.90625, 3.359375, 2.4375, 163.150146484375, 2746.7265625.

2.4. 30.310 = 11110.0(1001)2 = 36.2(3146)8 = 1E.4(C)16.

2.5. 671.50.

2.6. 101001000010, 000101001000.1111, 001100110001.01010000

2.7. 0.207022 x 103, 0.446 x 10-2

2.8. b

2.9. Un cod de reprezentare a caracterelor alfanumerice.

Lucrare de verificare ...................................................✍

Realizaţi o sistematizare a cunoştinţelor dobândite în această unitate de învăţare.

Rezumat

Construcţia memoriei calculatoarelor fiind bazată pe utilizarea bistabililor, informaţia numerică se reprezintă în baza 2 sau în baze care sunt puteri ale acesteia (baza 8 şi baza 16). Pe de altă parte, valorile numerice pe care le furnizăm programelor sunt exprimate în baza 10, şi tot în baza 10 solicităm rezultatele acestor programe. Prin urmare, în operarea cu valori numerice au loc foarte frecvent conversii în şi din baza 10 în bazele 2, 8 sau 16. Această unitate de învăţare descrie conversiile numerelor întregi şi reale dintr-o bază de numeraţie în alta şi reprezentarea în calculator a informaţiilor numerice şi alfanumerice.

Reprezentarea numerelor întregi se poate realiza în trei moduri:

Page 49: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

47

reprezentare în modul şi semn (cod direct);

reprezentare în complement faţă de 1 (cod invers);

reprezentare în cod complement faţă de 2 (cod complementar).

Reprezentarea utilizată de calculatoarele moderne, care deţine avantaje faţă de celelalte reprezentări, este reprezentarea în cod complementar.

Reprezentarea numerelor reale se poate face în virgulă fixă sau în virgulă mobilă. În cazul folosirii virgulei fixe puterea de reprezentare este foarte redusă, spre deosebire de cazul folosirii virgulei mobile, bazate pe exprimarea numerelor (reale) în virgulă mobilă normalizată.

După dimensiunea şi structura spaţiului de memorie utilizat, reprezentarea în virgulă mobilă poate fi: reprezentare în virgulă mobilă simplă precizie (pe 32 de biţi) sau reprezentare în virgulă mobilă dublă precizie (pe 64 de biţi).

Informaţia nenumerică (litere, cifre zecimale, semne de punctuaţie, operatori aritmetici şi logici, simboluri pentru controlul comunicaţiei şi editare etc.) se reprezintă pe baza unor coduri care asociază fiecărui semn o configuraţie binară. Cel mai cunoscut astfel de cod este codul ASCII.

Bibliografie

1. Gheorghe Barbu, Ion Văduva, Mircea Boloşteanu, Bazele

Informaticii, Editura Tehnică, Bucureşti, 1997.

2. A. Petrescu, N. Ţăpuş, T. Moisa, Gh. Rizescu, V. Hărăbor, N.

Mârşanu, Tr. Mihu, abc de calculatoare personale şi … nu doar atât

…, Vol.I, Ed. Tehnică, Bucureşti, 1990.

3. L. Livovschi, Bazele Informaticii, Editura Didactică şi Pedagogică,

Bucureşti, 1981

Page 50: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

 

Page 51: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

49

UI3. Rezolvarea problemelor cu calculatorul

Obiectivele unităţii de învăţare – pag 49

Etapele rezolvării problemelor cu calculatorul – pag 49

Tipuri de date şi operaţii elementare – pag 53

Test de autoevaluare – pag 55

Structuri de date – pag 55

Test de autoevaluare – pag 63

Algoritmi – caracteristici şi descriere – pag 63

Test de autoevaluare – pag 79

Răspunsurile testelor de autoevaluare – pag 79

Lucrare de verificare – pag 80

Rezumat – pag 80

Bibliografie – pag 82

Obiectivele unităţii de învăţare

cunoaşterea etapelelor rezolvării problemelor cu calculatorul

cunoaşterea tipurilor de date elementare şi a celor structurate utilizate în rezolvarea problemelor

abilitatea de a proiecta un algoritm corect în pseducod sau schemă logică pentru probleme elementare

Durata: 8 ore

Etapele rezolvării problemelor cu calculatorul

Activitatea de rezolvare a problemelor cu calculatorul se bazează pe talent, creativitate şi experienţă. Evident, în condiţiile creşterii complexităţii problemelor de rezolvat, în scopul măririi eficienţei acestei activităţi, calităţile enumerate devin cu atât mai

Page 52: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

50

necesare. Totuşi, acest lucru nu este suficient. În timp, viaţa a impus o nouă abordare a activităţii de rezolvare a problemelor cu calculatorul. Dorinţa şi nevoia de a obţine eficienţă în acest domeniu au condus la conturarea unor etape bine definite, cu metode şi instrumente de lucru specifice. Astfel, o activitate care în trecut era văzută mai ales ca un meşteşug sau o artă, la ora actuală este abordată tot mai des şi sub aspectul ei de activitate sistematică.

O listă a etapelor pe care programatorul le parcurge în mod uzual în rezolvarea problemelor poate fi privită ca un important ajutor în obţinerea unor rezultate bune. Evident, etapele pe care le enumerăm mai jos trebuie privite mai degrabă ca un ghid, în sensul că parcurgerea lor conştiincioasă nu va conduce în mod obligatoriu la rezultatul scontat. A ignora aceste etape este însă la fel de dăunător cu a exagera importanţa lor. În general, se acceptă ca fiind necesare următoarele faze în rezolvarea unei probleme cu calculatorul:

1. analiza problemei;

2. proiectarea algoritmului de rezolvare;

3. descrierea algoritmului;

4. codificarea algoritmului (obţinerea programului);

5. testarea programului;

6. execuţia programului, obţinerea rezultatelor şi interpretarea lor;

7. întreţinerea programului.

În prima etapă, etapa de analiză a problemei se are în vedere stabilirea modelului logico-matematic al problemei. Se identifică cu claritate funcţia (sau funcţiile) problemei, se stabilesc datele de intrare şi datele de ieşire. Această etapă are ca scop înţelegerea cât mai exactă a problemei de rezolvat.

Etapa de proiectare a algoritmului are ca scop stabilirea algoritmului de rezolvare a problemei. Este etapa în care se precizează operaţiile pe care trebuie să le execute un calculator pentru a rezolva problema. În cazul problemelor complexe este recomandabilă descompunerea problemei în subprobleme care pot fi rezolvate mai uşor. Această tehnică, numită top-down (de

Page 53: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

51

sus în jos) va avea ca efect final obţinerea unui sistem de module conectate între ele după logica impusă de rezolvarea problemei. Practic, într-o primă fază se obţine o schiţă generală de rezolvare care se rafinează succesiv până la obţinerea comenzilor necesare execuţiei pe calculator. Împărţirea problemei în subprobleme prezintă avantajul lucrului eficient în echipă - subproblemele pot fi rezolvate simultan de către membrii echipei. De asemenea, obţinerea modulelor program prin implementarea fiecărei subprobleme uşurează munca de depanare (depistare a erorilor) şi de întreţinere a programului.

Pe măsură ce creşte complexitatea problemelor de rezolvat, creşte şi dificultatea de a descrie algoritmii cât mai exact, fără ambiguităţi, utilizând un limbaj natural. Din acest motiv s-au imaginat diferite forme de descriere (diagramă de structură, scheme logice, pseudocod etc.) care pe de o parte permit reprezentarea corectă a algoritmilor într-o manieră prietenoasă, naturală, iar pe de altă parte facilitează codificarea cu uşurinţă a acestuia într-un limbaj de programare.

Deşi foarte multe limbaje de programare au un caracter universal, totuşi anumite trăsături ale problemei de rezolvat pot recomanda un anumit tip de limbaj. Astfel, pentru o problemă în care predomină prelucrările numerice se va alege un limbaj puternic în acest sens, cum ar fi Fortran, Basic, Pascal etc. Pentru probleme în care operaţiile aritmetice au complexitate redusă, dar predomină prelucrările nenumerice (sortare, căutare, reuniune de fişiere etc.) se va alege un limbaj orientat pe aceste probleme (Cobol, dBase, FoxPro etc.). Dacă problema necesită prelucrări ale unor baze de cunoştinţe se pot folosi limbaje speciale ca Prolog, Lisp, Ada etc.

În etapa de codificare o importanţă deosebită trebuie acordată stilului de programare. În general se consideră că stilul de programare este bun dacă îndeplineşte condiţii cum ar fi:

programul este însoţit de documentaţia de analiză şi proiectare care trebuie să conţină elementele minimale: descrierea funcţiilor programului, diagrama de structură (schiţa generală a programului), tabele de descriere a variabilelor de intrare şi ieşire etc.;

există procedee de validare a datelor. Se pot utiliza diverse procedee (sume de control, coduri autocorectoare,

Page 54: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

52

intervale de apartenenţă, scrierea cu ecou, verificarea unor relaţii existente între variabilele de intrare etc.);

programul este lizibil. Acest lucru se poate realiza prin scrierea indentată (în fierăstrău) a liniilor de program, prin alegerea unor nume sugestive pentru identificatori, prin folosirea (neabuzivă) a comentariilor etc.

Etapa de testare este etapa în care se elimină erorile programului. Erorile pot fi de natură sintactică sau de natură logică. Eliminarea erorilor de natură sintactică se face în urma listelor de erori afişate de compilatoare. Stabilirea corectitudinii din punct de vedere logic a programului se poate face prin demonstraţie matematică sau prin testarea programului folosind date de test. Deoarece demonstrarea matematică a corectitudinii este dificilă chiar şi pentru programe mici, metoda uzuală este metoda datelor de test. Datele de test trebuie alese cu grijă, astfel încât să se poată valida toate ramurile programului. Dacă sunt erori se încearcă localizarea acestora folosind diverse metode.

O metodă rapidă constă în afişarea unor mesaje din loc în loc, prin analiza cărora se poate stabili zona unde se află eroarea. Mediile moderne de programare, care asistă programatorul în punerea la punct a programului, oferă şi alte facilităţi de depanare, cum ar fi: ferestre de observare în timpul execuţiei a unor variabile şi expresii, execuţia pas cu pas a liniilor de program, puncte de oprire a execuţiei etc. Odată îndepărtate erorile de sintaxă şi de logică, programul poate fi executat. Rezultatele obţinute sunt analizate, iar în urma interpretării lor se iau deciziile corespunzătoare.

✎ Descrieţi câteva trăsături ale unui bun stil de

programare.

În mod normal programele sunt proiectate spre a fi rulate (executate) la diverse intervale de timp, pe seturi de date diferite. Aplicaţia informatică obţinută din unul sau mai multe programe trebuie privită şi ca un produs care suferă în timp un proces de uzură morală. Activitatea de întreţinere a programului constă în modificări ale programelor ori de câte ori este nevoie, realizate tocmai în scopul de a menţine aplicaţia la zi. Depanarea şi întreţinerea programelor sunt două din activităţile care pun în

Page 55: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

53

lumină, în cel mai înalt grad, importanţa unui stil bun de programare. Este evident că aceste activităţi vor fi îngreunate dacă programele nu sunt suficient documentate, dacă lipsesc comentariile, scrierea este neindentată, iar logica programului se realizează prin folosirea abuzivă a instrucţiunilor de salt.

✎ Care sunt etapele de rezolvare ale unei probleme cu

calculatorul? Descrieţi pe scurt fiecare etapă.

Tipuri de date şi operaţii elementare

În acest paragraf vom prezenta, într-o manieră generală, operaţiile elementare şi obiectele pe care le întâlnim de obicei într-un limbaj de programare.

Datele sunt obiectele folosite într-un limbaj de programare şi pot fi de două tipuri: date elementare şi date structurate. Datele elementare sunt recunoscute de calculator şi se referă, în majoritatea cazurilor la următoarele tipuri de date:

date numerice;

date logice;

date alfanumerice.

Datele numerice pot fi întregi sau reale.

Datele întregi pot fi reprezentate în sistemul zecimal (de exemplu -64, 9569, +311) sau în alte baze de numeraţie (de exemplu în sistemul hexazecimal: AD4, 6E3C etc.).

Datele reale se reprezintă în multe limbaje de programare sub două forme:

în notaţie uzuală (notaţie cu punct), unde virgula e reprezentată printr-un punct (exemplu -6.43, 82.1, +0.6);

în notaţie ştiinţifică (exponenţială). În acest caz

succesiunile bE sau be au semnificaţia de b10 . De exemplu, 0725.3,0252.0 eE înseamnă 21052.0 ,

respectiv 71025.3 .

Operaţiile folosite în mod obişnuit sunt operaţii de adunare, scădere, înmulţire, împărţire, ridicare la putere.

Page 56: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

54

Datele logice se referă la valorile logice (numite şi booleene) adevărat şi fals. Operaţiile permise sunt cele cunoscute: conjuncţia (ŞI), disjuncţia (SAU), negaţia (NU), SAU exclusiv etc. Dacă notăm cu 1 valoarea adevarat şi cu 0 valoarea fals, rezultatele acestor operaţii sunt după cum urmează (Tabelul 3.1):

Tabelul 3.1. Tabelul operaţiilor de lucru cu date logice

a b a ŞI b a SAU b NU a a SAU exclusiv b 0 0 1 1

0 1 0 1

0 0 0 1

0 1 1 1

1 1 0 0

0 1 1 0

Datele alfanumerice se referă la caractere şi şiruri de caractere. Asupra acestor tipuri de date sunt permise operaţii cum ar fi comparaţia, copierea, concatenarea (alipirea) etc. De exemplu, prin concatenarea şirurilor ’Ploieşti’ şi ’-Vest’ rezultă şirul ’Ploieşti-Vest’.

✎ Daţi exemple de date întregi, reale, alfanumerice.

Se observă că un tip de date este caracterizat printr-o mulţime de valori şi o mulţime de operaţii care li se aplică.

În cadrul unui algoritm, datele se prezintă sub forma variabilelor şi a constantelor. Constantele nu-şi modifică valoarea în timpul execuţiei algoritmului. De exemplu, 6.29 este o constantă reală. O variabilă îşi poate modifica valoarea pe parcursul execuţiei algoritmului. Numele unei variabile se asociază cu adresa unei celule, iar valoarea ei la un moment dat, cu conţinutul acesteia. Variabilele pot fi clasificate în variabile statice şi variabile dinamice. În cazul variabilelor statice numelui variabilei i se asociază adresa unei locaţii de memorie pe toată durata execuţiei algoritmului. Valoarea variabilei este dată de conţinutul acestei locaţii la un moment dat. De exemplu, atribuirea: 3x se poate schiţa grafic sub forma:

Prin atribuirea 7x conţinutul locaţiei asociate variabilei x se schimbă în 7, conform schiţei:

3 x  

Page 57: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

55

Unei variabile dinamice i se poate asocia pe parcursul execuţiei unui algoritm diferite adrese. O dată fixată adresa celulei asociate se poate prelucra conţinutul (informaţia propriu-zisă) din celulă.

în cazul static asocierea nume - variabilă adresă celulă este fixă (statică), conform schiţei

în cazul dinamic, asocierea nume - variabilă adresă celule este variabilă (dinamică), după cum sugerează schema următoare:

Datele avute în vedere până acum sunt date elementare, indivizibile în raport cu operaţiile pe care le prelucrează.

Expresiile sunt combinaţii valide sintactic de date (operanzi) şi operaţii (operatori).

� Test de autoevaluare

3.1. Ce se înţelege prin variabile statice?

3.2. Ce se înţelege prin variabile dinamice?

Structuri de date

Abordarea datelor sub aspectul lor elementar este în foarte multe situaţii nesatisfăcătoare. De foarte multe ori, este preferabil sau chiar imperios necesar ca datele să fie privite drept

3 x

7

3 s  legătură

statică

d

Page 58: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

56

componente ale unor structuri de date mai complexe. Structurile de date folosite frecvent în algoritmi sunt: tabloul, înregistrarea, lista liniară simplu înlănţuită, lista liniară dublu înlănţuită, stiva, coada, arborele şi graful.

Tabloul reprezintă o colecţie omogenă de date (de acelaşi tip, numit tip de bază). Tablourile modelează vectori, matrici, masive multidimensionale. Accesul la elementele unui tablou se face folosind indicii elementelor. De exemplu, componentele haşurate ale vectorului a şi ale matricii b din figura 16 se desemnează prin a[3] şi b[1][2]. Numerele 3, 1 şi 2 dintre parantezele pătrate sunt indici. Indicele 3 desemnează a 3-a componentă din şirul de componente a[1], a[2], a[3], a[4], iar indicii 1 şi 2 se referă la elementul aflat pe linia 1 şi coloana 2 din matricea b de dimensiune 3x4.

b

a

Figura 3.1. Figurarea componentelor a[3] şi b[1][2] din tablourile a şi b

Variabilele ia , 41 i şi jib , 31 i , 41 j se numesc variabile indexate. Notaţia indicelui şi implicit folosirea tablourilor are o importanţă covârşitoare în prelucrarea datelor. Pentru a ilustra acest lucru, să presupunem că vrem să calculăm suma a n numere reale, cu n cunoscut. Dacă n = 4 atunci, reprezentând cele 4 numere prin a, b, c şi d, vom avea algoritmul:

Citeşte a, b, c, d

dcbas Scrie s Stop

Dacă n are valoare mare (de exemplu 100), mergând pe aceeaşi idee, ar trebui să avem 100 de variabile şi să le prelucrăm conform algoritmului de mai sus. Evident, acest lucru este de neimaginat. Soluţia constă în a folosi n = 100 de variabile

Page 59: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

57

indexate, xi, ni ,1 şi de a calcula suma

n

iix

1 folosind o

structură iterativă de control.

✎ Caracterizaţi tipul de date tablou. Daţi câteva exemple.

Înregistrările modelează colecţii neomogene de date. De exemplu, se presupunem că pentru fiecare persoană a unui colectiv ne interesează datele: nume (tip alfanumeric), vârstă (tip întreg), salariu (tip real), sex (tip boolean).

Pentru o persoană, datele de tip diferit pot fi reunite într-o înregistrare ca în variabila înregistare info (Figura 3.2):

nume vârstă salariu sex info Ionescu 52 7 633 1

Figura 3.2. Ilustrarea unei înregistrări cu patru câmpuri

nume, vârstă, salariu şi sex se numesc câmpuri. Referirea la un câmp se face folosind construcţia

numevariabila.numecamp

De exemplu, info.nume se referă la şirul ’Ionescu’, nume.varsta la valoarea 52 etc.

✎ Daţi câteva exemple de înregistrări.

În mod natural, listele de obiecte se pot memora în tablouri unidimensionale (numite vectori). De exemplu, lista de persoane Ionescu, Popescu, Georgescu, Vasilescu poate fi memorată în vectorul persoane:

persoane Ionescu Popescu Georgescu Vasilescu …

Folosind structura tablou, două elemente vecine din listă sunt memorate la adrese vecine (de exemplu, vecinii ’Popescu’ şi ’Georgescu’ sunt memorate la adresele vecine 2 şi 3).

Această variantă de implementare a listelor (numită statică) are avantajul unei parcurgeri rapide în ambele sensuri, în orice

Page 60: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

58

punct ne-am afla. Dificultatea apare la eliminarea sau adăugarea unui element nou în listă. Presupunând că vectorul în care se memorează lista are o dimensiune suficientă, introducerea persoanei ‘Marinescu’ în listă pe poziţia a 2-a implică deplasarea subşirului ‘Popescu’, ‘Georgescu’, ‘Vasilescu’ cu o poziţie spre dreapta conform schiţei din Figura 3.3.

Marinescu

Ionescu Popescu Georgescu Vasilescu ...

Figura 3.3. Adăugarea unui element într-un vector pe poziţia a doua

Deplasări, dar de data aceasta spre stânga, au loc şi atunci când se elimină elemente din listă. De exemplu, dacă din lista iniţială se doreşte scoaterea persoanei ‘Popescu’, acest lucru implică deplasări spre stânga cu o poziţie (Figura 3.4).

Ionescu Popescu Georgescu Vasilescu

Figura 3.4. Eliminarea elementului de pe poziţia a doua dintr-un vector

Aceste deplasări consumă timp calculator, a cărui mărime depinde de poziţia de inserţie sau de ştergere.

O soluţie de implementare care rezolvă elegant aceste probleme o reprezintă listele înlănţuite. Într-o listă înlănţuită elementele vecine din listă nu sunt memorate obligatoriu la adrese vecine. Lista de mai sus poate fi implementată dinamic sub forma unei liste simplu înlănţuite, ca în figura 20.

Ionescu Popescu Georgescu Vasilescu

Figura 3.5. Listă înlănţuită (listă implementată dinamic)

Orice element al listei (numit nod) este alcătuit din două câmpuri: un câmp unde se memorează informaţia propriu-zisă (‘Ionescu’, ‘Popescu’, ‘Georgescu’ etc.) şi un câmp de legătură,

Page 61: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

59

unde se memorează adresa următorului element din listă.

Evident, consumul de memorie este mai mare decât în cazul listelor liniare implementate prin vectori (static), însă avantajul apare la efectuarea operaţiilor de inserţie şi ştergere.

Astfel, inserţia în listă a persoanei ‘Marinescu’ se realizează, conform schiţei din Figura 3.6, foarte simplu, actualizând corespunzător legăturile.

Ionescu Popescu Georgescu Vasilescu

Marinescu

Figura 3.6. Adăugarea unui element într-o listă înlănţuită

Ştergerea persoanei ’Popescu’ din lista iniţială se face memorând în câmpul de adresă al primului nod (Ionescu) adresa “nodului” Georgescu. În felul acesta “nodul” Popescu rămâne izolat. Schiţa următoare ilustrează acest lucru (figura 22).

Ionescu Popescu Georgescu Vasilescu

Figura 3.7. Eliminarea elementului de pe poziţia a doua dintr-o listă

înlănţuită

Analizând lista simplu înlănţuită se observă că vizitarea vecinului drept se face cu uşurinţă, datorită sensului “stânga-dreapta” în care s-au făcut înlănţuirile. Realizarea legăturilor în ambele sensuri (“stânga-dreapta” şi “dreapta-stânga”) presupune ca fiecare nod să aibă două câmpuri de legătură. Ceea ce se obţine este lista dublu înlănţuită, ilustrată în figura 3.8.

Ionescu Popescu Georgescu Vasilescu

Figura 3.8. Listă dublu înlănţuită

Cu preţul introducerii unui câmp de legătură pentru fiecare câmp se obţine astfel o listă dinamică cu facilităţi de deplasare rapidă în ambele sensuri.

Page 62: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

60

În informatică, deosebit de utile sunt două tipuri particulare de liste: stiva şi coada.

Stiva este lista liniară în care adăugarea şi extragerea unui element se fac pe la acelaşi cap al listei. Se spune că operaţiile în stivă se fac după disciplina LIFO (Last In First Out: Ultimul Intrat Primul Ieşit). Pentru a face adăugări sau extrageri este nevoie să se ştie poziţia ultimului element din stivă. Aceasta este memorată într-o variabilă numită vârf. În figura de mai jos (Figura 3.9.) se prezintă schematic cele două implementări ale stivei– statică şi dinamică.

X

X

X

Figura 3.9. Ilustrarea stivei – implementare statică şi dinamică

Coada este lista liniară în care adăugarea elementelor se face pe la un cap, iar extragerea elementelor pe la celălalt cap. Disciplina specifică unei cozi este FIFO (First In First Out: Primul Intrat Primul Ieşit). În Figura 3.10 se ilustrează schiţa celor două modalităţi de implementare: statică şi dinamică.

X X X

Figura 3.10. Ilustrarea cozii – implementare statică şi dinamică

Variabilele prim şi ultim indică locul de unde se extrag, respectiv unde se adaugă elemente.

vârf

•••

vârf

prim ultim prim ultim

• ••

Page 63: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

61

✎ Caracterizaţi stiva. Daţi câteva exemple.

✎ Caracterizaţi coada. Daţi câteva exemple.

Deoarece foarte multe probleme se referă la obiecte aflate într-o relaţie de ordin ierarhic (piramidal), structura adecvată pentru descrierea acestor relaţii este arborele. Ca exemple de structuri arborescente menţionăm: structura unei armate, structura unei cărţi, structura unei firme, organizarea teritorială a unei ţări etc.

Schiţa de mai jos (Figura 3.11) ilustrează organizarea studenţilor până la nivel de grupe în cadrul specializătii Matematică al Facultăţii de Litere şi Ştiinţe.

Specializarea Matematică

Figura 3.11. Ilustrarea unei organizări arborescente

Elementele arborelui se numesc noduri. O poziţie aparte o ocupă nodul etichetat “Specializarea Matematică“, numit rădăcină. Păstrând analogia cu un arbore întors, nodurile Grupa1, Grupa2 etc. se numesc frunze (sau noduri terminale).

Implementarea arborilor se face de regulă dinamic, însă există şi variante de implementare statică.

✎ Caracterizaţi arborele. Daţi câteva exemple.

Pentru descrierea celor mai complexe relaţii dintre obiecte se utilizează grafurile. Un graf foarte cunoscut este reţeaua de căi ferate descrisă în mersul trenurilor. În acest caz, obiectele

An 2 An I

Grupa1

Grupa2

Grupa3

Grupa4

An 3

Grupa 5

Grupa6

An 4

Grupa 7

Grupa 8

Page 64: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

62

(nodurile) sunt staţiile de cale ferată, iar muchiile grafului sunt reprezentările căilor ferate care leagă staţiile. Alte exemple sunt: reţeaua de drumuri dintr-un oraş (nodurile sunt intersecţiile), reţeaua de calculatoare din universitate etc.

Când relaţiile dintre obiecte sunt nesimetrice modelarea se face cu ajutorul digrafurilor (directed graph – graf direcţionat). Mai jos (Figura 3.12), se prezintă digraful datoriilor existente între patru persoane: Cristina, Mihai, Andrei şi Alina. O săgeată de la nodul a la nodul b se traduce prin “a este dator lui b”.

Figura 3.12. Un exemplu de graf al datoriilor între patru persoane

Se observă că Andrei nu are datorii, la nici un membru al listei şi, în acelaşi timp, nici unul dintre aceştia nu-i este dator.

Implementarea unui graf se poate face atât static cât şi dinamic. În implementarea statică se foloseşte matricea de adiacenţă. Dacă vom considera nodurile ca fiind numerotate 1, 2, …, n matricea de adiacenţă A are semnificaţia următoare:

arc exista si între daca,1

arc existanu si între daca,0,

ji

jijiA .

De exemplu, considerând codificările Cristina1, Alina2, Mihai3, Andrei4, matricea de adiacenţă ataşată este:

A =

0 1 1 0

0 0 1 0

0 1 0 0

0 0 0 0

Mihai

Cristina Alina

Andrei

1

3

2

4

Page 65: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

63

Implementarea dinamică ia forma listelor de adiacenţă. Pentru exemplul considerat, lista de adiacenţă este următoarea:

Cristina

Alina

Mihai

Andrei

Figura 3.13. Implementare dinamică a grafului datoriilor

✎ Caracterizaţi graful. Daţi câteva exemple.

� Test de autoevaluare

3.3. Care este deosebirea dintre datele elementare şi structurile de date?

3.4. Care sunt principalele structuri de date utilizate în algoritmi?

3.4. Enumeraţi avantajele şi dezavantajele implementărilor statice şi dinamice ale listelor.

Algoritmi – caracteristici şi descriere

Deşi studiul algoritmilor reprezintă punctul central al ştiinţei calculatoarelor, totuşi, noţiunea de algoritm nu are încă o definiţie riguroasă. Intuitiv, un algoritm constă dintr-o mulţime ordonată de paşi executabili, descrişi fără ambiguitate, care definesc un proces finit. Cu ajutorul unui algoritm, un set de date de intrare, numit domeniul de definiţie al algoritmului este transformat într-un set de date de ieşire, numit domeniul de valori al algoritmului [4].

Alina

Mihai            

Alina

Mihai  

Page 66: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

64

Un algoritm se caracterizează prin:

generalitate – algoritmul furnizează rezultate pentru o mulţime de date de intrare;

finititudine – procesul trebuie să fie finit pentru a furniza un rezultat concret;

neambiguitate – fiecare pas se execută după reguli bine precizate.

Cerinţa ca paşii algoritmului să fie executabili se referă la capacitatea lor efectivă de a produce rezultate. De exemplu, comanda “sortează în ordine crescătoare toate numerele întregi pozitive” nu poate fi pasul unui algoritm, deoarece, a sorta toate numerele întregi pozitive (o infinitate) este o acţiune imposibilă.

✎ Ce este algoritmul ? Daţi câteva exemple.

O posibilitate de a descrie un algoritm este limbajul natural. Datorită polisemiei unor termeni, limbajul natural nu este potrivit pentru reprezentarea algoritmilor. De foarte multe ori, ambiguitatea prezentă într-un algoritm nu ţine de algoritmul însuşi ci de modul său de reprezentare. Gradul de detaliere în reprezentarea unui algoritm poate să aibă drept obiectiv nivelul operaţiilor executabile de către un calculator.

Descrierea rezultată este stufoasă şi puternic îngreunată de omniprezenţa structurilor de salt condiţionat şi necondiţionat.

Teorema de structură elaborată de Böhm şi Jacopini [4] furnizează justificarea conceptului de programare structurată implementat în limbajele de programare moderne. Conform acestei teoreme, orice algoritm cu un singur punct de început şi un singur punct de terminare a execuţiei poate fi reprezentat ca o combinaţie de trei structuri algoritmice fundamentale:

secvenţa de două sau mai multe operaţii;

decizia – alegerea unei operaţii din două alternative posibile;

iteraţia cu test iniţial – repetarea unei secvenţe cât timp este adevărată o anumită condiţie.

Se observă că cele trei structuri de control corespund unor procese naturale ale raţionamentului uman: enumerare, decizie,

Page 67: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

65

repetiţie. Acest lucru explică şi uşurinţa şi naturaleţea cu care sunt descrişi algoritmii folosind structurile de mai sus. De cele mai multe ori descrierea acestor structuri nu se face direct într-un limbaj de programare, ci se utilizează anumite convenţii de reprezentare. Foarte des întâlnite în practică sunt convenţiile de reprezentare sub formă de schemă logică şi pseudocod. Aceste convenţii au avantajul lipsei de formalism al limbajelor de programare (sunt mai intuitive) şi totodată permit reprezentarea cu claritate a structurilor algoritmice fundamentale.

Reprezentarea sub forma schemei logice foloseşte simboluri grafice cu înţeles prestabilit. Cele mai uzuale simboluri sunt (Figura 3.14):

Bloc terminal

Bloc intrare – ieşire

Bloc de calcul

Figura 3.14. Simbolurile grafice utilizate în schemele logice 

Pentru exemplificare să considerăm algoritmul de rezolvare al ecuaţiei de gradul I. Fie deci ecuaţia 0 bax . Variabilele de intrare sunt a şi b, iar variabila de ieşire este x. În limbaj natural, discuţia ecuaţiei de gradul I se poate face astfel:

dacă a ≠ 0 atunci ecuaţia este determinată şi are rădăcina x = - b/a ;

dacă a=0 atunci analizăm cazurile:

dacă b=0 ecuaţia devine 000 x adică ecuaţia e nedeterminată;

dacă b ≠ 0 ecuaţia devine 00 bx adică ecuaţia este imposibilă.

Se observă că, deşi exemplul este destul de simplu, descrierea în limbaj natural este relativ greoaie. O descriere

Bloc de decizie

Bloc conector

Săgeată

Page 68: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

66

simplă şi clară este realizată mai jos (Figura 3.15) cu ajutorul schemei logice.

Figura 3.15. Schema logică a algoritmului de rezolvare a ecuaţiei de grad I

În pseudocod, în locul simbolurilor grafice se utilizează cuvinte cu înţeles prestabilit, (cuvinte cheie). Astfel, descrierea algoritmului de rezolvare a ecuaţiei de gradul I ia forma:

Citeşte a, b Dacă a 0 atunci x -b/a Scrie x Altfel Dacă b 0 atunci Scrie “Ecuaţie nedeterminată“ Altfel Scrie “Ecuaţie imposibilă“

Stop

Start

Citeşte a, b

0a

0b

Scrie x

abx /

Scrie “Ecuaţie nedeterminată“

Scrie “Ecuaţie imposibilă“

Nu Da

Da Nu

Stop

Page 69: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

67

Se observă că modul de subordonare logică este sugerat cu ajutorul unor reguli de aliniere simple. Operaţii elementare cum sunt citirea, scrierea, atribuirea, sfârşit execuţie, se pot reprezenta sub forma:

Citeşte lista de variabile Scrie lista de expresii v expresie Stop

Modul de reprezentare al celorlalte operaţii complexe (decizia şi iteraţia) va fi descris în secţiunile următoare.

SECVENŢA

O secvenţă este o suită de operaţii care se execută în ordinea în care sunt scrise.

De exemplu, descrierea algoritmului pentru calculul expresiei e x 1 este o secvenţă pe care o prezentăm mai jos:

Citeşte x e x 1 Scrie e Stop

DECIZIA

Decizia are următoarele reprezentări în pseudocod şi schemă logică (Figura 3.16):

Dacă conditie atunci secvenţa1 Altfel secvenţa2

Figura 3.16. Descrierea în pseudocod şi schemă logică a deciziei

secventa2 secvenţa1

conditie

Fals Adevărat

Page 70: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

68

Execuţia structurii de decizie se face astfel:

se evaluează conditie;

dacă conditie este adevărată se execută secventa1, în caz contrar se execută secventa2.

Exemplu. Calculul maximului dintre două numere a şi b.

Citeste a,b Dacă a>b atunci amax Altfel bmax Scrie max Stop

 

 

 

Figura 3.17. Descrierea în pseudocod şi schemă logică a algoritmului

de calcul a maximului dintre două numere

ITERAŢIA CU TEST INIŢIAL

Iteraţia cu test iniţial are următoarele reprezentări în pseudocod şi schemă logică (Figura 3.18).

Cât timp conditie execută secventa

Figura 3.18. Descrierea în pseudocod şi schemă logică a iteraţiei cu test iniţial

Fals Adevărat

amax

Scrie max

Stop

ba

bmax

Start

Citeşte a, b

secventa

Adevarat

Falsconditie

Page 71: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

69

Efectul acestei structuri este următorul: se execută secventa cât timp conditie este adevărată.

Observaţii:

dacă din start conditie ia valoarea Fals, secvenţa nu se execută niciodată;

secventa trebuie să conţină enunţuri care să conducă la modificarea valorii de adevăr a condiţiei după un număr finit de paşi (condiţia trebuie sa ia valoarea Fals la un moment dat pentru a se ieşi din ciclu, în caz contrar se produce o buclă eternă sau un ciclu infinit).

Prezentăm mai jos un exemplu care conţine o buclă eternă.

7x Cât timp 6x execută

xy Stop

Se observă că secvenţa xy nu va modifica niciodată valoarea variabilei x. În consecinţă, x va avea întotdeauna valoarea 7, condiţia 7x va fi întotdeauna adevărată şi, deci, secvenţa xy se va executa de o infinitate de ori.

Exemplu. Calculul sumei elementelor unui şir. Sfârşitul şirului este marcat de cifra zero.

0s

Citeşte x Cât timp x≠0 execută xss Citeşte x Scrie s Stop

Page 72: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

70

✎ Descrieţi în pseudocod secvenţa. Daţi câteva exemple.

✎ Descrieţi în pseudocod decizia. Daţi câteva exemple.

✎ Descrieţi în pseudocod iteraţia. Daţi câteva exemple.

Forme echivalente pentru structurile de decizie şi de iteraţie cu test iniţial

Pentru a uşura implementarea şi a spori claritatea programelor, majoritatea limbajelor de programare utilizează şi alte structuri algoritmice, echivalente logic cu structurile algoritmice fundamentale prezentate.

Astfel, în cazul deciziei, amintim decizia cu ramură vidă şi decizia generalizată (sau selecţia).

Decizia cu ramură vidă are forma generală (Figura 3.19):

Citeşte x

0x

Stop

Nu

Da

Scrie x

xss

Citeşte x

Start

Page 73: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

71

Dacă conditie atunci secventa

Figura 3.19. Descrierea în pseudocod şi schemă logică a deciziei cu ramură vidă

Efectul deciziei cu ramură vidă constă în execuţia condiţionată a secvenţei: secventa se execută numai dacă conditie este adevărată.

Exemplu. Calculul maximului dintre două numere a şi b utilizând decizia cu ramură vidă.

 

Citeşte a,b amax Dacă ba atunci bmax Scrie max Stop

Decizia generalizată permite alegerea (selecţia) unei alternative din mai multe posibile. Forma generală a selecţiei este următoarea (Figura 3.20):

secventa

Adevarat Fals conditie

ba

bmax

Scrie max

Stop

Nu Da

amax

Citeşte a, b

Start

Page 74: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

72

Alege expresie dintre C1: secventa1 C2: secventa2 . . . Cn: secventan Altfel secventan+1

Figura 3.20. Descrierea în pseudocod şi schemă logică a

deciziei generalizate

Modul de execuţie al deciziei generalizate este următorul:

se evaluează expresie;

dacă există ni ...,,2,1 astfel încât expresie ci se execută secventai şi se iese din structură;

dacă pentru orice ni ...,,2,1 expresie ci se execută secventan+1 şi se iese din structură.

Observaţie. Secvenţa secventan+1 este opţională.

Exemplu. Se citeşte un caracter şi în funcţie de valoarea sa se scriu diferite mesaje. Algoritmul este descris în pseudocod.

Citeste x Alege x dintre ’a’, ’A’: Scrie (’Ana’) ’e’: Scrie (’Elena’) ’m’..’a’: Scrie (’Mona, Nae, Oana’) Altfel: Scrie (’Ati tastat gresit’) Stop

De regulă, în limbajele moderne de programare se

secventa1

C1

C2

C3

Altfel

secventan+1

secventa2

secventa3

expresie

Page 75: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

73

implementează alături de iteraţia cu test iniţial şi următoarele două forme echivalente:

iteraţia cu contor (structura Pentru);

iteraţia cu test final (structura Repetă Cât Timp).

Iteraţia cu contor este un caz particular al iteraţiei cu test iniţial. Rolul central îl ocupă aici o variabilă specială, numită variabilă contor, care poate fi iniţializată, actualizată şi poate controla valoarea logică a condiţiei. Actualizarea înseamnă modificarea cu o valoare constantă (numită raţie sau pas) a variabilei contor. Reprezentarea în pseudocod şi sub formă de schemă logică a iteraţiei cu contor este prezentată în Figura 3.21:

Pentru v vi, vf, r execută secventa

Figura 3.21. Descrierea în pseudocod şi schemă logică a iteraţiei cu contor

Observaţie. Situaţia descrisă în schema logică de mai sus se referă la cazul vi vf şi raţia r 0. Când vi vf şi r 0 condiţia de test se schimbă în v vf.

Structura de control Pentru se foloseşte când se cunoaşte numărul de iteraţii. Observaţiile făcute la structura Cât timp rămân valabile şi aici.

Exemplu. Calculul sumei a n numere reale citite de la tastatură.

v vf

secventa v v r

Fals

Adevărat

v vi

Page 76: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

74

Citeşte n 0s

Pentru ni ,1 execută Citeşte x xss Scrie s Stop

Observaţie. Când raţia lipseşte se consideră că implicit are valoarea 1.

Iteraţia cu test final se reprezintă în pseudocod şi schemă logică sub forma (Figura 3.22):

Repetă secventa

Cât timp conditie

Figura 3.22. Descrierea în pseudocod şi schemă logică a iteraţiei cu test final

Observaţii:

secventa se execută cel puţin o dată.

Pentru a nu se cicla la infinit, secventa trebuie să conţină enunţuri care, după un număr finit de paşi, să conducă la valoarea de adevăr Fals pentru conditie.

Exemplu. Calculul valorii xy pentru un număr x real citit de la tastatură.

Repetă Citeşte x Cât Timp 0x

xy Scrie y Stop

secventa

conditie Fals Adevărat

Page 77: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

75

Proceduri şi funcţii

Sunt frecvente cazurile în care o secvenţă de instrucţiuni este reluată pe parcursul unei algoritm schimbându-se de fiecare dată numai valorile iniţiale ale variabilelor.

Pentru a se evita scrierea aceloraşi instrucţiuni de mai multe ori, acestea sunt organizate separat, sub forma unui subalgoritm şi apelate în algoritmul principal ori de câte ori este nevoie.

Schematic, situaţia se prezintă astfel:

Subalgoritmul poate lua forma unei proceduri sau a unei funcţii.

În pseudocod o procedură se reprezintă astfel: Procedura numeprocedura (listadeparametri) corpul procedurii Sfârşit

Instrucţiuni care se repetă

Instrucţiuni care se repetă

Instrucţiuni care se repetă

Algoritm Algoritm principal

apel subalgoritm

apel subalgoritm

apel subalgoritm

Subalgoritm

Page 78: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

76

Precizări:

cuvintele Procedura şi Sfârşit sunt cuvinte rezervate.

numeprocedura este evident numele procedurii şi serveşte la identificarea instrucţiunilor care se apelează.

listadeparametri reprezină parametrii formali sau fictivi; lista poate fi vidă.

corpul procedurii conţine instrucţiunile subalgoritmului.

Apelul unei proceduri se face prin specificarea numelui procedurii urmat de lista de parametri actuali sau efectivi cuprinşi între paranteze rotunde:

numeprocedura (listadeparametri)

Şi în acest caz listadeparametri poate să fie vidă.

Transferul informaţiei dinspre algoritmul principal spre procedură şi invers se face prin intermediul parametrilor. Există şi posibilitatea de a transmite informaţii prin variabile globale, adică variabile care sunt recunoscute (se “văd”) şi în algoritmul principal şi în procedură. Această ultimă variantă nu este recomandată deoarece, tocmai datorită caracterului lor global, valorile variabilelor pot fi modificate uneori din greşeală.

Parametrii formali pot sau nu avea aceleaşi nume cu parametrii actuali. Important este însă ca în ambele liste să existe un număr egal de parametri, iar parametrii formali şi actuali de pe aceeaşi poziţie să fie de tipuri compatibile.

Numele procedurii nu intervine în operaţiile expresiilor din algoritm. Rolul său este numai de a identifica instrucţiunile care se apelează.

Exemplu. Calculul combinărilor de n luate câte k:

)!(!

!

knk

nC k

n

,

utilizând o procedură pentru calculul factorialului. Descrierea se face în pseudocod.

Page 79: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

77

Procedura Fact (m,Fm) 1p Pentru nk ,2 execută

kpp

pFm Sfârşit Citeşte n, k Fact (n,Fn) Fact (k,Fk) Fact (n-k,Fnk) )/( knknnk FFFC Scrie Cnk Stop

La efectuarea apelului, se execută instrucţiunile din procedură, iar după terminare se revine în algoritmul principal la prima instrucţiune de după apel.

Un algoritm principal poate apela subalgoritmi diferiţi, iar fiecare subalgoritm poate apela la rândul său alţi subalgoritmi.

În exemplul de mai sus procedura Fact este apelată de trei ori. De fiecare dată parametrii formali m şi Fm sunt puşi în corespondenţă cu parametrii actuali corespunzători. De exemplu, la apelul

Fact(n,Fn)

parametrul formal m primeşte valoarea parametrului actual n. Se execută instrucţiunile din procedură iar rezultatul (n!) calculat în Fm se întoarce în algoritmul principal prin parametrul actual corespunzător Fn. Analog, după apelul succesiv al procedurii, în Fnk se va afla valoarea k!, iar în Fnk valoarea (n-k)!.

În pseudocod, o funcţie se reprezintă astfel: Funcţia numefunctie (listadeparametri) corpul funcţiei Sfârşit

Precizări:

cuvintele Funcţie şi Sfârşit sunt cuvinte rezervate.

Page 80: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

78

numefunctie este numele funcţiei.

lista_de_parametri reprezintă parametri formali sau fictivi; lista poate fi vidă.

corpul functiei conţine instrucţiunile subalgoritmului.

Transferul informaţiei dinspre algoritm spre funcţie se face prin intermediul parametrilor formali la apelul funcţiei. Rezultatul prelucrărilor din corpul funcţiei se întoarce în algoritmul principal prin intermediul numelui funcţiei. Din acest motiv, în corpul funcţiei, numefunctie trebuie să primească cel puţin o valoare. Numele funcţiei, urmat (dacă e cazul) de lista de parametri actuali cuprinsă între paranteze, poate să fie operand într-o expresie; la apel construcţia

numefunctie(listaparametriactuali)

va fi înlocuită cu rezultatul prelucrărilor din corpul funcţiei.

Exemplu. Calculul expresiei 63.5)( xfy

unde

7

725.10

72

)(

xdacaxe

xdaca

xdacax

xfx

.

Descrierea în pseudocod este următoarea: Funcţia )(xf Dacă 7x atunci 2 xf Altfel Dacă 7x

25.10f Altfel

xef x Sfârşit Citeşte x

63.5)( xfy Scrie y Stop

Page 81: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

79

✎ Explicaţi rolul procedurilor şi funcţiilor. Daţi 3 exemple

de funcţii şi 3 exemple de proceduri.

� Test de autoevaluare

3.5. Enumeraţi caracteristicile de bază ale algoritmului.

3.6. Enunţaţi teorema de structură.

Răspunsurile testelor de autoevaluare

3.1. Variabilele statice sunt variabile al căror nume se asociază pe toată durata execuţiei programului cu adresa unei locaţii de memorie.

3.2. Variabilele dinamice sunt variabile cărora se pot asocia mai multe adrese de locaţii de memorie pe durata execuţiei programului.

3.3. Datele elementare sunt indivizibile în raport cu operaţiile pe care le prelucrează (exemple: 4, -34.89, ‘s’), iar structurile de date sunt ansambluri de date, omogene sau nu, care pot fi tratate unitar în prelucrare.

3.4. Principalele structuri de date utilizate în algoritmi sunt: tabloul (sau vectorul), înregistrarea, lista liniară simplu înlănţuită, lista liniară dublu înlănţuită, stiva, coada, arborele şi graful.

3.4. Avantajele implementărilor statice ale listelor faţă de cele dinamice: consum de memorie mai redus, acces direct la orice element al listei, parcurgeri rapide în ambele sensuri.

Dezavantajele implementărilor statice ale listelor faţă de cele dinamice: dificultăţi la eliminarea sau adăugarea de elemente în listă.

3.5. Generalitatea, finititudinea şi neambiguitatea.

3.6. Orice algoritm cu un singur punct de început şi un singur punct de terminare a execuţiei poate fi reprezentat ca o

Page 82: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

80

combinaţie de trei structuri algoritmice fundamentale: secvenţa, decizia şi iteraţia cu test iniţial.

Lucrare de verificare ...................................................✍

Realizaţi o sistematizare a structurilor de date.

Scrieţi în pseudocod algoritmul de rezolvare a următoarei probleme: pentru o companie generică se citesc veniturile pe fiecare trimestru al ultimului an pentru toate sucursalele (încheierea citirii se face la întâlnirea unei valorie negative). Se cer: venitul trimestrial maxim, venitul trimestrial minim, suma veniturilor pentru toate sucursalele şi toate trimestrele şi venitul mediu trimestrial pe sucursală.

Rezumat

Etapele de rezolvare a unei probleme cu calculatorul sunt: analiza problemei, proiectarea algoritmului de rezolvare, descrierea algoritmului în pseudocod sau schemă logică, codificarea algoritmului într-un limbaj de programare (obţinerea programului), testarea programului, execuţia sa, obţinerea rezultatelor şi interpretarea lor şi întreţinerea programului.

În limbajele de programare se folosesc date elementare şi date structurate. Datele elementare, care sunt date indivizibile şi recunoscute de calculator fără prelucrări suplimentare, sunt date numerice (întregi şi reale), logice şi alfanumerice. Datele structurate (sau structurile de date) folosite frecvent în algoritmi sunt: tabloul, înregistrarea, lista liniară simplu înlănţuită, lista liniară dublu înlănţuită, stiva, coada, arborele şi graful.

Tablourile reprezintă colecţii omogene de date (şiruri).

Înregistrările reprezintă colecţii neomogene de date.

Listele liniare (simplu şi dublu înlănţuite) modelează şiruri de elemente omogene care nu se memorează obligatoriu la adrese vecine.

Stiva şi coada sunt liste liniare particulare care funcţionează după principiul Ultimul Intrat Primul Ieşit şi

Page 83: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

81

respectiv Primul Intrat Primul Ieşit.

Arborii sunt structuri pentru reprezentarea relaţiilor ierarhice dintre obiect.

Grafurile sunt structuri de tip reţea pentru reprezentarea relaţiilor (de aproape orice tip) dintre obiecte.

Tipurile de date se caracterizează printr-o mulţime de valori şi o mulţime de operaţii specifice care li se aplică.

În cadrul unui algoritm, datele se prezintă sub forma constantelor şi a variabilelor (statice sau dinamice).

Un algoritm se defineşte ca o mulţime ordonată de paşi executabili, descrişi fără ambiguitate, care definesc un proces finit. Un algoritm trebuie să fie deci general, finit şi neambiguu. Descrierea algoritmilor se realizează prin anumite convenţii de reprezentare, ca schema logică şi pseudocodul.

Teorema de structură, care furnizează justificarea conceptului de programare structurată implementat în limbajele de programare moderne, stipulează că orice algoritm cu un singur punct de început şi un singur punct de terminare a execuţiei poate fi reprezentat ca o combinaţie de trei structuri algoritmice fundamentale (structuri de control): secvenţa, decizia şi iteraţia cu test iniţial. Alături de aceste forme standard ale structurilor de control mai apar: decizia cu ramură vidă, decizia generalizată, iteraţia cu contor şi iteraţia cu test final.

Când într-un algoritm este necesară scrierea repetată a unor grupuri de instrucţiuni (în diverse puncte de execuţie) se pot scrie subalgoritmi care organizează separat aceste instrucţiuni şi care se pot apela ulterior în algoritmul principal sau de câte ori este nevoie. Subalgoritmii sunt proceduri dacă reunesc instrucţiuni care nu întorc valori în algoritmul apelant şi funcţii dacă reunesc instrucţiuni care întorc o valoare algoritmului apelant.

Page 84: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

82

Bibliografie

1. Liviu Dumitraşcu, Monica Vlădoiu, Mihaela Oprea, Cristian Marinoiu şi colectiv, Borland Pascal în 13 conversaţii cu CD, capitolul 12, Structuri de date. Operaţii elementare, pag. 548-583, Editura Universităţii din Ploieşti, 2001.

2. Gheorghe Barbu, Ion Văduva, Mircea Boloşteanu, Bazele Informaticii,

Editura Tehnică, Bucureşti, 1997.

3. A. Petrescu, N. Ţăpuş, T. Moisa, Gh. Rizescu, V. Hărăbor, N.

Mârşanu, Tr. Mihu, abc de calculatoare personale şi … nu doar atât …,

Vol.I, Ed. Tehnică, Bucureşti, 1990.

4. Luca-Dan Şerbănaţi, V. Cristea, Florica Moldoveanu, Valeriu Iorga,

Programarea sistematică în limbajele Pascal şi Fortran, Editura Tehnică,

Bucureşti, 1984.

Page 85: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

83

UI4. Introducere în limbajul de programare C

Obiectivele unităţii de învăţare – pag 83

Introducere în limbajul de programare C – pag 83

Test de autoevaluare – pag 89

Elemente de bază ale limbajului C – pag 90

Test de autoevaluare – pag 97

Expresii în C. Funcţii de intrare/ieşire uzuale pentru consolă

– pag 98

Test de autoevaluare – pag 120

Răspunsurile testelor de autoevaluare – pag 129

Lucrare de verificare – pag 129

Rezumat – pag 130

Bibliografie – pag 132

Obiectivele unităţii de învăţare

Familiarizarea cu limbajul de programare C

Cunoaşterea elementelor de bază ale limbajului C

Capacitatea de a crea programe în limbajul C

Durata: 2 ore

Introducere în limbajul de programare C

Limbajul C a fost inventat şi implementat prima dată în anii ’70 de către Dennis Ritchie, programator de sistem la Bell Laboratories. El îşi are originea în limbajul BCPL (Basic Computer Programming Language) care, prin perfecţionări şi dezvoltări succesive a devenit limbajul B şi în final limbajul C.

Page 86: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

84

Răspândirea iniţială a limbajului C se datorează folosirii sale în scrierea sistemului de operare UNIX, sistem care cunoaşte astăzi o ascensiune constantă printre sistemele de operare existente. Una din versiunile remarcabile ale limbajului C este cea furnizată împreună cu versiunea a 5-a sistemului de operare UNIX. Această versiune este descrisă prima oară în cartea lui Brian Kernighan şi Dennis Ritchie intitulată The C Programming Language. Cartea este cunoscută ca un punct de referinţă în evoluţia limbajului, fiind asimilată cu un adevărat standard.

Apariţia microcalculatoarelor a contribuit la răspândirea spectaculoasă a limbajului în diverse variante. Deşi diferenţa dintre ele nu a fost niciodată semnificativă, totuşi, pentru eliminarea anumitor neconcordanţe, în anul 1983 o comisie specială începe lucrul pentru elaborarea standardului ANSI (American National Standards Institute) al limbajului C, care apare 6 ani mai târziu, în anul 1989. La ora actuală, majoritatea compilatoarelor C sunt compatibile cu acest standard.

Locul limbajului C în familia limbajelor de programare

Familia limbajelor de programare se poate clasifica în: limbaje de nivel coborât, limbaje de nivel înalt şi limbaje de nivel mediu.

Prima categorie cuprinde limbajul cod-maşină şi limbajul de asamblare. Ambele sunt specifice tipului de maşină de calcul pe care sunt implementate. Limbajul cod maşină este limbajul alcătuit din acele instrucţiuni elementare care sunt înţelese şi executate de un anumit tip de calculator. Limbajul de asamblare foloseşte în locul codurilor numerice reprezentări simbolice, numite şi mnemonice, care uşurează munca de programare. Operaţiile limbajului de asamblare sunt operaţii de bază ale calculatorului. El nu acceptă structuri de control şi date structurate, dar permite adresarea simbolică a locaţiilor de memorie. Din aceste motive programele în limbaj de asamblare sunt lungi şi se scriu anevoios, dar sunt performante din punct de vedere al vitezei de execuţie şi al posibilităţilor de acces la resursele hardware.

A doua categorie, cea a limbajelor de nivel înalt, include binecunoscutele limbaje Fortran, Cobol, Basic şi Pascal. O parte din trăsăturile lor comune se referă la posibilitatea de a folosi

Page 87: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

85

structuri de control, date structurate, de a elabora cu uşurinţă programe portabile (care se pot adapta uşor la implementarea pe diverse categorii de sisteme de calcul). Limbajele din această categorie pierd însă calitatea esenţială a limbajelor de nivel coborât, aceea de a exploata eficient resursele maşinii de calcul pe care sunt implementate.

Categoria limbajelor de nivel mediu îmbină trăsăturile principale ale limbajelor de nivel înalt cu cele ale limbajelor de nivel coborât. Limbajul C este un limbaj de nivel mediu.

✎ Care sunt categoriile de limbaje de programare?

Câteva trasături ale limbajului C

Limbajul C oferă posibilitatea organizării programelor în module şi permite implementarea unor structuri de control şi tipuri de date care facilitează programarea structurată. Ca şi limbajele de nivel înalt, este uşor de învăţat şi de folosit, iar în plus are un număr foarte mic de cuvinte cheie (32 cuvinte după standardul ANSI C).

Portabilitatea specifică limbajelor de nivel înalt este accentuată în C prin folosirea funcţiilor de bibliotecă în realizarea operaţiilor de intrare/ieşire şi de prelucrare a fişierelor. Numărul mic de cuvinte cheie şi prezenţa unei bogate familii de operatori permit realizarea unor programe concise, cu un cod sursă relativ redus.

Compilatorul C este mai puţin sever în comparaţie cu majoritatea compilatoarelor limbajelor de nivel înalt.

Dacă la aceste trăsături adăugăm şi posibilitatea de a oferi facilităţi ale limbajelor de nivel coborât (lucru cu adrese de memorie, accesarea regiştrilor, incrementări, decrementări, apelul unor funcţii ale sistemului de operare) obţinem imaginea unui limbaj puternic şi flexibil preferat în special de programatorii profesionişti.

Page 88: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

86

Structura generală a unui program C

Structura generală a unui program C este următoarea:

directive preprocesor declaratii globale tip main(lista de parametri) { declaratii locale instructiuni } tip f1(lista de parametri) { declaratii locale instructiuni } tip f2(lista de parametri) { declaratii locale instructiuni } . . . . . tip fn(lista de parametri) { declaratii locale instructiuni }

Precizări. Faza de analiză a unei probleme evidenţiază uzual o funcţie principală şi mai multe funcţii secundare ale acesteia. Rezultatul acestei faze îl constituie o reprezentare modulară, care reflectă interdependenţa dintre funcţiile problemei. În principiu, orice program C este o secvenţă de funcţii aflate la acelaşi nivel.

Cuvintele main, f1,f2,…,fn sunt nume de funcţii C. Orice funcţie dintr-un program poate apela oricare altă funcţie din program. Excepţie face funcţia main() care poate apela alte funcţii, dar nu poate fi apelată dintr-o altă funcţie a programului. La execuţia unui program C prima funcţie apelată este main(): execuţia programului începe şi se termină cu instrucţiuni din main(). Ea este obligatorie şi poate figura oriunde în program. De obicei este plasată la începutul programului, pentru a-i mări lizibilitatea.

Directivele preprocesor sunt instrucţiuni destinate compilatorului, care face transformări preliminare asupra textului

Page 89: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

87

înainte de a începe compilarea. Faza preprocesării are drept rezultat obţinerea unei unităţi de compilare. Unitatea de compilare este analizată sintactic (compilată), iar rezultatul este depus în module obiect. Modulele obiect rezultate, împreună cu modulele obiect corespunzătoare funcţiilor de bibliotecă folosite sunt “legate“ cu ajutorul programului linkeditor (editor de legături) obţinându-se programul executabil. Directivele se constituie ca un limbaj în interiorul limbajului C şi oferă anumite facilităţi: compilarea condiţionată a unor porţiuni de cod, înlocuirea în text a unui identificator la fiecare apariţie cu un set de caractere, includerea unui fişier sursă în program etc..

O funcţie C este alcătuită din antet şi un bloc de declaraţii şi instrucţiuni delimitat de acoladele { şi }, numit şi corpul funcţiei. Antetul conţine numele funcţiei, tipul valorii returnate (întreg, real etc.) şi o listă de parametri formali care poate fi eventual vidă.

O funcţie este definită dacă este prezentată complet, adică are forma:

antet corpul funcţiei

Dacă se prezintă doar antetul funcţiei, se spune că funcţia este declarată. Declaraţia modernă a unei funcţii poartă numele de prototip. Apelul funcţiei se face sub forma

nume_functie(lista de parametri actuali)

şi presupune transferul controlului execuţiei programului către instrucţiunile din corpul funcţiei, execuţia acestora şi revenirea în funcţia apelantă în punctul unde se execută operaţia care urmează. Schema de apel este următoarea:

funcţie apelantă funcţie apelată

Figura 4.1. Schema de apel a unei funcţii  

apel functie

Page 90: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

88

O funcţie C nu poate fi declarată sau definită în interiorul altei funcţii.

Declaratiile globale se referă la entităţi (tipuri de date, variabile etc.) care sunt recunoscute de toate funcţiile. Declaratiile locale limitează valabilitatea acestor entităţi doar la nivelul funcţiei unde se fac. Prezenţa prototipului unei funcţii în zona declaraţiilor globale face posibilă recunoşterea sa în toate funcţiile care o apelează şi permite evitarea unor erori de apelare, încă din faza de compilare.

✎ Care este structura generală a unui program C?

În construcţia unui program C se pot folosi două categorii de funcţii:

funcţii utilizator, elaborate de programator;

funcţii standard (predefinite), care pot fi preluate din biblioteca standard a limbajului C.

Funcţiile standard ale limbajului se pot clasifica în: funcţii de intrare/ieşire, funcţii pentru prelucrarea caracterelor, funcţii pentru prelucrarea şirurilor de caractere etc.. În mod corespunzător prototipurile acestor funcţii sunt grupate în fişiere speciale numite fişiere antet sau header (au extensia “.h“). De exemplu, funcţiile matematice sunt grupate în fişierul antet ”math.h”, funcţiile de manipulare a şirurilor de caractere în ”string.h” etc.. Pentru a utiliza o funcţie standard în program trebuie cunoscut prototipul său, lucru posibil prin includerea fişierului antet în program utilizând directiva #include.

Un program C poate avea funcţiile editate într-un singur fişier (programe monofişier) sau în mai multe fişiere (programe multifişier). Un exemplu simplu de program C este următorul:

Exemplul 4.1

Primul program C #include ”stdio.h” void main(void) { printf(”/nPrimul program C!”); }

Page 91: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

89

Se observă că programul este alcătuit dintr-o singură funcţie, funcţia main() şi foloseşte funcţia standard printf() cu prototipul în ”stdio.h”.

✎ Ce sunt funcţiile utilizator? Dar funcţiile predefinite?

� Test de autoevaluare

4.1. Limbajul C a fost inventat de:

a. Niklaus Wirth

b. Dennis Ritchie

c. Brian Kernighan

4.2. Limbajul C este:

a. un limbaj de nivel coborât

b. un limbaj de nivel mediu

c. un limbaj de nivel înalt

4.3. În C, o funcţie:

a. nu se poate declara sau defini în interiorul alteia

b. poate apela o altă funcţie

c. este alcătuită din antet şi un bloc de declaraţii şi instrucţiuni delimitat de cuvintele begin şi end

4.4. Funcţia main()

a. poate să lipsească dintr-un program C

b. este obligatorie şi figurează prima în program

c. este obligatorie şi poate figura oriunde în program

4.5. În C, o funcţie:

a. poate include declaraţia sau definiţia altei funcţii

b. poate fi declarată sau definită în interiorul altei funcţii

c. se poate apela numai din main()

d. se poate apela din orice altă funcţie

Page 92: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

90

Elemente de bază ale limbajului C

Aşa cum se întâmplă cu orice limbaj artificial, temelia pe care se clădesc programele C este alcatuită din alfabet şi vocabular (atomi lexicali). Combinând atomii lexicali după regulile specifice de sintaxă se construiesc linii valide de program şi, în final, programul.

Alfabetul limbajului

Alfabetul limbajului este alcătuit dintr-o mulţime de simboluri care se pot clasifica în simboluri afişabile şi simboluri neafişabile.

Setul minim de simboluri afişabile (care pot fi reprezentate grafic) este alcătuit din:

litere mari ale alfabetului englez:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

litere mici ale alfabetului englez:

a b c d e f g h i j k l m n o p q r s t u v w x y z

cifre zecimale: 0 1 2 3 4 5 6 7 8 9

liniuţă de subliniere: _

semne de punctuaţie şi semne speciale:

, . ; : ? ’ ( ) [ ] < > ” ! | \ / ~ # & ^ * - = + { } %

Prezentăm în Tabelul 4.1. denumirea unora din semnele enumerate.

Tabelul 4.1. Câteva semne folosite în C şi denumirea lor

Semn Nume Semn Nume

| bară verticală / slash

\ backslash ~ tilda

# diez _ liniuţă de subliniere (underscore)

& ampersand ^ săgeată sus

Page 93: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

91

Simbolurile neafişabile (fără echivalent grafic) sunt reprezentate prin secvenţe escape (de evitare) sau coduri backslash-caracter. Aceste simboluri reprezintă coduri ASCII care nu pot fi citite de la tastatură. Folosirea lor în programe în locul echivalentelor ASCII este recomandată din raţiuni de portabilitate. Codurile backslash ale limbajului C sunt prezentate în Tabelul 4.2.

Tabelul 4.2. Codurile backslash din C şi semnificaţia lor Cod

backslash Semnificaţie Cod

backslashSemnificaţie

\a alarmă \’ apostrof \b backspace

(recul cu o poziţie) \” ghilimele

\f form feed (salt pagină nouă)

\0 caracter nul

\n newline (salt la rând nou şi de la capăt)

\\ backslash

\r carriage return (retur car)

\ddd caracter ASCII în notaţie octală

\t horizontal tab (tab orizontal)

\xdd caracter ASCII în notaţie hexazecimală

\v vertical tab (tab vertical)

Observaţii:

Tab orizontal înseamnă saltul cursorului cu un număr de coloane, iar tab vertical saltul cursorului cu un număr de linii.

Notaţia octală foloseşte cifre în baza 8 (adică 0,1,2,3,4,5,6,7), iar notaţia hexazecimală cifre în baza 16 (adică 0,1,2,3,4,5,6,7,8,9, A,B,C,D,E,F). Se observă că literele A,B,C,D,E, F corespund respectiv numerelor 10,11,12,13,14,15. Secvenţele ”\ddd” permit scrierea oricărui caracter din setul ASCII ca un număr octal format din trei cifre, iar secvenţele ”\xdd” ca un număr hexazecimal format din două cifre. De exemplu, caracterul backspace poate fi scris ca ”\010” sau ”\x08”.

Vocabularul limbajului

Vocabularul limbajului este alcătuit din atomi lexicali.

Page 94: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

92

Aceştia reprezintă grupuri de simboluri afişabile care primesc în timpul procesului de compilare o anumită semnificaţie. Prezentăm mai jos următorii atomi lexicali:

identificatori (nume);

constante;

operatori;

semne de punctuaţie;

simboluri speciale.

Un identificator reprezintă o secvenţă de litere, cifre, liniuţe de subliniere, primul caracter din secvenţă fiind obligatoriu o literă sau liniuţă de subliniere.

De exemplu, Cod_mat, cod_mat, y_1, ax, _ol sunt identificatori, în timp ce x...1, a&b, 3xy nu sunt. În legătură cu identificatorii facem următoarele precizări:

În C se face deosebirea între literele mari şi mici ale alfabetului. De exemplu, Cod_mat şi cod_mat reprezintă nume diferite;

Deşi sunt permişi, este recomandabil ca identificatorii care încep cu liniuţă de subliniere să fie evitaţi. Ei pot coincide cu nume rezervate, invizibile programatorului, provocând erori;

Standardul ANSI C nu limitează numărul de caractere (lungimea) unui identificator. Un compilator C va ignora însă caracterele aflate pe poziţii mai mari decât un număr prestabilit.

✎ Daţi câteva exemple de identificatori corecţi.

Cuvintele cheie sunt cuvinte rezervate C care au o destinaţie prestabilită (nu pot fi folosite ca nume de funcţie sau variabilă). Standardul ANSI C are 32 de cuvinte cheie, din care 27 au fost definite de varianta originală a limbajului C (standardul Kernighan/Ritchie).

Page 95: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

93

Tabelul 4.3. Cuvinte cheie după standardul Kernighan / Ritchie auto break case char continue

default do double else extern float for goto if int long register return short sizeof

static struct switch typedef union unsigned while

Tabelul 4.4. Cuvinte cheie adăugate de standardul ANSI C

const enum signed void volatile

După cum se poate observa, cuvintele cheie din C se scriu cu litere mici. Pe lângă cuvintele cheie rezervate de standardul ANSI C, diverse tipuri de compilatoare C includ şi cuvinte cheie folosite în exploatarea eficientă a mediului de operare specific (facilităţi privind programarea interlimbaje, accesarea întreruperilor etc.), numite cuvinte cheie extinse.

Cuvintele cheie extinse folosite cel mai des sunt:

asm cdecl far huge interrupt nearpascal _cs _ds _es _ss

Constantele pot fi numere, caractere, şiruri de caractere; valoarea lor nu se schimbă în timpul execuţiei unui program. În C există patru tipuri de constante: întreg, real, caracter, şir.

O constantă întreagă este un număr zecimal, octal sau hexazecimal care reprezintă o valoare întreagă pozitivă. Dacă se doresc şi reprezentări ale unor numere întregi negative se adaugă semnul minus în faţa constantei respective.

Constantele întregi zecimale sunt numere întregi scrise în baza 10 (de exemplu: 759,+38,6496), constantele octale sunt numere în baza 8 care încep, pentru identificare, cu cifra zero (de exemplu: 012,0765), iar constantele hexazecimale sunt numere în baza 16 care încep pentru identificare cu caracterele 0x (de exemplu: 0xA3,0xBC1,0x7E31).

Constantele reale sunt numere reale pozitive. Pentru a reprezenta valori reale negative se plasează semnul minus în faţa constantei. Semnul minus este tratat ca operator aritmetic. Există două modalităţi de reprezentare o constantelor reale: în format F (cu punct zecimal) şi în format exponenţial (formă ştiinţifică).

Page 96: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

94

Reprezentarea în format F este reprezentarea uzuală pentru numere reale. De exemplu, constantele 32.753,0.591,-4296.823, .69 sunt valori reale reprezentate în format F. Se observă că partea întreagă a reprezentării poate să lipsească atunci când este egală cu zero (.69 este tot una cu 0.69).

O constantă reală în format exponenţial are forma generală:

numar simbexp valexp unde:

numar este o constantă întreagă sau o constantă reală în format F;

simbexp este E sau e;

valexp este o constantă întreagă pozitivă precedată sau nu de semnele + sau-;

grupul simbexp valexp se interpretează ca fiind egal cu 10valexp.

Remarcă. În realitate, între numar, simbexp, valexp nu apar spaţii. De exemplu, numerele reale: 1.6*103, -2.6*10-4, 0.32*106, 423*104 se scriu, respectiv: 1.6E+3,-2.6E-4, 0.32e+6,423E+04.

O constantă caracter este o literă, cifră, semn de punctuaţie sau secvenţă escape cuprinse între două apostrofuri. Exemplu de constante caracter: ’a’,’\n’,’\’’,’7’ reprezentând respectiv a, newline, apostrof, 7.

O constantă şir este o secvenţă de litere, cifre şi simboluri incluse între ghilimele. Exemple de constante şir: ”\n Acesta e un sir”, ”Str. Cameliei, nr.3” etc.. Constantele şir se memorează în octeţi consecutivi (un octet pentru fiecare caracter). Sfârşitul şirului este marcat de un octet nul (care conţine ’\0’) ce se adaugă automat. Din acest motiv un şir cu n caractere ocupă n+1 octeţi consecutivi.

Operatorii reprezintă combinaţii de semne speciale care arată modalitatea de prelucrare sau atribuire a valorilor. Limbajul C posedă o bogată familie de operatori, fapt ce permite elaborarea unor programe compacte. În Tabelul 4.5 prezentăm lista operatorilor C şi semnificaţia lor.

Page 97: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

95

Tabelul 4.5. Lista operatorilor C şi semnificaţia lor

Operator Semnificaţie [] paranteze drepte (stângă si dreaptă) () paranteze rotunde (stângă si dreaptă) . membru structură referinţă indirectă la membru de structură ++ incrementare (prefix sau postfix) -- decrementare (prefix sau postfix)

sizeof dimensiunea unei variabile sau unui tip în octeţi ~ NOT pe bit ! NOT logic & adresă, ŞI pe bit * indirectare, înmulţire / împărţire + adunare - scădere, negaţie aritmetică << deplasare logică pe bit la stînga >> deplasare logică pe bit la dreapta == egalitate != neegalitate < mai mic > mai mare <= mai mic sau egal cu >= mai mare sau egal cu ^ SAU exclusiv pe bit SAU pe bit && ŞI logic || SAU logic ?: operator condiţional = atribuire simplă op= atribuire compusă % modul , virgula (operator de secvenţiere)

Observaţie. Caracterul op de la atribuirea compusă poate fi unul din semnele * / % + - >> << & ^ rezultând corespunzător operatorii compuşi *= /= %= += -= >>= <<= = &= ^=.

Între semnele care alcătuiesc un operator compus nu trebuie să existe spaţiu. De exemplu, operatorul >= nu poate fi utilizat sub forma > = . De la regula de mai sus face excepţie operatorul condiţional (?:) care are altă interpretare.

Page 98: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

96

Semnele de punctuaţie folosite în C sunt: ... # : {}

Utilizarea lor va fi exemplificată pe parcursul lucrării.

Simboluri speciale. Orice simbol care nu aparţine alfabetului C este considerat atom lexical. Astfel de semne sunt: @ şi $. Ele pot fi folosite în construcţia constantelor caracter şi a şirurilor. Ca exemplu, considerăm constanta şir ”Am folosit semnul @ in FoxPro”.

Atomii lexicali sunt separaţi în cadrul programului prin simboluri ale alfabetului cu rol de separator. Separatorii sunt: spaţiul, tabul (orizontal şi vertical), sfârşit de linie, sfârşit de pagină, comentariu. Prin comentariu se înţelege orice succesiune de simboluri cuprinse între /* şi */. Comentariile nu sunt luate în considerare de compilator, ele servesc la documentarea programului uşurând înţelegerea şi depanarea lui. Un comentariu poate fi plasat oriunde în program şi se poate întinde pe unul sau mai multe rânduri.

Exemplu:

/* Acest program calculeaza produsul a doua

matrici. Matricile de intrare A(4x3) si B(3x2) se citesc de la tastatura, iar matricea produs rezultata este C(4x2).

*/

Comentariile nu pot fi imbricate (incluse unul în altul). De exemplu, următoarea construcţie este eronată:

/* Un comentariu care include /* un comentariu inclus */ */

Modul în care sunt aranjaţi atomii lexicali într-un program este impus de specificul problemei şi de regulile de sintaxă ale limbajului.

Page 99: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

97

� Test de autoevaluare

4.6. Un identificator este:

a. o secvenţă de cifre, liniuţe de subliniere şi litere

b. o secvenţă de cifre, liniuţe de subliniere şi litere, primul caracter din secvenţă fiind obligatoriu liniuţă de subliniere sau literă

c. o secvenţă de cifre, litere, spaţii, liniuţe de subliniere

4.7. În C un identificator poate fi scris:

a. numai cu litere mici

b. numai cu litere mari

c. combinat, cu litere mici şi litere mari

4.8. Dacă într-un identificator C se înlocuieşte o literă mică (mare) cu litera sa omoloagă mare (mică) atunci:

a. identificatorul obţinut este considerat identic cu primul

b. se obţine un identificator diferit

4.9. În C există:

a. patru tipuri de constante: întregi, reale, caracter, şir

b. patru tipuri de constante: naturale, reale, complexe, caracter

c. cinci tipuri de constante: întregi, reale, complexe, caracter, şir

4.10. În C secvenţa de cifre 0631 este interpretată ca:

a. o constantă în bază 10

b. o constantă în bază 8

c. o constantă în bază 16

4.11. Secvenţa de caractere 0xABC poate fi:

a. un identificator

b. o constantă hexazecimală

c. şi una şi alta

Page 100: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

98

4.12. Cuvintele cheie:

a. au semnificaţii date de programator

b. au semnificaţii prestabilite

c. au semnificaţii date de contextul în care sunt utilizate

4.13. Despre constantele reale 3.0E-2 şi .03 se poate afirma că:

a. sunt greşite deoarece conţin punct în loc de virgulă

b. sunt corecte şi reprezintă valori diferite

c. sunt corecte şi reprezintă aceeaşi valoare

d. sunt greşite deoarece prima conţine litera E, iar a doua nu are parte întreagă

4.14. Secvenţa ’a’ reprezintă:

a. un şir

b. un caracter

4.15. Secvenţa ’Citirea matricii A’reprezintă:

a. un şir

b. un comentariu

c. nici una, nici alta

4.16. Construcţiile ’a’ şi ”a”:

a. reprezintă acelaşi lucru

b. reprezintă un şir, respectiv un caracter

c. reprezintă un caracter, respectiv un şir

Expresii în C. Funcţii de intrare/ieşire uzuale pentru consolă

Expresiile sunt combinaţii valide sintactic de date şi operatori. Aici, prin date înţelegem deopotrivă constante şi variabile. Spre deosebire de constante care sunt valori fixe, variabilele semnifică valori care se pot modifica prin program.

În C, ca şi în alte limbaje, datele sunt clasificate în tipuri de date. Există tipuri de date fundamentale (numite şi predefinite, simple sau de bază) şi tipuri de date derivate. Tipurile derivate

Page 101: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

99

(tablouri, pointeri, structuri, uniuni, enumerări şi orice tip definit de programator) se bazează pe tipurile fundamentale.

Tipurile fundamentale de date în C

Tipurile de date fundamentale din C se împart în cinci categorii: char, int, float, double şi void. Primele patru tipuri se mai numesc şi tipuri aritmetice şi se referă respectiv la valori caracter, întregi, reale în simplă precizie şi reale în dublă precizie. Tipul de date void indică absenţa oricărei valori şi este utilizat, de exemplu, la descrierea funcţiilor care nu returnează nici o valoare.

Dimensiunea zonei de memorie alocate şi domeniul de valori asociate tipurilor aritmetice pot să difere funcţie de varianta de implementare a limbajului şi de tipul de procesor folosit. Standardul ANSI C nu precizează decât domeniul minimal de valori al fiecărui tip de date, nu şi dimensiunea sa. În majoritatea implementărilor însă, tipul char ocupă un octet, int ocupă doi octeţi, iar float patru octeţi. Domeniul de valori poate fi modificat utilizând modificatorii de tip. Aceştia sunt: signed, unsigned, short şi long. Modificatorii signed, unsigned, short şi long se pot aplica tipului int, signed şi unsigned, tipului char, iar long, tipului double. Efectul aplicării modificatorilor signed sau unsigned asupra tipurilor de date întregi constă în interpretarea diferită, din punct de vedere al semnului, a informaţiei memorate. Să considerăm o configuraţie binară de lungime N, biţii fiind numerotaţi ca mai jos:

N - 1 N - 2 … 1 0

Figura 4.2. Configuraţie binară de N biţi

Dacă această zonă o destinăm memorării doar a întregilor pozitivi, printr-un calcul simplu se vede că plaja de reprezentare este [0, 2N-1]. Dacă zona este destinată memorării atât a întregilor cu semn cât şi fără semn, bitul N-1 va fi folosit pentru reprezentarea semnului (0 pentru numere pozitive, 1 pentru numere negative), iar plaja de reprezentare va fi [-2N-1, 2N-1-1].

Având în vedere aceste consideraţii, de exemplu, o variabilă de tip signed int va avea un domeniu de valori cuprins între -32768 şi 32767, iar una de tip unsigned int va lua valori între 0

Page 102: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

100

şi 65535.

Observaţii:

Pentru tipul întreg de date (char, int, short, long) reprezentarea implicită este signed.

Specificarea unui modificator fără tip înseamnă considerarea implicită a tipului int.

În C nu există tipul de date boolean. Din acest motiv funcţionează următoarea convenţie: orice expresie diferită de zero are valoarea adevărat, iar dacă e egală cu zero, valoarea fals.

Variabile şi tipuri de date

Asocierea dintre numele unei variabile şi un anumit tip de date se face folosind declaraţiile. Forma generală a declaraţiei unei variabile este:

tip lista_de_variabile;

unde: tip poate fi orice tip de date recunoscut în C, iar lista_de_variabile conţine unul sau mai mulţi identificatori despărţiţi prin virgulă. În exemplele de mai jos vom folosi doar tipurile fundamentale.

Exemple de declaraţii de variabile:

float x,y; int a,b1; short a_x,b_y; double z;

Orice variabilă folosită în program trebuie mai întâi declarată. Dacă pe linia de declarare variabila este iniţializată se spune că are loc o definire a variabilei.

Exemple de declaraţii şi definiţii de variabile:

float x=38.981,I; int ab=-453; char ch=’A’,z;

Orice variabilă definită (adică declarată şi iniţializată) păstrează în continuare atributul de bază al variabilei, adică poate fi modificată. Dacă se doreşte “îngheţarea“ asocierii dintre o variabilă şi o anumită valoare se utilizează modificatorul de

Page 103: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

101

acces (sau calificatorul) const. Practic, efectul unei declaraţii de genul

const tip nume_variabila;

este crearea constantei simbolice nume care poate fi utilizată, dar nu poate fi modificată prin program. Dacă tip lipseşte se consideră implicit că tipul este int. În exemplul de mai jos se definesc două constante, constanta pi şi constanta de tip int, ore_zi. Exemplu:

const double pi=3.1415926536; const ore_zi=24;

Constante şi tipuri de date

Anterior s-a prezentat o clasificare a constantelor în: întregi, reale, caracter, şir. Se pune problema, cărui tip de date îi aparţine o constantă numerică? Când constanta este caracter, răspunsul este simplu: tipului char. De asemenea, constanta în virgulă mobilă (în notaţie uzuală cu punct sau în notaţie ştiinţifică) va aparţine tipului double. Pentru celelalte constante numerice compilatorul va considera implicit încadrarea în cel mai mic tip de date compatibil. De exemplu, 23 este de tip int, 65000 de tip unsigned, 2000002 de tip long int. Încadrarea într-un tip de date se poate face şi explicit adăugând constantei unul din sufixurile L sau U, dacă e întreagă sau F sau L, dacă e reală. Constanta întreagă cu sufixul L este de tip long, iar cu sufixul U, de tip unsigned. Constanta reală cu sufixul F are tipul float, iar dacă e urmată de sufixul L are tipul long double.

Funcţii uzuale de intrare/ieşire pentru consolă. Descriptori de format

Prezentăm în continuare funcţiile folosite frecvent pentru transferul de date de la tastatură în memoria calculatorului (funcţii de intrare) şi din memoria calculatorului pe ecran (funcţii de ieşire); cu această ocazie introducem şi descriptorii de format cei mai folosiţi. Deosebim trei categorii de funcţii de intrare/ieşire pentru consolă:

Page 104: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

102

funcţii generale de intrare/ieşire (scanf() şi printf());

funcţii speciale de intrare/ieşire:

funcţii pentru citirea şi scrierea caracterelor;

funcţii pentru citirea şi scrierea şirurilor de caractere.

Funcţiile printf() şi scanf() reprezintă echivalentele pentru consolă a funcţiilor de intrare/ieşire pentru fişiere, fprintf() şi fscanf(). Forma generală a funcţiei de afişare printf() este:

int printf(sir_format,lista_de_argumente); unde:

sir_format poate conţine: mesaje pentru utilizator, secvenţe escape şi descriptori de format pentru valorile care se afişează;

lista_de_argumente reprezintă variabile sau expresii al căror conţinut se va afişa.

Funcţia întoarce numărul de caractere scrise efectiv sau o valoare negativă în caz de insucces.

Precizări:

Descriptorii de format servesc la efectuarea conversiilor dintre reprezentarea externă şi internă (la citire) şi între reprezentarea internă şi externă (la scriere); formatul extern presupune succesiuni de caractere, iar cel intern succesiuni de cifre binare;

Atât la scriere cât şi la citire, descriptorii de format sunt puşi în corespondenţă de la stânga spre dreapta cu elementele listei de argumente. Argumentul trebuie să fie compatibil cu tipul anunţat în descriptorul de format corespunzător;

Dacă numărul de argumente este mai mic decât numărul descriptorilor de format, datele de ieşire sunt nedefinite; dacă numărul argumentelor este mai mare decât numărul descriptorilor de format, argumentele în plus sunt ignorate.

În Tabelul 4.6. prezentăm lista celor mai utilizaţi descriptori

Page 105: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

103

folosiţi de funcţia printf() şi semnificaţia lor.

Tabelul 4.6. Descriptori de format Descriptor Utilizare %u numere întregi zecimale fără semn %d sau %i numere întregi zecimale cu semn %c caracter %f numere reale în notaţie uzuală %e sau %E numere reale în notaţie ştiinţifică (e sau E) %x sau %X hexazecimal fără semn (litere mici sau

majuscule) %o octal fără semn %s şir de caractere %g sau %G se alege reprezentarea cu numărul cel mai

mic de caractere dintre cea în notaţie uzuală şi cea în notaţie ştiinţifică (de tip e sau E)

%p valoare pointer

Descriptorul %x are ca efect afişarea cifrelor hexazecimale A,B,C,D,E,F cu literă mică; dacă se foloseşte %X se afişează cu litere mari.

Dacă se foloseşte %e litera ”e” din notaţia ştiinţifică apare ca e, iar dacă se foloseşte %E, apare ca majusculă (litera E).

Valorile de tip long int se afişează utilizând %ld,%li,%lu,%lo sau %lx. Valorile de tip short int se afişează utilizând %hd,%hi,%hu,%ho sau %hx.

Pentru a afişa valori double se va alege una din variantele: %lf,%le,%lE,%lg,%lG, iar pentru valori long double una din variantele: %Lf,%Le,%LE,%Lg,%LG.

Tabelul 11 prezintă descriptori de format fără caracteristici de lungime, precizie şi aliniere. Folosiţi astfel, ei aliniază implicit valorile la stânga şi folosesc spaţiu de afişare necesar reprezentării acestor valori după cum urmează:

%f afişează implicit partea întreagă, punctul şi 6 cifre la partea subunitară;

%e sau %E afişează implicit o cifră la partea întreagă, 6 cifre la partea subunitară, caracterul e sau E şi exponentul precedat de + sau -;

%g sau %G alege reprezentarea cu cel mai mic număr de

Page 106: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

104

caractere dintre cea uzuală şi cea ştiinţifică.

%d,%i,%c,%o,%x,%X,%s,%p folosesc un număr de coloane egal cu numărul de caractere ce trebuie afişate.

Exemplificăm folosirea descriptorilor prezentaţi şi a secvenţelor de evitare cu ajutorul următoarelor programe:

Exemplul 4.2.

Afişarea valorilor şi sumei a două numere întregi, sub forma:

x=valoare y=valoare suma=valoare # include "stdio.h" void main(void) { int x=10, y=-43; printf ("\n\tx=%d\t\y=%d\n\t suma=%i", x,y, x+y); }

Exemplul 4.3

Afişarea unei constante întregi şi a valorilor sale în octal şi hexazecimal pe câte un rând.

#include "stdio.h" void main(void) { const x=4529; printf("\n numarul este=%d\n",x); printf("\n valoarea in octal este=%o",x); printf("\n valoarea in hexazecimal este=%x",x); }

Exemplul 4.4

Afişarea unui caracter şi a codului său ASCII; afişarea se va termina cu un semnal sonor.

#include "stdio.h" void main(void) { char a='Q';

Page 107: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

105

printf("\n caracterul %c are codul ASCII=%i\a",a,a);

}

Exemplul 4.5

Afişarea unor valori folosind diverşi descriptori de format; comentariile arată efectul execuţiei funcţiei printf().

#include "stdio.h" void main(void) { char ch; short k; int i; long int j; float x; clrscr(); ch='A'; printf("\n Caracterul %c are codul ASCII =%i",ch,ch); /* Caracterul A are codul ASCII = 65 */ k=250; printf("\n k=%hu",k); /* k=250 */ i=4567; printf("\n i=%i",i); /* i=4567 */ printf("\n i=%u",i); /* i=4567 */ printf("\n –i=%i",-i); /* -i=-4567 */ printf("\n i=%i",i); /* i=4567 */ printf(" are valoarea hexazecimala %x",i); /* are valoarea hexazecimala 11d7 */ printf(" sau echivalent, %X",i); /* sau echivalent, 11D7 */ printf("\n i=%i",i); /* i=4567 */ printf(" are valoarea octala %o",i); /* are valoarea octala 10727 */ j=123456; printf("\n j=%li",j); /* j=123456 */ x=76.5432; printf("\n x=%f",x); /* x=76.543198 */ printf("\n x=%e",x); /* x=7.65320e+01 */ printf("\n x=%E",x); /* x=7.65320E+01 */ printf("\n x=%g",x); /* x=76.543200 */ printf("\n x=%G",x); /* x=76.543200 */ x=-0.123456789; printf("\nx=%f",x); /*x=-0.123457 */ printf("\nx=%e",x); /*x=-1.234568e-01 */ printf("\n x=%E",x);/* x=-1.234568E-01*/

Page 108: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

106

printf("\n x=%g",x); /*x=-0.123457 */ printf("\n x=%G",x); /*x=-0.123457 */ printf("\n %s","testare"); }

Dimensiunea câmpului de afişare, precizia şi modul de

aliniere pot fi stabilite prin simboluri plasate între semnul % şi specificatorul descriptorului de format (i,d,u,f etc.).

Astfel, un întreg pozitiv aflat între % şi specificatorul descriptorului de format indică dimensiunea minimă a câmpului de afişare. Dacă şirul sau numărul care se afişează are mai multe caractere decât dimensiunea minimă precizată, atunci afişarea va fi integrală, în caz contrar se completează cu spaţii până la realizarea dimensiunii minime. Dacă dorim ca această completare să fie făcută cu cifra 0 în loc de spaţii, atunci, înainte de întregul care specifică dimensiunea de afişare, se pune cifra 0.

De exemplu, descriptorul %7f semnifică afişarea unui număr real pe minim 7 coloane şi, completarea eventualelor coloane libere cu spaţii, iar %07f impune acelaşi număr minim de coloane pentru afişare, însă completarea coloanelor libere se va face cu cifra 0.

Utilitatea precizării dimensiunii minime de afişare apare mai ales la afişarea tablourilor în care alinierea se face pe coloane. Programul următor ilustrează efectul precizării dimensiunii câmpului de afişare:

Exemplul 4.6

Afişarea unor valori folosind descriptori de format cu precizarea dimensiunii câmpului de afişare.

#include "stdio.h" void main(void) { int i; float x; i=4567; printf("\n i=%4i",i); /* i=4567 */ printf("\n i=%6i",i); /* i= 4567 */ printf("\n i=%3i",i); /* i=4567 */ printf("\n i=%06i",i); /* i=004567 */ x=76.123001; printf("\n x=%10f",x); /* x= 76.123001*/

Page 109: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

107

printf("\n x=%010f",x);/* x=076.123001*/ printf("\n %3s","testare");/* testare */ printf("\n %10s","testare");/* testare*/ }

Precizia de afişare se specifică printr-un punct urmat de un întreg pozitiv. Specificatorul de precizie astfel obţinut se plasează imediat după dimensiunea câmpului de afişare (când este precizată). Interpretarea lui depinde de tipul de date avut în vedere.

De exemplu, descriptorul %7.3f indică afişarea unui număr real pe minim 7 coloane şi cu 3 cifre zecimale după virgulă. Lucrurile se petrec asemănător dacă în loc de %f se foloseşte %e sau %E. Dacă se foloseşte unul din descriptorii %g sau %G specificatorul de precizie arată minimul de cifre semnificative.

Aplicat unui întreg, specificatorul de precizie arată numărul minim de cifre cu care va apare afişat întregul respectiv (dacă întregul nu are suficiente cifre atunci se completează la început cu numărul necesar de cifre 0).

Un descriptor de format prevăzut cu specificator de dimensiune şi specificator de precizie poate fi aplicat unui şir cu lungimea cuprinsă între valoarea specificatorului de dimensiune şi cea a specificatorului de precizie. Dacă se depăşeşte valoarea specificatorului de precizie, şirul se trunchiază.

Se poate impune alinierea la stânga a datelor plasând semnul – (minus) imediat după semnul % în cadrul descriptorului.

Programul următor ilustrează toate cazurile prezentate:

Exemplul 4.7

Afişarea unor valori folosind diverse facilităţi ale descriptorilor prezentaţi

#include "stdio.h" void main(void) { int i; double x; i=4567; printf("\n i=%3.7i",i); /* i=0004567 */ printf("\n i=%7.3i",i); /* i= 4567 */

Page 110: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

108

printf("\n i=%-7.3i",i); /* i=4567 */ x=76.123401; printf("\n x=%10.3f",x); /* x= 76.123*/ printf("\n x=%-10.3f",x); /* x=76.123*/ printf("\n x=%3.7f",x); /* x=76.1234010*/ printf("\n x=%10.2e",x); /* x= 7.61e+01*/ printf("\n x=%-10.1E",x); /* x=7.6E+01*/ printf("\n x=%10.3g",x); /*x= 76.1*/ printf("\n x=%-10.4G",x); /* x=76.12*/

printf("\n %.4s","testare"); /* test */ printf("\n %10.4s","testare");/* test*/ printf("\n %-10.4s","testare");/* test */ printf("\n %-1.10s","testare");/* testare*/ }

Funcţia de citire scanf() are forma generală:

int scanf(sir_format,lista_de_argumente); unde:

sir_format poate conţine descriptori de format, caractere de spaţiere albe, alte caractere;

lista_de_argumente este de forma: &var1,&var2,...,&varn. Prin &v se înţelege adresa variabilei v.

Funcţia întoarce numărul de argumente cărora li s-a atribuit o valoare sau constanta EOF (egală de obicei cu –1) în caz de insucces.

Precizări:

În marea lor majoritate descriptorii de format folosiţi la funcţia scanf() sunt identici cu cei de la funcţia printf(); practic, din tabelul prezentat anterior obţinem o listă validă pentru scanf(), îndepărtând %E,%X,%G. Folosiţi cu scanf(), descriptorii %f,%e,%g sunt echivalenţi.

Lista de argumente este citită de la stânga la dreapta şi asociată în această ordine cu lista de descriptori. Fiecare descriptor arată funcţiei scanf() tipul valorii care se va citi: întreg, real, şir, pointer etc.. Să observăm că aceste valori sunt transferate variabilelor v1,v2,...vn prin intermediul adreselor

Page 111: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

109

&v1,&v2,...&vn.

Este de menţionat faptul că în cazul citirii unui şir, deoarece însuşi numele şirului reprezintă o adresă, operatorul de luare a adresei & nu va mai preceda obligatoriu numele şirului. Un exemplu de program care citeşte şiruri de caractere este prezentat în UI5, în paragraful Funcţii pentru prelucrarea şirurilor de caractere).

Ca şi în cazul funcţiei printf() descriptorii de format pot avea şi un modificator de lungime maximă a şirului de caractere care va fi citit. De exemplu, apelul:

scanf(”%15s”,sir); are drept consecinţă citirea a maximum 15 caractere din şirul de intrare şi atribuirea şirului format variabilei sir. Dacă şirul de intrare are mai mult de 15 caractere, caracterele în plus se ignoră; la un nou apel al funcţiei scanf() explorarea şirului de intrare începe cu aceste caractere anterior ignorate.

Caracterele albe de spaţiere în şirurile de intrare pot fi blank-urile (spaţiile albe), tab-urile (spaţii tab), sau caracterul linie nouă (tasta enter). Aceste caractere albe de spaţiere sunt ignorate dacă în şirul format avem corespunzător între descriptori cel puţin un spaţiu. De asemenea, orice alt caracter poate fi folosit ca separator în fluxul de intrare, cu condiţia ca el să fie plasat corespunzător şi între descriptorii de format din sir_format. Dacă această condiţie nu e îndeplinită, la prima neconcordanţă (de la stânga la dreapta) între separatorii din fluxul de intrare şi cei din sir_format execuţia funcţiei scanf() se încheie. De exemplu, apelul funcţiei scanf():

scanf(”%d,%f,%s”,&x,&y,sir); realizează o atribuire corectă a datelor de intrare dacă ele sunt despărţite prin virgulă. Pentru a atribui variabilei x valoarea 32, lui y valoarea 10.75 şi variabilei sir valoarea anI, în fluxul de intrare trebuie să avem 32,10.75,anI.

Page 112: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

110

Exemplul 4.8

Citirea numerelor reale x şi X de la tastatură, calculul produsului x*X şi afişarea lui în format exponenţial.

#include "stdio.h" void main(void) { float x,X; printf("\n Tastati doua numere separate

prin spatiu "); scanf("%f %f",&x,&X); X=X*x; printf("\n Produsul X*x este = %e", X); }

Observaţii:

X şi x sunt variabile diferite;

X=X*x; este o expresie de atribuire care se poate scrie mai scurt sub forma X*=x; cu ajutorul operatorului compus *=.

Funcţiile scanf() şi printf() sunt funcţii de intrare/ieşire standard cu destinaţie generală. Din considerente de eficienţă (cod mai mic, viteză de execuţie sporită, comoditate în programare etc.) limbajul C pune la dispoziţia utilizatorului şi funcţii cu destinaţie specială.

Funcţii speciale pentru citirea/scrierea caracterelor la nivelul consolei

Standardul ANSI C prevede două funcţii simetrice pentru transferul caracterelor la nivelul consolei: funcţiile getchar() şi putchar(). Ele îşi au prototipurile în ”stdio.h”.

Funcţia pentru citire getchar() are forma generală

int getchar(void);

şi întoarce următorul caracter care va fi citit. Dacă s-a atins sfărşitul şirului sau se produce o eroare se întoarce EOF.

Deşi nu aparţin standardului ANSI C, totuşi, funcţiile getch(), getche(), putch() sunt incluse frecvent în biblioteca standard a compilatoarelor compatibile DOS. Prototipurile

Page 113: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

111

acestor funcţii sunt în fişierul header ”conio.h”.

Funcţiile getch() şi getche() sunt echivalente funcţional cu funcţia getchar(). Forma generală este:

int getch(void); int getche(void);

 

Spre deosebire de funcţia getchar() unde caracterul tastat este citit numai dacă se apasă în continuare tasta Enter, funcţiile getch() şi getche() preiau caracterul imediat după ce a fost tastat (fără a mai apăsa Enter). De asemenea, funcţia getch() preia caracterul de la tastatură fără a-l afişa pe ecran, în timp ce getche() afişează pe ecran caracterul citit (citire cu ecou).

Funcţia pentru afişare putchar() are forma generală

int putchar(int ch);

unde ch este caracterul care se afişează. Funcţia întoarce în caz de succes caracterul scris, iar în caz contrar EOF.

Funcţia putch() este echivalentă funcţional cu putchar() şi are forma generală

int putch(int ch);

unde ch este caracterul care se afişează. Este de asemenea o funcţie nestandard frecvent utilizată.

Exemplul 4.9

Citirea si afişarea unui caracter folosind funcţiile speciale getche() şi putch().

#include "stdio.h" #include "conio.h" void main(void) { char x; printf("\n Tastati o litera! "); x=getche(); printf("\n Multumesc! Ati tastat litera "); putch(x); getch(); }

Page 114: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

112

Funcţii speciale pentru citirea/scrierea şirurilor de caractere la nivelul consolei

Funcţii speciale pentru citirea/scrierea şirurilor de caractere la nivelul consolei sunt gets() şi puts(). Ambele funcţii îşi au prototipurile în fişierul header ”stdio.h”. Deoarece în construcţia acestor prototipuri intervine noţiunea de pointer, care nu face obiectul acestui curs introductiv, ne limităm aici la a spune că prin apelul

gets(sir_destinatie); se citeşte un şir de la tastatură în sir_destinatie, iar apelul

puts(sir); are ca efect afişarea şirului sir pe ecran.

Dăm ca exemplu secvenţa de program:

. . . . . . . gets(x); . . . . . . . printf(”\n Sirul citit este =”); puts(x); . . . . . . .

Un program complet care utilizează funcţiile gets() şi puts() este prezentat în UI5 (vezi paragraful Funcţii pentru prelucrarea şirurilor de caractere).

Operatori. Clasificare

Operatorii sunt elemente de bază ale limbajului care arată ce operaţii trebuie executate asupra unor operanzi. În C, operanzi pot fi constantele, numele de variabile, numele de funcţii, expresiile. Bogata familie de operatori conferă limbajului C o trăsătură aparte. Clasificarea operatorilor C se poate face după mai multe criterii:

după numărul de operanzi prelucraţi (unari, binari, ternari);

după prioritatea avută în evaluarea expresiilor (clase de precedenţă);

după tipul operanzilor (aritmetici, relaţionali, logici şi la nivel de bit).

Page 115: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

113

Operatori unari, binari, ternari. Ţinând cont de numărul de operanzi prelucraţi, în C există operatori unari, binari şi ternari. Clasele rezultate nu sunt disjuncte, în sensul că, de exemplu, un operator unar poate fi şi binar. Astfel, în expresia -3 operatorul - (minus) este unar, iar în expresia a-3, este binar.

Singurul operator ternar este operatorul condiţional ?:. Operanzii săi sunt plasaţi după schema operand1 ? operand2 : operand 3.

Clase de precedenţă. Priorităţile operatorilor impun ordinea de evaluare a expresiilor. Ca şi în calculele algebrice obişnuite ordinea de evaluare poate fi modificată cu ajutorul parantezelor rotunde.

Operatorii care au priorităţi egale, aparţin aceleiaşi clase de precedenţă. Lista operatorilor grupaţi după clase de precedenţă este dată în Tabelul 4.7.

Tabelul 4.7. Clase de precedenţă Clasa Operatori 1 (paranteze, op. de selecţie) () [] -> . 2 (op.unari) ++ -- ! ~ - + & * sizeof cast 3 (op. multiplicativi) % / * 4 (op. aditivi) + - 5 (op. shift) << >> 6 (op. relaţionali) < <= > >= 7 (op. relaţionali) == != 8 (“ŞI” pe bit) & 9 (“SAU” exclusiv bit cu bit) ^ 10 (“SAU” bit cu bit) | 11 (“SI” logic) && 12 (“SAU” logic) || 13 (operator condiţional) ?: 14 (atribuire) = += -= *= etc. 15 (secvenţiere) ,

Funcţionează, de asemenea, reguli de asociere de la stânga la dreapta sau de la dreapta la stânga. Singurii operatori care se asociază de la dreapta la stânga sunt operatorii unari şi operatorul ?:, restul se asociază de la stânga la dreapta.

Operatorul de atribuire = ocupă un loc aparte în familia operatorilor. Cu ajutorul lui putem să atribuim unei variabile o anumită valoare.

Page 116: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

114

Forma sa generală este:

v=e;

unde v este un nume de variabilă, iar e este o expresie. În C, membrul stâng şi membrul drept al unei atribuiri se mai numesc valoare stângă (lvalue), respectiv valoare dreaptă (rvalue). Spre deosebire de alte limbaje (Fortran, Pascal etc.) în C, operatorul de atribuire poate apare şi în interiorul unei expresii, fapt ce permite o compactare a codului sursă. De exemplu, două atribuiri succesive de genul:

A=pi*r*r; V=A*h;

pot fi scrise compact sub forma:

V=(A=pi*r*r)*h;

Practic, ce am scris mai sus este o instrucţiune expresie. Rezultatul evaluării expresiei (A=pi*r*r)este pi*r*r; după cum se vede, acest rezultat se poate folosi mai departe în calcule. Atribuirea valorii pi*r*r variabilei A apare ca un efect secundar al instrucţiunii expresie A=pi*r*r;.

Compilatorul C permite ca în expresii de genul

v=e; unde v şi e să aibă tipuri diferite. În această situaţie au loc conversii de tip. Regula de conversie este următoarea: valoarea membrului drept (valoarea lui e) se converteşte la tipul membrului stâng (tipul lui v). Deoarece sizeof (int) <= sizeof (float) <= sizeof (double), se spune că int este mai “slab“ decât float, care este la rândul său mai “slab“ decât double. Dacă membrul stâng este de un tip mai “slab“ decât tipul membrului drept pot avea loc pierderi de informaţie (prin trunchiere) sau depăşirea posibilităţilor de reprezentare. De exemplu, în secvenţa:

int x,y; float a,b; ......... x=a; b=y;

Page 117: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

115

variabila x va primi partea fără fracţie a valorii a sau un rezultat imprevizibil dacă se depăşesc posibilităţile de reprezentare, iar valoarea întreagă y va fi convertită la o valoare reprezentată în virgulă mobilă.

Consideraţiile de mai sus referitore la conversia tipurilor sunt valabile şi în situaţia în care cel puţin unul dintre cei doi operanzi ai operatorului de atribuire sunt variante ale tipului int (char, signed, unsigned, short, long) sau ale tipului double (long double).

În C este posibilă atribuirea multiplă, ca în exemplul de mai jos:

x=y=z=s=0;

Efectul este atribuirea valorii 0 variabilelor x,y,z,s.

De asemenea, în anumite situaţii se pot folosi operatorii de atribuire compusă. Practic, orice atribuire de genul:

variabila=variabila operator expresie;

unde operator poate fi ales din lista de operatori *, /, %, +, -, >>, <<, , &, ^ se poate scrie simplificat sub forma:

variabila operator=expresie;

De exemplu, expresia x=x+2; are acelaşi efect cu x+=2;

Dacă v e un operand oarecare cazurile uzuale de atribuire v=v+1 şi v=v-1 se pot scrie simplificat sub forma v++ şi respectiv v--. Operatorul ++ se numeşte operator de incrementare, iar -- operator de decrementare. Funcţie de poziţia lor faţă de operand ei pot fi operatori prefix sau postfix.

De exemplu:

x=x+1 se poate scrie x++ sau ++x,

x=x-1 se poate scrie x-- sau --x.

Dacă operandul nu apare în cadrul unei expresii, după cum

se vede din exemplul de mai sus, nu are importanţă dacă operatorii sunt prefix sau postfix. Când operandul apare în cadrul unei expresii, dacă este precedat de operatorul ++ sau -- se

Page 118: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

116

execută întâi incrementarea sau decrementarea operandului şi apoi este folosit în expresie; dacă este însă urmat de operatorul ++ sau -- incrementarea sau decrementarea se va face după folosirea sa în expresie.

De exemplu, expresia y=++x; este echivalentă cu secvenţa x=x+1; y=x;

Iar expresia y=x++; este echivalentă cu secvenţa y=x; x=x+1;

Să observăm că cele două secvenţe vor produce aceeaşi valoare pentru x şi valori diferite pentru y.

Folosirea operatorilor de incrementare şi decrementare este recomandabilă nu doar din raţiuni de simplificare a scrierii programelor ci şi datorită faptului că majoritatea compilatoarelor C generează coduri obiect foarte rapide în astfel de cazuri.

Operatorul de secvenţiere (virgula) permite construirea unei expresii ca o listă de alte expresii. Expresiile din listă se evaluează de la stânga la dreapta. Valoarea şi tipul întregii expresii este dat de ultima expresie din listă. De exemplu, în urma execuţiei secvenţei de program:

. . . . . int x=7,y=3,z,w; . . . . . z=(w=x<y,x+y);

z va primi valoarea 10. Explicaţia este următoarea: se evaluează mai întâi expresia w=x<y, apoi expresia x+y. Rezultatul evaluării expresiei x+y este 10, iar întreaga expresie (w=x<y,x+y) va primi această valoare care se va atribui lui z.

Practic, operatorul virgulă oferă o modalitate elegantă de a scrie mai multe expresii în secvenţă, sub forma compactă a unei singure expresii. În exemplul de mai sus, expresia

z=(w=x<y,x+y);

înlocuieşte secvenţa

w=x<y; z=x+y;

Operatorii ?,[,] vor fi prezentaţi mai pe larg în capitolele unde prezenţa lor este necesară: operatorul ?: la instrucţiuni

Page 119: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

117

condiţionale, parantezele pătrate [ şi ] la tipul de date tablou.

Limbajul C are următorii operatori aritmetici: -,+,*,/,%,--,++.

Semnificaţia lor rezultă din Tabelul 10 şi din prezentarea făcută anterior operatorilor ++ şi --. În plus vom face următoarele observaţii:

aplicat unor operanzi întregi, operatorul / va produce doar partea întreagă a împărţirii; de exemplu, secvenţa:

. . . int x,y; x=7; y=x/2; . . .

va produce valoarea 3 pentru y.

operatorul % aplicat unor operanzi întregi furnizează restul împărţirii acelor întregi; de exemplu, secvenţa:

. . . int x,y x=7; y=x%2; . . .

produce pentru y valoarea y=1, adică restul împărţirii lui 7 la 2.

Operatori relaţionali şi logici. Operatorii relaţionali din limbajul C sunt: <, >, <=, >=, ==, !=. Semnificaţia lor rezultă din Tabelul 4.7. În urma evaluării unei expresii în care intervin operatori relaţionali rezultă valoarea 0 pentru fals şi 1 pentru adevărat. Programul de mai jos afişează valorile anunţate în comentariile alăturate:

Exemplul 4.10

Afişarea valorilor unor expresii în care intervin operatori relaţionali

#include "stdio.h" #include "conio.h"

Page 120: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

118

void main(void) { float x=0, y=2.3; printf("\n x<y are valoarea %d",x<y) ;/*1*/ printf("\n x<=y are valoarea %d",x<=y);/*1*/ printf("\n x>y are valoarea %d",x>y); /*0*/ printf("\n x>=y are valoarea %d",x>=y);/*0*/ printf("\n x==y are valoarea %d",x==y);/*0*/ printf("\n x!=y are valoarea %d",x!=y);/*1*/ getch(); } Operatorii logici din C sunt: ! (NU logic), && (ŞI logic),

|| (SAU logic). Modul de acţiune al acestor operatori este prezentat în Tabelul 4.8.

Tabelul 4.8. Tabla valorilor de adevăr pentru operatori logici a b a && b a || b !a 0 0 0 0 1 0 1 0 1 1 1 0 0 1 0 1 1 1 1 0

Observaţii:

Din Tabelul 4.8 rezultă că operatorii logici && şi || au o prioritate mai mică decât operatorii relaţionali. Din acest motiv:

expresia a<=b||c>d e echivalentă cu (a<=b)||(c>d)

expresia a>b&&c<=d e echivalentă cu (a>b)&&(c<=d)

Concluzia este că în astfel de situaţii prezenţa parantezelor este opţională. Există însă cazuri în care parantezele sunt absolut necesare; de exemplu, dacă dorim să negăm expresia a>3 vom scrie !(a>3) şi nu !a>3. Expresia !(a>3) va returna corect valoarea 0 sau 1 funcţie de mărimea lui a, în timp ce expresia !a>3 are totdeauna valoarea 0 (datorită priorităţii mai mari a operatorului ! faţă de > se evaluează mai întâi !a care poate fi 0 sau 1; oricare ar fi valoarea lui a, rezultă în final valoarea 0).

Dacă într-o expresie formată din operanzi legaţi prin operatorul || , iar valoarea primului operand este 1, valoarea expresiei este 1 (vezi Tabelul 4.8) şi ceilalţi operanzi nu se mai evaluează. Dacă într-o expresie formată din operanzi legaţi prin operatorul &&, primul operand ia valoarea 0, valoarea expresiei

Page 121: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

119

este 0 iar ceilalţi operanzi nu se mai evaluează.

Deoarece prezenţa parantezelor nu reduce viteza de execuţie a expresiilor, ele pot fi folosite, alături de spaţii, la creşterea gradului de lizibilitate a unui program. Iată două expresii echivalente:

a=c<d||d>=c&&a<3;

a = (c<d) || (d>=c) && (a<3);

Este evident că cea de a doua expresie este mai uşor de citit.

Operatorii la nivel de bit din C permit programatorului să manevreze biţii aparţinând unor valori de tip char sau int (ei nu se aplică tipurilor de date float, double sau long double). Aceasta este una din acele facilităţi care apropie limbajul C de nivelul limbajelor de asamblare.

Conversii de tip implicite

Limbajul C oferă posibilitatea de a construi expresii cu date de tipuri diferite. Din acest motiv există un set de reguli de conversie a operanzilor la tipul operandului cel mai “tare“. Aceste reguli sunt cunoscute sub numele de avansare de tip (type promotion). Iată setul de reguli:

Variabile de tip char şi short se convertesc la tipul int.

Dacă un operand este long double

Atunci al doilea este convertit la long double;

Altfel dacă un operand este double

Atunci al doilea e convertit la double;

Altfel dacă un operand este float

Atunci al doilea e convertit la float;

Altfel dacă un operand este unsigned long

Atunci al doilea e convertit la unsigned long;

Altfel dacă un operand este long

Atunci al doilea e convertit la long;

Page 122: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

120

Altfel dacă un operand este unsigned

Atunci al doilea este convertit la unsigned.

Conversii de tip explicite (operatorul cast)

Operatorul de conversie explicită (cast) acţionează temporar, forţând schimbarea tipului expresiei la care se referă. Forma generală a operatorului este:

(tip)expresie; unde tip este tipul la care dorim să se facă conversia expresiei.

De exemplu, rezultatul evaluării expresiei

(float)i/2; unde i a fost definit prin

int i=3; este 1.5. Dacă în aceleaşi condiţii se evalua expresia i/2; rezultatul ar fi fost trunchiat la 1 (se împărţeau doi întregi).

� Test de autoevaluare

4.17. În C există tipurile fundamentale de date:

a. char, int, float, double, void

b. char, integer, real, double, void

c. char, int, float, double, nul, boolean

d. character, string, real, void

4.18. Declaraţiile

char x; şi signed char x; a. sunt echivalente

b. sunt greşite

c. sunt corecte

Page 123: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

121

4.19. Declaraţiile

short int x; şi

int x; a. sunt echivalente

b. sunt greşite

c. sunt corecte

4.20. Declaraţia float x,y; a. este echivalentă cu float x;float y;

b. este greşită

c. este echivalentă cu x,y:float;

d. este echivalentă cu real x,y;

4.21. Linia de program

char ch=’A’,Z; are semnificaţia:

a. variabila ch ia valori de la A la Z

b. variabila ch este de tip char şi este iniţializată cu valoarea ’A’, iar variabila Z este de tip char

c. tipul de date char ia valori de la A la Z

4.22. Liniile de program

const ore_zi=24; int ore_zi=24;

a. sunt echivalente

b.sunt corecte şi compatibile

c.sunt corecte şi incompatibile

4.23. Secvenţa de program

int x=10,y=20,z=5,w=7; printf(”\n x=%i y=%i z=%d”,x,y);

afişează:

a. x=10 y=20 z=5

Page 124: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

122

b. date de ieşire nedefinite

c. x=10 y=20

4.24. Secvenţa de program:

int x=10,y=20,z=5,w=7; printf(”\n x=%d y=%i”,x,y,z); a. afişează x=10 y=20

b. afişează x=10 y=20 z=5

c. este greşită

4.25. Instrucţiunea printf() de mai jos

printf(”\nuu!\taurul \n-are importanta!”); afişează

a. \nuu!\taurul\n-are importanta!

b. taurul n-are importanta!

c. uu!aurul -are importanta!

d. uu! aurul

e. -are importanta!

4.26. Secvenţa de program

int i=10,j=20; printf(”\n i=%i,j=%i”,j,i);

afişează

a. i=10, j=20

b. i=20, j=10

c. i=10% j=20%

4.27. Secvenţa de program

int i=10,j=20; printf(”\n i=%i,j=%j”,i,j); a. afişează i=10,j=20

b. este greşită

c. afişează i=%10,j=%20

4.28. Secvenţa de program

char a=’q’; printf(”\n a=%d”,a);

Page 125: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

123

a. este greşită deoarece %d este descriptor pentru tipul

int, nu pentru tipul char

b. este corectă şi afişează codul ASCII al caracterului q

c.este corectă şi afişează codul ASCII al caracterului a

d. este corectă şi afişează caracterul q

4.29. Secvenţa de program

float x=32.75; printf(”\n x=%e,x=%f”,x,x); a. este greşită deoarece argumentul x se repetă

b. este corectă şi va afişa x=32.75,x=32.75

c.este corectă şi va afişa

x=3.275000e+01,x=32.750000

4.30. Secvenţa de program

int x=439; printf(”\n %o”,x);

afişează:

a. 439

b. numărul 439 scris în baza 8

c. numărul 439 scris în baza 16

4.31. Secvenţa de program

int x=1011; printf(”\n %x”,x);

afişează:

a. valoarea lui x în binar

b. valoarea lui x în hexazecimal

c. valoarea lui x în octal

4.32. Secvenţa de program

int x=12; float y=31.42; printf(”\n x=%f y=%d”,x,y); a. afişează x=12 y=31.42

b. afişează x=12.0 y=31

Page 126: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

124

c. este greşită

4.33. Secvenţa de program

float x=10.5; printf(”\n x=%-10.5f”,x); a. afişează x=-10.5

b. afişează x=10.50000

c. este greşită

4.34. Secvenţa de program

float x=10.5; printf(”\n x=%10.5”,x); a. afişează x=10.5

b. afişează x= 10.50000

c. afişează x=10.50000

4.35. Despre secvenţele de program

float x; scanf(”%f”,x);

şi

float x; scanf(”%f”,&x);

se poate afirma că:

a. sunt corecte şi au acelaşi efect

b. prima secvenţă este corectă şi a doua incorectă

c. prima secvenţă este incorectă şi a doua corectă

4.36. Secvenţa de program

printf(”%.3s”,”abcde”); a. afişează abc

b. afişează abcde

c. este greşită

4.37. Dacă şirul care trebuie citit de la tastatură este abcdef atunci secvenţa

scanf(”%3s”,sir);

Page 127: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

125

a. este greşită, deoarece variabila sir nu e precedată de operatorul &

b. este greşită, deoarece şirul de intrare are 6 caractere, iar descriptorul %s prevede doar 3 caractere

c. este corectă, dar se citesc doar caracterele abc

4.38. Secvenţa de program

scanf(”%d;%f;%s”,&x,&y,sir);

a. este greşită, deoarece descriptorii de format sunt despărţiţi prin semnul ;

b. este greşită, deoarece variabila sir nu e precedată de operatorul &

c. este corectă şi realizează corect citirea dacă datele din fluxul de intrare sunt despărţite prin semnul ;

4.39. Operatorii în C pot fi:

a. unari, binari

b. unari, binari, ternari

c. unari, binali, termali

4.40. Operatorii + şi - pot fi:

a. numai unari

b. numai binari

c. unari sau binari

4.41. Secvenţa de program:

float x; int i; x=34.21; i=x;

a. este greşită deoarece se atribuie valoarea reală din x variabilei întregi i

b. este corectă

c. este corectă, iar i va primi valoarea 34

4.42. Secvenţa de program

int i; float x;

Page 128: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

126

i=34; x=i; a. este greşită, deoarece se atribuie valoarea întreagă

din i variabilei reale x

b. este corectă

c. este corectă, iar x va primi valoarea 34 convertită în virgulă mobilă.

4.43. Linia de program

V=(A=B*b)*h; a. este eronată deoarece conţine operatorul de atribuire

= de două ori

b. este corectă

c. este corectă şi este echivalentă cu secvenţa de program

A=B*b; V=A*h;

4.44. Linia de program

a=b=c=1; a. este corectă şi e echivalentă cu secvenţa

a=1; b=1; c=1;

b. este corectă şi e echivalentă cu secvenţa

1=a=b=c; c. este greşită deoarece operatorul de atribuire apare de

mai multe ori

4.45. Expresia

x+=1; a. este greşită;

b. este corectă şi echivalentă cu x=x+1;

c. este corectă şi echivalentă cu x++;

d. este corectă şi echivalentă cu ++x;

Page 129: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

127

4.46. Expresia

y=--x; a. este greşită

b. este corectă şi echivalentă cu secvenţa

x=x-1; y=x;

c. este corectă şi echivalentă cu secvenţa

y=x; y=x-1;

4.47. Expresia

y=x--; a. este greşită

b. este corectă şi echivalentă cu secvenţa

x=x-1; y=x;

c. este corectă şi echivalentă cu secvenţa

y=x; x=x-1;

4.48. În urma execuţiei secvenţei de program:

int i,j; i=19; j=i/4; a. j ia valoarea 4

b. j ia valoarea 4.75

c. j ia valoarea 5

4.49. În urma execuţiei secvenţei de program:

int i,j; i=19; j=i%4; a. j ia valoarea 3

b. j ia valoarea 4

c. j ia valoarea 4.75

4.50. Dacă a,b,c,d sunt variabile numerice atunci expresia (a<b)||(c>d) se poate scrie:

Page 130: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

128

a. a<b||c>d

b. a<(b||c)>d

c. c>d||a<b

4.51. În secvenţa de program

int x=3,y=4,a,b,z; scanf(”%i %i”,&a,&b); z=(y>x)||(a<b);

variabila z va lua

a. o valoare nedefinită

b. valoarea 1

c. o valoare care depinde de a şi b

4.52. În secvenţa de program

int x=3,y=4,a,b,z; scanf(”%i %i”,&a,&b); z=(x>y)&&(a<b);

variabila z va lua

a. valoare nedefinită

b. valoarea 0

c. valoare care depinde de a şi b

4.53. În secvenţa de program

int a=3,b=4,x,y,z; z=(x=a+b,y=x); a. x ia valoarea 7

b. y ia valoarea 7

c. z ia valoarea 7

4.54. Secvenţa de program

int i=7; float x; x=(float)i/4; printf(”\n x=%f”,x); . . . . . a. este greşită

Page 131: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

129

b. este corectă şi afişează x=1.750000

c. este corectă şi afişează x=1

Răspunsurile testelor de autoevaluare

4.1. b 4.2. b 4.3. a, b 4.4. c 4.5. d

4.6. b 4.7. c 4.8. b 4.9. a 4.10. b

4.11. b 4.12. b 4.13. c 4.14. b 4.15. c

4.16. c 4.17. a 4.18. a, c 4.19. c 4.20. a

4.21. b 4.22. c 4.23. b 4.24. a 4.25. d

4.26. b 4.27. a 4.28. b 4.29. c 4.30. b

4.31. b 4.32. c 4.33. b 4.34. b 4.35. c

4.36. a 4.37. c 4.38. c 4.39. b 4.40. c

4.41. b, c 4.42. b, c 4.43. b, c 4.44. a

4.45. b,c,d 4.46. b 4.47. c 4.48. a 4.49. a

4.50. a, c 4.51. b 4.52. b 4.53. a, b, c 4.54. b

Lucrare de verificare ...................................................✍

Descrieţi succint limbajul de programare C.

Scrieţi un program C care:

citeşte de la tastatură două numere întregi a şi b, două numere reale c şi d, două caractere c1 şi c2 şi un şir de caractere s.

afişează a şi b pe minim 4 poziţii, c pe minim 4 poziţii cu două zecimale şi d în format ştiinţific, caracterele c1 şi c2 şi şirul s.

determină şi afişează a+b, a/b, c/d, c1==c2, (c-d)/a+2*c/b-1.5, (a<c) || (b<d).

Page 132: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

130

Rezumat

Limbajul C, propus în anii ’70 de către Dennis Ritchie, este un limbaj de programare puternic şi flexibil, de nivel mediu, îmbinând avantajele limbajelor de nivel coborât cu cele ale limbajelor de nivel înalt: este performant din punctul de vedere al vitezei de execuţie şi oferă posibilitatea folosirii structurilor de control, a datelor structurate, a elaborării de programe portabile.

Limbajul C oferă posibilitatea organizării programelor în module şi permite implementarea unor structuri de control şi tipuri de date care facilitează programarea structurată. Are un număr foarte mic de cuvinte cheie (32), este uşor de învăţat şi de folosit.

Structura generală a unui program C cuprinde directive preprocesor (instrucţiuni destinate compilatorului), declaraţii globale şi funcţii utilizator (printre care apare cel puţin funcţia principală a programului, main()).

O funcţie C este declarată dacă i se prezintă numai antetul (prototipul) şi este definită dacă, pe lângă antet, se descrie şi corpul (instrucţiunile care o formează). Apelul unei funcţii (în altă funcţie, excepţie făcând funcţia main()) presupune transferul controlului execuţiei programului către instrucţiunile din corpul funcţiei, execuţia acestora şi revenirea în funcţia apelantă în punctul unde se execută operaţia care urmează.

Elementele de bază ale limbajului sunt alfabetul şi vocabularul (atomii lexicali). Prin combinarea atomilor lexicali după regulile specifice de sintaxă se construiesc linii valide de program şi, în final, un program.

Alfabetul este alcătuit simboluri afişabile şi simboluri neafişabile (secvenţe escape sau coduri backslash-caracter), iar atomii lexicali sunt: identificatori (nume), constante, operatori, semne de punctuaţie şi simboluri speciale.

Tipurile de date fundamentale în C sunt: char, int, float, double şi void, pentru care domeniul de valori poate fi modificat utilizând modificatorii de tip: signed, unsigned, short şi long.

Declaraţiile de variabile se fac sub forma

tip lista_de_variabile;

Dacă pe linia de declarare o variabilă este iniţializată se

Page 133: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

131

spune că are loc o definire a variabilei.

Dacă tip lipseşte se consideră implicit că tipul este int.

Pe lângă funcţiile utilizator, elaborate de programator, în programe se folosesc şi funcţii standard, predefinite, care sunt recunoscute şi executate la compilare prin includerea în program a fişierelor antet corespondente care le conţin. Funcţiile standard ale limbajului se pot clasifica în: funcţii de intrare/ieşire, funcţii pentru prelucrarea caracterelor, funcţii pentru prelucrarea şirurilor de caractere etc.

Funcţiile de intrare (pentru transferul de date de la tastatură în memoria calculatorului) şi funcţiile de ieşire (pentru transferul din memoria calculatorului pe ecran) pentru consolă sunt:

funcţii generale de intrare/ieşire (scanf() şi printf());

funcţii speciale de intrare/ieşire:

funcţii pentru citirea şi scrierea caracterelor: getchar(), putchar(), getch(), getche(), putch();

funcţii pentru citirea şi scrierea şirurilor de caractere: gets() şi puts().

Descriptorii de format (%d sau %i, %c, %f, %s, %u, %e sau %E, %x sau %X, %o, %g sau %G şi %p)servesc la efectuarea conversiilor dintre reprezentarea externă şi internă (la citire) şi între reprezentarea internă şi externă (la scriere); formatul extern presupune succesiuni de caractere, iar cel intern succesiuni de cifre binare.

Operatorii sunt elemente de bază ale limbajului care arată ce operaţii trebuie executate asupra unor operanzi. În C, operanzi pot fi constantele, numele de variabile, numele de funcţii şi expresiile. Operatorii C se clasifică după:

numărul de operanzi prelucraţi (unari, binari, ternari);

prioritatea avută în evaluarea expresiilor (clase de precedenţă);

tipul operanzilor (aritmetici, relaţionali, logici şi la nivel de bit).

Page 134: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

132

În C este posibilă atribuirea multiplă, ca în exemplul:

x=y=z=s=0;

De asemenea, C permite folosirea operatorilor de atribuire compusă de forma op=. De exemplu, expresia x=x+2; are acelaşi efect cu x+=2;

Operatorii aritmetici sunt: -,+,*,/,%,--,++.

Operatorii relaţionali sunt: <, >, <=, >=, ==, !=.

Operatorii logici sunt: !, &&, ||.

Bibliografie

1. Cristian Marinoiu, Programarea în limbajul C, Editura Universităţii din Ploieşti, Ploieşti, 2000.

2. Brian Kernighan, Dennis Ritchie, The C programming Language, Prentice Hall, 1988.

3. Herbert Schildt C: Manual complet, Editura Teora, Bucuresti, 1997.

 

Page 135: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

133

UI5. Programare în limbajul C

Obiectivele unităţii de învăţare – pag 133

Instrucţiuni de control ale programului – pag 133

Test de autoevaluare – pag 157

Tablouri şi şiruri de caractere – pag 168

Test de autoevaluare – pag 177

Răspunsurile testelor de autoevaluare – pag 181

Lucrare de verificare – pag 182

Rezumat – pag 182

Bibliografie – pag 185

Obiectivele unităţii de învăţare

Familiarizarea cu instrucţiunile de control ale limbajului de programare C.

Realizarea conexiunilor corecte între structurile algoritmice fundamentale discutate în UI4 şi implementările acestora în limbajul C care sunt instrucţiunile de control.

Abilitatea de a integra corect noţiunile teoretice în practică prin scrierea de programe care rezolvă diverse probleme elementare.

Durata: 10 ore

Instrucţiuni de control ale programului

În acest capitol se prezintă instrucţiunile de control ale unui program C: instrucţiunea expresie, instrucţiunile de decizie (sau de selecţie), instrucţiunile iterative (repetitive sau de ciclare) şi

Page 136: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

134

instrucţiunile de salt. În situaţia în care sintaxa limbajului impune utilizarea unei singure instrucţiuni, dar logica programului cere folosirea unei secvenţe de instrucţiuni, secvenţa de instrucţiuni se organizează ca o instrucţiune bloc (sau instrucţiune compusă). O instrucţiune bloc începe cu { şi se termină cu }.

Instrucţiuni expresie

Instrucţiunea expresie are forma generală:

expresie;

unde expresie are efect lateral (conţine o atribuire sau reprezintă un apel de funcţie).

Secvenţa de program următoare conţine exemple de instrucţiuni expresie:

. . . x=(a+b)*c; x+=2; p++; getch();

Instrucţiuni de decizie

INSTRUCTIUNEA IF

Forma generală a instrucţiunii if este:

if(expresie) instructiune_1; else instructiune_2;

Efectul instrucţiunii este următorul: dacă expresie este adevărată (diferită de zero) se execută instructiune_1 în caz contrar (expresie este egala cu zero) se execută instructiune_2. Figura 5.1 ilustrează modul de execuţie al instrucţiunii if.

Page 137: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

135

Figura 5.1. Modul de execuţie al instrucţiunii if

Exemplul 5.1

Programul calculează şi afişează radicalul dintr-un număr.

#include "stdio.h" #include "conio.h" #include "math.h" void main(void) { float x,y; printf("\n Introduceti x="); scanf("%f",&x); if (x<=0) printf("\n Calcul imposibil"); else { y=sqrt(x); printf("\n y=%f",y); } getch(); }

Observaţii:

Sintaxa generală a instrucţiunii if cere pe ambele alternative câte o instrucţiune. În situaţia în care pe o alternativă sunt necesare mai multe instrucţiuni acestea vor fi grupate cu ajutorul acoladelor într-o instrucţiune bloc. Astfel, în exemplul de mai sus, secvenţa

expresie

instrucţiune_1 instrucţiune_2

Fals Adevărat

Page 138: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

136

{ y=sqrt(x); printf("\n y=%f",y); }

este o instrucţiune bloc.

Dacă alternativa else a instrucţiunii if este vidă atunci se poate scrie:

if(expresie) instructiune_1 else;

sau şi mai simplu

if(expresie) instructiune;

formă cunoscută sub numele de if cu ramură vidă. Instrucţiunea instructiune se execută numai dacă expresia este adevărată, adică se execută condiţionat. Modul de execuţie al instrucţiunii if cu ramură vidă este ilustrat în Figura 5.2.

Figura 5.2. Modul de execuţie al instrucţiunii if cu ramuă vidă

expresie

instrucţiune

Adevărat Fals

Page 139: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

137

Exemplul 5.2

Programul calculează maximul dintre două numere.

#include "stdio.h" #include "conio.h" void main(void) { float x,y,max; printf("\n x="); scanf("%f",&x); printf("\n y="); scanf("%f",&y);; max=x; if (max<y) max=y; printf("\n Maximul dintre x=%.2f si y=%.2f este=%.2f",x,y,max); getch(); }

Dacă în structura unei instrucţiuni if intervin alte instrucţiuni if avem de a face cu o structură de instrucţiuni if incluse sau imbricate. Forma generală a unei astfel de structuri este următoarea:

if(expr1) instr1; else if(expr2) instr2; else . . . . . . if(exprn) instrn; else instrn+1

Efectul execuţiei unei instrucţiuni if imbricate este următorul: dacă nu există i, i=1,...,n astfel încât expresia expri să fie adevărată, se execută instrn+1, în caz contrar se execută prima instrucţiune (considerând evaluarea de sus în jos), instri pentru care expri este adevărată, iar restul instrucţiunilor se ignoră.

Pentru n “mare“, folosind o aliniere strictă, se ajunge la o

Page 140: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

138

structură cu adâncime mare (mult deplasată spre dreapta). Din acest motiv se foloseşte de obicei forma:

if(expr1) instructiune1; else if(expr2) instructiune2; else if(expr3) instructiune3; . . . . . . else instructiunen+1;

numită şi scara if-else-if.

Exemplul 5.3

Programul citeşte coordonatele unui număr şi stabileşte în ce cadran se află acesta.

#include "stdio.h" #include "conio.h" void main(void) { float x,y; printf("\n abscisa x="); scanf("%f",&x); printf("\n ordonata y="); scanf("%f",&y); if (x>=0 && y>=0) printf("\n Numarul apartine cadranului I"); else if (x<0 && y>=0) printf("\n Numarul apartine cadranului II"); else if(x<0 && y<0) printf("\n Numarul apartine cadranului III"); else printf("\n Numarul apartine cadranului IV"); getch(); }

Ţinând cont că în limbajul C orice expresie diferită de zero este adevărată, o secvenţă de genul

Page 141: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

139

if(expr!=0) instructiune;

este echivalentă cu

if(expr) instructiune;

formă care va fi întotdeauna preferată.

✎ Care este diferenţa dintre structurile if şi if-else?

Cuvântul else se asociază întotdeauna cu cel mai apropiat if incomplet care nu este deja asociat cu un else şi care este în acelaşi bloc cu el. De exemplu, în secvenţa

if(x) if(y) printf(”\n x si y nenuli”); else printf(”\n x nul”);

alinierea şi mesajele sugereză asocierea lui else cu primul if. În realitate, else se asociază cu cel de-al doilea if, fiind adecvată alinierea

if(x) if(y) printf(”\n x si y nenuli”); else printf(”\n x nul”);

Dacă totuşi vrem să punem în practică prima intenţie putem folosi una din formele echivalente:

a) if(x) { if(y) printf(”\n x si y nenuli”); } else printf(”\n x nul”); b) if(x) if(y) printf(”\n x si y nenuli”); else; else printf(”\n x nul”);

Page 142: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

140

c) if(x&&y) printf(”\n x si y nenuli”); else if(!x) printf(”\n x nul”);

În ideea creerii unor programe „dense„ se pot scrie construcţii de genul

if( (c=getch() ) == ’a’) putch(’a’); else printf(”\n caracter diferit de a”);

unde expresia condiţională conţine o atribuire.

Construcţiile “dense” trebuie facute însă cu grijă, deoarece este posibil să avem surprize neplăcute. Secvenţa de mai jos

x=y=7; a=5;b=6; if((x=a)(y=b)) printf(”\nx=%i si y=%i”,x,y);

va produce x=5, y=7 şi nu x=5, y=6 cum ne-am fi aşteptat. Pentru ca expresia (x=a)(y=b) să fie adevărată este suficient ca numai una din expresiile (x=a) sau (y=b) să fie adevărată. Cu alte cuvinte, se execută atribuirea x=5, expresia (x=5) ia valoarea adevărat, valoarea expresiei (y=b) nu mai are importanţă şi deci atribuirea y=6 nu mai are loc.

OPERATORUL CONDIŢIONAL ? :

Operatorul condiţional ?: este un operator ternar, iar forma sa generală este:

expr1?expr2:expr3;

Efectul execuţiei unei astfel de secvenţe este echivalent cu efectul execuţiei secvenţei:

if expr1 expr2; else expr3;

Page 143: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

141

În plus, expresia expr1 ? expr2 : expr3 va lua valoarea expr2 sau expr3 după cum expr1 este adevărată sau nu.

Exemplul 5.4

Programul afişează maximul dintre două numere a şi b citite de la tastatură.

#include "stdio.h" #include "conio.h" void main(void) { int a,b; printf("\n a="); scanf("%i",&a); printf("\n b="); scanf("%i",&b); printf("\n Maximul dintre a=%i si b=%i este %i",a,b,a<b?b:a); getch(); }

INSTRUCTIUNEA switch

Instrucţiunea switch permite selecţia unei alternative din mai multe posibile într-o formă comodă şi elegantă.

Forma generală a instrucţiunii este:

switch(expresie) { case c1:secventa de instructiuni1;break; case c2:secventa de instructiuni2;break; . . . . . . . . case cn:secventa de instructiunin;break; default:secventa de instructiunin+1;break; }

unde:

expresie este expresia selectoare care trebuie să fie de tip întreg;

c1,c2,...,cn sunt constante de tip întreg distincte între ele;

default este o etichetă opţională;

secvenţa instructiunii, pentru orice

Page 144: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

142

i=1,...,n+1 se poate constitui sau nu într-un bloc de instrucţiuni, poate să fie vidă sau nu;

break este o instrucţiune care permite saltul la prima instrucţiune aflată după structura switch. Prezenţa sa este opţională.

Efectul instrucţiunii este următorul:

Dacă există un i astfel încât expresia selectoare este egală cu ci, se execută secvenţa instructiunik, k>=i până la primul break întâlnit sau până la sfârşitul instrucţiunii switch.

Dacă pentru orice i=1,...,n constantele ci sunt diferite de expresia selectoare se execută instructiunen+1, dacă există opţiunea default sau se iese direct din switch, dacă aceasta lipseşte.

Exemplul 5.5

Programul citeşte una din literele a,A,m,M,p,P de la tastatură şi afişează o listă de nume care încep cu una din aceste litere, fără să ţină cont dacă litera este mare sau mică. Dacă se tastează alt caracter se afişează un mesaj de eroare.

#include "stdio.h" #include "conio.h" void main(void) { printf("\n Tastati una din literele:

a,A,m,M,p,P "); switch(getch())

{ case 'a': case 'A':printf("\n Aurel,Ana,Andrei"); break; case 'm': case 'M':printf("\n Maria,Mihai,Marin"); break; case 'p': case 'P':printf("\n Paula,Petre,Pavel"); break; default:printf("\n Ati tastat gresit !");

} getch(); }

Page 145: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

143

Observaţie. În programul de mai sus, indiferent dacă s-a tastat a sau A se afişează aceeaşi listă de nume: Aurel, Ana, Andrei. Explicaţia este următoarea. Dacă se tastează a se “intră“ în switch, prin case 'a'. Secvenţa de prelucrări corespunzătoare fiind vidă şi neântâlnindu-se nici o instrucţiune break se trece şi se execută secvenţa de prelucrări corespunzătoare constantei case 'A' (adică afişarea listei). Deoarece secvenţa se încheie cu break se “iese“ din switch. Analog se întâmplă şi cu grupurile de litere m,M şi p,P.

✎ Instrucţiunea switch este implementarea în limbajul C a

cărei structuri algoritmice fundamentale?

Instrucţiuni iterative

Instrucţiunile iterative (repetitive sau de ciclare) permit ca una sau mai multe instrucţiuni să fie repetate. Numărul de iteraţii depinde de îndeplinirea unei condiţii. Dacă testul asupra condiţiei se face înaintea instrucţiunilor care se repetă, se spune că iteraţia este cu test iniţial; în caz contrar iteraţia este cu test final.

În limbajul C există două instrucţiuni cu test iniţial, while şi for şi o instrucţiune cu test final, do - while.

INSTRUCTIUNEA while

Forma generală a instrucţiunii while este:

while(conditie) instructiune;

unde:

conditie poate fi orice expresie;

instructiune poate fi o instrucţiune simplă, vidă sau o instrucţiune compusă (numită şi corpul ciclului).

Efectul instrucţiunii este următorul: se execută instructiune cât timp conditie este adevărată (diferită de zero). Atunci când conditie devine falsă (egală cu zero), execuţia programului continuă cu instrucţiunea imediat următoare. Organigrama de mai jos ilustrează sugestiv modul de

Page 146: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

144

lucru al instrucţiunii while.

Figura 5.3. Modul de lucru al instrucţiunii while

Observaţii:

Dacă din start condiţia este falsă, instructiune nu se execută niciodată.

Ieşirea din ciclu se poate face normal (ca efect al prelucrărilor din instructiune, atunci când după un număr de paşi conditie devine falsă), anormal (printr-o instrucţiune de salt care transferă execuţia programului din interiorul ciclului în afara lui) sau “niciodată“ (conditie rămâne mereu adevărată, şi se obţine aşa zisa buclă eternă).

Prezentăm mai jos un exemplu de program unde apare foarte naturală prezenţa testului iniţial în buclă şi deci folosirea instrucţiunii while.

Exemplul 5.6

Calculul lungimii unui şir de caractere citit de la tastatură; sfârşitul şirului este marcat de tasta Enter (caracterul ’\r’).

#include "stdio.h" #include "conio.h" void main(void) { int i=0; printf("\n Tastati un sir:\n"); while (getche()!='\r') i++; printf("\n Lungimea sirului =%d",i); getch(); }

Fals

instrucţiune

Adevărat

condiţie

Page 147: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

145

INSTRUCTIUNEA for

În C, instrucţiunea for prezentă şi în alte limbaje, are implementarea cea mai flexibilă. Ea depăşeşte cadrul tradiţional în care este plasată de obicei: instrucţiune cu contor (variabilă de control) recomandată spre a fi folosită ori de câte ori se cunoaşte numărul de iteraţii.

Forma generală a instrucţiunii for este:

for(initializare;conditie;actualizare) instructiune;

Semnificaţia tradiţională a celor trei componente este următoarea:

initializare este de regulă o instrucţiune de atribuire folosită pentru iniţializarea contorului ciclului;

conditie este o expresie care determină sfârşitul ciclului;

actualizare se referă la felul în care se modifică variabila contor.

Instrucţiunea for este echivalentă cu secvenţa de instrucţiuni

initializare while(conditie) { instructiune actualizare }

De aici rezultă şi efectul execuţiei sale: se execută blocul instructiune–actualizare cât timp conditia este îndeplinită.

Exemplul 5.7

Programul realizează suma a n numere reale.

#include "stdio.h" #include "conio.h" void main(void) { float s=0,x;

Page 148: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

146

int i,n; printf("\n n="); scanf("%i",&n); for (i=0;i<n;i++) { printf("\n x="); scanf("%f",&x); s+=x; } printf("\n Suma este =%f",s); getch(); }

Observaţii:

Componenta initializare a instrucţiunii for poate conţine atribuiri care nu se referă neapărat la variabila contor. În exemplul de mai sus iniţializarea variabilei s se poate face în componenta initializare a ciclului for cu ajutorul operatorului virgulă, astfel:

for(s=0,i=0;i<n;++i) { . . . . . . } . . . . . .

Componenta actualizare a instrucţiunii for poate să conţină mai multe variabile contor.

Variabila contor nu trebuie să fie prezentă obligatoriu în componenta conditie a unei instrucţiuni for.

Exemplul 5.8

Afişarea termenilor şirului lui Fibonacci mai mari ca 1 şi mai mici ca un număr dat m. Şirul are forma 1, 1, 2, 3, 5, 8, …, adică primii doi termeni sunt egali cu 1, iar orice alt termen se obţine ca sumă a celor doi termeni care-l preced.

#include "stdio.h" #include "conio.h" void main(void) {

Page 149: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

147

int a,b,c,m,i; printf("\n Limita de afisare ="); scanf("%i",&m); printf("\n Termenii sirului Fibonacci < %i\n",m); printf("\n 1 1 "); for (i=3,a=b=1,c=2;c<m;i++) { printf("%i ",c); a=b;b=c; c=a+b; } getch(); }

Exemple:

Dacă în programul precedent renunţăm la ideea de a afişa numărul de ordine al termenilor putem folosi secvenţa:

for(a=b=1,c=2;c<m;) { printf(”\n Termenul =%i”,c) a=b;b=c; c=a+b; }

Se observă absenţa componentei actualizare.

Secvenţa de program

int i=50000; for(;i;i--);

are ca efect introducerea unei temporizări egală cu timpul necesar decrementării contorului i de la voloare 50000 la 0. Aici se observă absenţa componentei initializare şi totodată ciclarea unei instrucţiunii vide.

Oricare din componentele initializare, conditie, actualizare ale instrucţiunii for poate să lipsească, însă delimitatorii ; trebuie să fie prezenţi. Lipsa componentei conditie este interpretată ca fiind echivalentă cu prezenţa unei expresii condiţionale adevărate. Din acest motiv, secvenţa

for(;;);

Page 150: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

148

creează un ciclu infinit sau o buclă eternă.

INSTRUCTIUNEA do-while

Este recomandabil să se folosească instrucţiunea do-while când instrucţiunea care reprezintă corpul ciclului trebuie executată cel puţin o dată.

Forma generală a acestei instrucţiuni este:

do { instructiuni } while(conditie);

Când corpul ciclului este format dintr-o singură instructiune acoladele pot să lipsească. Totuşi, este recomandabil să se păstreze chiar şi în această situaţie pentru a distinge mai uşor o instrucţiune while care începe, de o instrucţiune do-while care se termină.

Efectul instrucţiunii este următorul: se execută secvenţa de instructiuni cât timp expresia condiţională conditie este adevărată. Organigrama de mai jos ilustrează cu claritate modul de execuţie al ciclului do-while.

Figura 5.4. Modul de execuţie al instrucţiunii do-while

Observaţii:

Datorită aşezării testului de condiţie după corpul ciclului, este evident că grupul de instructiuni se execută cel puţin o dată.

Dacă în corpul ciclului nu se află instrucţiuni care să

instrucţiune

FalsAdevărat

condiţie

Page 151: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

149

conducă la o condiţie falsă după un număr finit de ciclări (ieşire normală din ciclu) sau instrucţiuni de salt din interiorul ciclului (ieşire anormală) se obţine un ciclu infinit (buclă eternă).

Exemplul 5.9

Programul citeşte două numere a şi b de la tastatură şi afişează suma lor. Procesul continuă cât timp la întrebarea ”Continuati?” se apasă una din tastele care conţin literele d sau D.

#include "stdio.h" #include "conio.h" void main(void { float a,b; char c; do { printf("\n a="); scanf("%f",&a); printf("\n b="); scanf("%f",&b); printf("\n Suma a+b=%.2f",a+b); printf("\n Continuati? (d/n) "); c=getch(); } while (c == 'D' || c == 'd'); }

Exemplul 5.10

Programul implementează un meniu simplu. Pentru două numere citite de la tastatură se efectuează una din următorele operaţii: suma, diferenţa produsul sau împărţirea (atunci când este posibil) sau se iese din meniu. #include "stdio.h" #include "conio.h" void main(void) { float a,b; char ch; printf("\n a=");scanf("%f",&a); printf("\n b=");scanf("%f",&b);

Page 152: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

150

printf("\n + Adunare"); printf("\n - Scadere"); printf("\n * Inmultire"); printf("\n / Impartire"); printf("\n r Renunta!"); printf("\n Introduceti optiunea dvs:"); do {

ch=getchar(); switch(ch) { case '+' :printf("\n a+b=%.2f",a+b); break; case '-' :printf("\n a-b=%.2f",a-b); break; case '*' :printf("\n a*b=%.2f",a*b); break; case '/' :if (b) printf("\n a/b=%.2f",a/b); else printf("\n Impartire imposibila!"); break;

case 'r' : case 'R' :exit(0); }

} while (ch!='+' && ch!='-' && ch!='*' && ch!='/'); getch(); }

Observaţie. Funcţia exit() provoacă întreruperea programului şi revenirea în sistemul de operare. Funcţia are forma generală:

void exit(int cod_retur);

De obicei, cod_retur are valoarea 0 la ieşire normală din program şi o valoare diferită de 0 în caz contrar.

Exemplul 5.11

Programul calculează şi afişează radicalul dintr-un număr. Noutatea faţă de Exemplul 5.1 este apariţia unei bucle iterative de validare: ieşirea din buclă urmată de calculul radicalului se face doar atunci când numărul citit de la tastatură este pozitiv.

Page 153: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

151

#include "stdio.h" #include "conio.h" #include "math.h" void main(void) { float x; do { printf("\n x="); scanf("\n %f",&x); } while (x<0); printf("\n Radical din x=%.2f este

y=%.4f",x,sqrt(x)); getch(); }

✎ Scrieţi un program C care calculează suma primelor n

numere naturale folosind pe rând structurile for, while şi do-while.

Cicluri imbricate (incluse)

Există posibilitatea ca o instrucţiune de ciclare să includă o altă instrucţiune de ciclare; în acest caz se spune că ciclurile sunt imbricate sau incluse.

Exemplul 5.12

Programul ilustrează folosirea ciclurilor imbricate:

#include "stdio.h" #include "conio.h" void main(void) { int i,j; for (i=1;i<=5;i++) { for (j=1;j<=i;j++) printf("%2d",j); printf("\n"); }; getch(); }

Page 154: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

152

Rezultatul execuţiei programului de mai sus este:

1 1 2 1 2 3 1 2 3 4 1 2 3 4 5

Pentru o valoare a variabilei contor i, variabila contor j a ciclului interior variază de i ori; se spune că indicele interior variază mai repede ca indicele exterior.

Evident, o structură de cicluri incluse poate să conţină oricare din instrucţiunile de ciclare permise în C. Iată un exemplu de acest gen:

Exemplul 5.13

Programul rezolvă următoarea problemă: cât timp se citeşte de la tastatură o valoare x diferită de zero se afişează şirul de numere x, x+1, x+2, x+3, x+4. Acest proces continuă sau se întrerupe la cerere.

#include "stdio.h" #include "conio.h" void main(void) { int x,i; char ch; do { printf("\n x="); scanf("%i",&x); while (x) { for (i=0;i<5;i++) printf("%5d",x+i); printf("\n x="); scanf("%i",&x); } printf("\n Continuati ? (d/n)"); ch=getch(); } while (ch == 'd' || ch == 'D'); }

Page 155: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

153

Instrucţiuni de salt

În limbajul C există patru instrucţiuni care execută un salt necondiţionat în program: break, continue, goto, return. Instrucţiunea return se referă la revenirea din funcţia apelată la punctul unde s-a făcut apelul.

INSTRUCTIUNEA break

După cum s-a văzut la prezentarea instrucţiunii switch, instrucţiunea break poate încheia execuţia unei prelucrări case şi forţa trecerea execuţiei la prima instrucţiune aflată după switch. O altă situaţie unde instrucţiunea break îşi dovedeşte utilitatea este atunci când se doreşte încheierea forţată a unui ciclu. În acest caz întâlnirea instrucţiunii break în corpul ciclului determină întreruperea ciclării şi trecerea controlului la prima instrucţiune care urmează după ciclu.

Exemplul 5.14

Programul “extrage“ şi afişează cel mult 20 de numere aleatoare folosind funcţia rand(). Dacă s-a “extras“ numărul 10 programul nu mai efectuează restul “extragerilor“.

#include "stdio.h" #include "conio.h" #include "stdlib.h" void main(void) { int i,x; for (i=0;i<20;i++) { x=rand()%20+1; printf("\n %i. S-a extras numarul %i",i+1,x); if (x==10) break; } getch(); }

Precizări. O instrucţiune break are efect numai asupra ciclului cel mai interior în care se află. Aceeaşi precizare e valabilă şi la instrucţiuni switch imbricate sau incluse în cicluri: instrucţiunea break va afecta numai prima instrucţiune switch in

Page 156: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

154

care se află, nu şi eventualele instrucţiuni switch sau de ciclare în care ar putea fi inclusă prima.

Exemplul 5.15

Programul tipăreşte de 10 ori câte 7 numere extrase aleator.

#include "stdio.h" #include "conio.h" #include "stdlib.h" void main(void) { int i,j; for (i=0;i<10;i++) { printf("\n"); for (j=0;j<10;j++) { printf("%5d",rand()%10+1); if (j>=7) break; } } getch(); }

INSTRUCŢIUNEA continue

Instrucţiunea continue se foloseşte numai în corpul unui ciclu; ea forţează execuţia următoarei iteraţii a ciclului, omiţându-se instrucţiunile prezente între cele două iteraţii (locul unde se află plasată în corpul ciclului şi sfârşitul acestuia). Efectul instrucţiunii este următorul:

Când continue este întâlnită într-un ciclu for se continuă cu execuţia componentei de actualizare şi apoi a testului condiţional.

Când este întâlnită într-un while sau do-while, se trece la execuţia expresiei condiţionale.

Exemplul 5.16

Programul citeşte de la tastatură 10 numere întregi însumându-le doar pe cele strict pozitive.

Page 157: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

155

#include "stdio.h" #include "conio.h" void main(void) { int i,x,s; for (i=s=0;i<10;i++) { printf("\n x="); scanf("%i",&x); if (x<=0) continue; s+=x; } printf("\n Suma este=%d",s); getch(); }

INSTRUCTIUNEA goto

Forma generală a instrucţiunii goto este:

goto eticheta; . . . eticheta:instructiune;

unde eticheta este numele de identificare al instrucţiunii instructiune.

Efectul execuţiei instrucţiunii goto este saltul necondiţionat la instrucţiunea identificată prin eticheta. Saltul poate fi făcut înainte sau după instrucţiunea goto. Folosirea frecventă a acestei instrucţiuni în programe afectează claritatea acestora, îngreunând înţelegerea lor. Ea poate fi însă evitată în orice situaţie utilizând celelalte structuri de control din C. Dăm mai jos un exemplu tipic de folosire a instrucţiunii goto: ieşirea forţată dintr-un ciclu sau dintr-o instrucţiune switch.

Exemplul 5.17

Programul reprezintă altă implementare a Exemplului 5.10.

#include "stdio.h" #include "conio.h"

Page 158: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

156

void main(void) { float a,b; char ch; for(;;) { clrscr(); printf("\n a="); scanf("%f",&a); printf("\n b="); scanf("%f",&b); printf("\n + Adunare"); printf("\n - Scadere"); printf("\n * Inmultire"); printf("\n / Impartire"); printf("\n r Renunta"); printf("\n Introduceti optiunea dvs:"); ch=getche(); switch (ch) { case '+' :printf("\n a+b=%.2f",a+b); break; case '-' :printf("\n a-b=%.2f",a-b); break; case '*' :printf("\n a*b=%.2f",a*b); break; case '/' :if (b) printf("\n a/b=%.2f", a/b); else printf("\n Impartire imposibila"); break; case 'r' : case 'R' :goto STOP; } getch(); } STOP:printf("\n Am renuntat!"); getch(); }

Page 159: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

157

� Test de autoevaluare

5.1. Secvenţa de program

int x=-3,y=7; if (x>0) printf(”\n x=%i”,x); else if (y) printf(”\n y=%i”,y); else printf(”\n y=0”); a. afişează y=7

b. este greşită deoarece o instrucţiune if conţine o altă instrucţiune if

c. afişează x=-3

5.2. Secvenţa de program

if(x) if(y) y=3; else y=5;

este echivalentă cu

a. if(x) if(y) y=3; else; else y=5; b. if(x&&y) y=3; else y=5; c. if(x) { if(y) y=3;

Page 160: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

158

} else y=5; d. nici una din secvenţele a, b, c

5.3. Secvenţa de program

int x=1,y=2; if ((x=0)&&(y=4)) printf(”\n x=%i y=%i”,x,y); a. afişează x=1 y=2

b. afişează x=0 y=4

c. nu afişează nimic deoarece printf() nu se execută

5.4. Secvenţa de program

if(x) y=1/x; a. este greşită

b. este echivalentă cu

if (x!=0) y=1/x; c. este chivalentă cu

if x!=0 y=1/x;

5.5. Secvenţa de program

if (x>=3) y=sqrt(x-3); else; a. este greşită deoarece conţine semnul ; înainte de else

b. este greşită deoarece după else lipseşte o instrucţiune

c. este corectă şi este echivalentă cu secvenţa

if(x>=3) y=sqrt(x-3);

Page 161: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

159

5.6. Secvenţa de program

int x=3,y=6; if (x>0) printf(”\n x=%i”,x); else y=x+3; printf(”\n y=%i”,y);

afişează

a. x=3

b. y=6

c. x=3

y=6

5.7. Secvenţa de program

int x=3,y=4; printf(”\n %i”,x>y?x:y); a. afişează 3

b. afişează 4

c. este greşită deoarece argumentul funcţiei printf() este o expresie, nu o variabilă.

5.8. Secvenţa de program

char x=’a’; switch(x) { case ’a’:printf(”\n amic”); case ’A’:printf(”\n Amare”); } a. afişează amic

b. afişează Amare

c. afişează

amic Amare

5.9. Secvenţa de program

int x=3; if (x=4)

Page 162: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

160

printf(”\n x=%i”,x); a. este greşită

b. este corectă, dar nu afişează nimic

c. este corectă şi afişează valoarea 4

d. este corectă şi afişează valoarea 3

5.10. Secvenţa de program

char x=’a’; switch(x) { case ’a’:printf(”\n amic”);break; case ’A’:printf(”\n Amare”); } a. afişează amic

b. afişează Amare

c. afişează

amic Amare d. este greşită deoarece al doilea case nu se termină cu

break

5.11. Secvenţa de program

int i=3; while(i) i--; printf(”%3i”,i); a. afişează 2 1 0

b. conţine o buclă eternă

c. afişează 0

5.12. Secvenţa de program

int i=3; while(i) printf(”%3i”,i); i--; a. afişează valoarea 3 de 3 ori

b. afişează valoarea 3 de o infinitate de ori (buclă

Page 163: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

161

eternă)

c. afişează 3 2 1

5.13. Secvenţa de program

int i=3; while(i); printf(”%3i”,i); i--; a. afişează valoarea 3 de 3 ori

b. afişează valoarea 3 de o infinitate de ori (buclă eternă)

c. conţine o buclă eternă şi nu afişează nimic

d. afişează 3 2 1

5.14. Secvenţa de program

int i=3; while(i) { printf(”%3i”,i); i--; } a. afişează 3 2 1 0

b. afişează 3 2 1

c. conţine o buclă eternă

5.15. Secvenţa de program

int i=0; while(i) printf(”%3i”,i); a. afişează valoarea 0

b. afişează valoarea 0 de o infinitate de ori (buclă eternă)

c. nu afişează nimic

5.16. Secvenţa de program

int i=0; for (;i<3;i++); printf(”%3i”,i);

Page 164: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

162

a. este greşită sintactic deoarece lipseşte componenta de iniţializare a instrucţiunii for

b. afişează valorile 0 1 2 3

c. afişează valorile 0 1 2

d. afişeaza valoarea 3

e. conţine o buclă eternă afişându-se permanent valoarea 0

f. conţine o buclă eternă şi nu afişează nimic

5.17. Secvenţa de program

int i,j; for (i=1,j=10;i<=5;i++,j--) printf(”\n %i %2i”,i,j); a. este greşită deoarece instrucţiunea for conţine două

variabile contor i,j

b. este greşită deoarece componenta iniţializare a instrucţiunii for conţine două iniţializări

c. este corectă şi afişează

1 10

2 9

3 8

4 7

5 6

5.18. Secvenţa de program

int i; for (i=1;-3<=i&&i<1;i--) printf(”\n%3i”,i); a. nu afişează nimic

b. afişează 0 -1 -2 -3

c. conţine o buclă eternă

5.19. În secvenţa de program

int x=1,i; for(i=1;x<=3;i++) scanf(”%i”,&x);

Page 165: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

163

a. funcţia scanf() se execută de 3 ori

b. funcţia scanf() se execută de o infinitate de ori

c. instrucţiunea for este greşită deoarece contorul i nu se testează niciodată

d. se iese din buclă numai după ce s-a citit o valoare x>3

5.20. Secvenţa de program

int i; for(i=1,i<=3;i++) printf(”%3i”,i) a. este greşită

b. conţine o buclă eternă

c. afişează 1 2 3

5.21. Secvenţa de program

int i; for (i=1,i<=3;i++) printf(”%3i”,i) a. conţine o instrucţiune for greşită sintactic

b. afişează 1 2 3

c. conţine o buclă for eternă

5.22. Secvenţa de program

for(); a. este o buclă for eternă

b. este greşită sintactic

c. apelează funcţia for()

5.23. Secvenţa de program

float x=-3.2; do scanf(”%f”,&x); while (x>0); a. citeşte x până când x>0

b. citeşte x cât timp x>0

Page 166: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

164

c. este greşită deoarece funcţia scanf() nu este pusă între acolade

d. nu execută nici o citire a lui x

5.24. Secvenţa de program

int j; do j=3; while (j<=4); { printf(”%3i”,j); j++; } a. afişează valoarea 3

b. afişează valorile 3 4

c. conţine o buclă do-while eternă

d. conţine o buclă while eternă

e. este greşită

5.25. Secvenţa de program

int i=1; do printf(”\n%i”,i); i++; while(i<=2); a. afişează 1 2

b. este greşită deoarece instrucţiunile dintre do şi while trebuie să fie cuprinse între acolade

5.26. Secvenţa de program

int i,j; for(i=1;i<=2;i++) for(j=1;j<=2;j++) printf(”\n i=%i j=%i”,i,j); a. afişează i=1 j=1

i=2 j=2 b. afişează i=1 j=1

i=1 j=2 i=2 j=1

Page 167: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

165

i=2 j=2 c. afişează i=1 j=1

i=2 j=1 i=1 j=2 i=2 j=2

5.27. Secvenţa de program

int i,j; for(i=1;i<=3;i++) { printf(”\n”); for(j=1;j<=i;j++) printf(”%3i”,j); } a. este greşită deoarece limitele de variaţie ale

contorului j depind de contorul i al primului ciclu

b. este corectă şi afişează

1 1 2 1 2 3

c. este corectă şi afişează

1 2 3 1 2 1

5.28. Secvenţa de program

int i; for(i=1;i<=5;i++) { printf(”%3i”,i); if(i==3)break; } a. este greşită deoarece instrucţiunea break se foloseşte

numai asociată cu switch

b. este corectă şi afişează 1 2 3

c. este corectă şi afişează 1 2 3 4 5 deoarece instrucţiunea break cuprinsă în corpul unui ciclu for nu are nici un efect

5.29. Secvenţa de program

int i,j; for(i=1;i-3;i++) for(j=0;j-9;j++)

Page 168: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

166

{ printf(”\n Sunt aici!”); if (!j)break; } a. afişează mesajul Sunt aici! de 2 ori

b. afişează mesajul Sunt aici! de 30 ori

c. afişează mesajul Sunt aici! o dată

5.30. Secvenţa de program

int s,i; for(s=0,i=10;i;i--) { s+=i; if(i-5)continue; } a. calculează suma s=10+9+8+7+6+4+3+2+1

b. calculează suma s=10+9+8+7+6+5+4+3+2+1

c. calculează suma s=5

5.31. Secvenţa de program

int s,i; for(s=0;i=10;i;i--) { if(i-5)continue; s+=i; } a. calculează suma s=10+9+8+7+6+4+3+2+1

b. calculează suma s=10+9+8+7+6+5+4+3+2+1

c. calculează suma s=5

5.32. Secvenţa de program

int s,i; for(s=0;i=10;i;i--) { if(i==5)continue; s+=i; } a. calculează suma s=10+9+8+7+6+4+3+2+1

b. calculează suma s=10+9+8+7+6+5+4+3+2+1

Page 169: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

167

c. calculează suma s=5

5.33. Secvenţa de program

int i=1; while(i<3) { if!(i==2)continue; printf(”%3i”,i); i++; } a. afişează 1 şi intră într-o buclă eternă

b. afişează 1 2 3

c. afişează 1 3

5.34. Secvenţa de program

int i=1,s=0; et1:if(i>10) goto et2; s+=i; i++; goto et1; et2:printf(”\n s=%d”,s); a. este greşită deoarece conţine salturi înapoi

b. este corectă şi realizează o iteraţie pentru calculul primelor 10 numere naturale

c. este corectă şi este echivalentă cu secvenţa

int s,i; for(s=0,i=1;i<11;i++) s+=i; printf(”\n s=%d”,s); d. este corectă şi este echivalentă cu secvenţa

int i=1,s=0; while(i<11) { s+=i; i++; } printf(”\n s=%d”,s);

Page 170: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

168

Tablouri şi şiruri de caractere

Notaţia indicială a variabilelor nu este nouă; ea a fost şi este folosită în special de matematicieni ori de câte ori este nevoie ca o prelucrare să fie exprimată cît mai sintetic. Este evident că prelucrarea S=a+b+c+d+e+f arată mult mai puţin elegant decât

6

1iixS În ultimul caz cele şase variabile a,b,c,d,e,f au

fost redenumite x1,x2,...,x6; ele pot fi privite astfel drept primele 6 componente ale vectorului x.

Tablourile reprezintă tocmai implementarea noţiunilor de vector, matrice sau masiv multidimensional într-un limbaj de nivel înalt. Ele reprezintă colecţii omogene de date (adică de acelaşi tip), stocate în locaţii de memorie învecinate. Accesul la oricare din elementele tabloului se face cu ajutorul indicilor.

Tablouri unidimensionale

Declaraţia unui tablou unidimensional se face după forma generală:

tip nume_tablou[dim]; unde:

tip reprezintă tipul de bază al elementelor indexate;

dim reprezintă numărul de elemente ale tabloului;

nume_tablou este un identificator reprezentând numele tabloului.

Dimensiunea zonei continue alocate se calculează prin relaţia

dimens_alloc=dim*sizeof(tip).

De exemplu, prin declaraţia

int a[100]; se vor aloca vectorului a, 100*2=200 de octeţi într-o zonă continuă de memorie.

Page 171: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

169

Observaţii:

alocarea se face în timpul compilării;

o dată făcută alocarea, în scopul măririi vitezei de execuţie nu se mai face nici o verificare a dimensiunii; gestionarea corectă a zonei de memorie alocate cade, deci, exclusiv în sarcina programatorului.

Referirea la un element al tabloului unidimensional se face precizând numele tabloului urmat de o expresie întreagă între paranteze drepte, adică

nume_tablou[expr]

Expresia expr poate lua valori întregi cuprinse în intervalul[0,dim-1]. Astfel, în urma declaraţiei float y[10]; vectorului y va avea 10 componente reale şi anume:

y[0] componenta_1

y[1] componenta_2

. . . . . . . .

y[9] componenta_10

Intenţia de a referi ultimul element al unui tablou sub forma nume_tablou[dim] este o greşeală cu atât mai gravă, cu cât, ţinând cont de observaţiile anterioare, ea nu este depistată de compilator. De obicei expresiile întregi folosite pentru a accesa componentele unui tablou sunt constante sau variabile simple (indici).

Exemplul 5.18

Comutarea componentelor unui vector şi afişarea lor în coloană.

#include "stdio.h" #include "conio.h" void main(void)

{ int x[50],i,n,c;

/* citirea elementelor vectorului */ printf("\n lungimea sirului n<50 este:");

Page 172: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

170

scanf("%d",&n); for (i=0;i<n;i++)

{ printf("\n x[%i]=",i); scanf("%i",&x[i]); }

/* comutarea elementelor */ for (i=0;i<n/2;i++)

{ c=x[i]; x[i]=x[n-1-i]; x[n-1-i]=c; }

/* afisarea elementelor vectorului comutat */ for (i=0;i<n;i++)

printf("\n componenta x[%i] este %i",i,x[i]);

getch(); }

Tablouri multidimensionale

Dacă elementele unui tablou unidimensional sunt la rîndul lor tablouri unidimensionale obţinem un tablou bidimensional sau o matrice. De exemplu, declaraţia:

int x[4][3];

se poate interpreta astfel: x este un tablou cu 4 elemente x[i], i=0,1,2,3. Fiecare element x[i] cu i=0,1,2,3 este un tablou cu 3 elemente întregi x[i][j] cu j=0,1,2.

Generalizând, un tablou multidimensional poate fi considerat ca un tablou unidimensional care are ca elemente un tablou cu restul de dimensiuni; declaraţia unui tablou cu dimensiunile dim1,dim2,...,dimn are forma generală:

tip nume_tablou[dim1][dim2]...[dimn];

iar referirea la un element al tabloului se face prin:

nume_tablou[indice1][indice2]...[indicen],

unde indicei ia valori întregi în intervalul [0,dimi-1], pentru i=1,2,...,n.

Page 173: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

171

Observaţii:

Referirea clasică la elementele unui tablou prin separarea indicilor prin virgulă este incorectă în C şi are semnificaţia rezultată din folosirea operatorului de secvenţiere. De exemplu, considerând declaraţia de mai sus, referirea x[i,j] este echivalentă cu x[j].

Dimensiunea zonei continue de memorie alocate este dată (în octeţi) de valoarea dim1*dim2*dim3*dimn* *sizeof(tip).

Exemplul 5.19

Calculul şi afişarea sumei a două matrici a şi b de dimensiune 4x3 citite de la tastatură.

#include "stdio.h" #include "conio.h" void main(void) { int a[10][10],b[10][10],c[10][10]; short i,j,m,n;

/*citirea dimensiunilor mtricilor a,b si c */ do

{ printf("\n m="); scanf("%i",&m); printf("\n n="); scanf("%i",&n); }

while (m<1 || m>10 || n<1 || n>10);

/* citirea elementelor matricilor a si b */ for (i=0;i<m;i++) for (j=0;j<n;j++)

{ printf("\n a[%i][%i]=",i,j); scanf("%i",&a[i][j]); printf("\n b[%i][%i]=",i,j); scanf("%i",&b[i][j]); }

/* calculul matricii suma c=a+b */ for (i=0;i<m;i++) for (j=0;j<n;j++)

Page 174: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

172

c[i][j]=a[i][j]+b[i][j];

/* afisarea matricii suma c */ printf("\n matricea suma este:\n"); for (i=0;i<m;i++) { for (j=0;j<n;j++) printf("%4i",c[i][j]); printf("\n"); } getch(); }

Iniţializarea tablourilor

Exemplele anterioare ne-au arătat cum se poate iniţializa un tablou prin valori date de la tastatură. Există însă posibilitatea iniţializării unui tablou printr-o definiţie de forma:

declaratie tablou={lista valori_initiale};

unde valori_initiale sunt expresii constante compatibile cu tipul de bază al tabloului.

Exemple:

int vector[6]={-7,-2,95,21,5,-23}; float a[3][2]={1,2,3,4,5,6}; int b[3][2][2]={1,2,3,4,5,6,7,8,9,10,11,12};

În cel de-al doilea caz a fost iniţializată o matrice. Cum se vor completa elementele matricii? Răspunsul este simplu: ”pe linii”, adică se completează linia 0, apoi linia 1 şi în sfârşit linia 2. Matricea a va arăta astfel:

1 2 3 4 5 6

Pentru a sugera modul de iniţializare al tablourilor multidimensionale se pot folosi acolade despărţitoare în interiorul listei de valori. Astfel, matricea a se poate scrie mai sugestiv

int b[3][2]= { {1, 2}, {3, 4}, {5, 6}, };

Page 175: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

173

În general, iniţializarea elementelor unui tablou multidimensional se face după regula “ultimul indice variază cel mai rapid“, care este o generalizare a regulii de memorare “pe linii“. Astfel, cele douăsprezece componente ale tabloului b[3][2][2] vor fi iniţializate astfel:

b[0][0][0]=1 b[0][0][1]=2 b[0][1][0]=3 b[0][1][1]=4 b[1][0][0]=5 b[1][0][1]=6 b[1][1][0]=7 b[1][1][1]=8 b[2][0][0]=9 b[2][0][1]=10 b[2][1][0]=11 b[2][1][1]=12

Aceste reguli decurg din modul de liniarizare a unui tablou în C: poziţiei i1*i2*...*in din tablou îi corespunde în forma sa liniarizată (formă sub care i se va aloca memoria) poziţia k dată de formula:

k=i1*dim2*...*dimn+i2*dim3*dimn+...+in-1*dimn+in.

De exemplu, în cazul unei matrici a[m][n] liniarizarea se face după formula k=i*n+j.

Să notăm în cazul general cu dim produsul dim1*dim2*...*dimn şi cu nval_in numărul constantelor din lista de iniţializare.

Dacă dim=nval_in iniţializarea tabloului decurge normal după regula de mai sus.

Dacă dim<nval_in se va produce o eroare, iar dacă dim>nval_in restul de elemente sunt iniţializate cu zero.

Se observă că formula de alocare nu depinde de prima dimensiune a tabloului, fapt ce permite următoarele iniţializări echivalente cu cele prezentate la începutul secţiunii:

int vector[]={-7,-2,95,21,5,-23}; float a[][2]={1,2,3,4,5,6}; int b[][2][2]={1,2,3,4,5,6,7,8,9,10,11,12};

Page 176: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

174

Tablouri şi şiruri de caractere

În C nu există un tip special pentru definirea unui şir de caractere. Şirurile de caractere se construiesc cu ajutorul tablourilor unidimensionale.

Declaraţia unui şir cu numele, nume_sir de lungime maxim dim-1 caractere se face sub forma:

char nume_sir[dim];

Sfârşitul unui şir este marcat de caracterul ’\0’; din acest motiv, în declaratia şirului, dimensiunea tabloului trebuie să fie cel puţin cu o unitate mai mare decât numărul de caractere al şirului pe care vrem să-l memorăm.

De exemplu: char sr[10];

conţine declaraţia şirului sr. Iniţializarea se poate face printr-o definiţie a şirului sub forma:

char sr[10]=”aAbBcCdD”;

✎ Care este caracterul sr[3] din exemplu de mai sus?

Dacă numărul elementelor din şir este mai mare decât dimensiunea şirului, caracterele în plus sunt ignorate, în caz contrar restul elementelor este iniţializat cu zero (caracterul nul).

Dacă nu se precizează dimensiunea, se poate face următoarea iniţializare:

char sr[]=”aAbBcCdD”;

care este echivalentă cu iniţializarea tabloului sr cu un şir de caractere, adică

char sr[]={’a’,’A’,’b’,’B’,’c’,’C’,’d’,’D’,\0’};

Se observă prezenţa explicită a terminatorului de şir ’\0’.

Ultimele două variante rezervă şirului un număr de locaţii egal cu numărul elementelor din şir plus o unitate (corespunzătoare terminatorului ’\0’) şi este mai comodă, deoarece nu precizează o limită maximă pentru numărul de caractere, permiţând programatorului să evite numărarea

Page 177: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

175

elementelor din şir.

Legătura dintre şiruri şi tablouri unidimensionale permite referirea indexată la caracterele şirului. Folosind acest lucru, în exemplul de mai jos se selectează şi afişează literele mici din şirul sir.

Exemplul 2.10

Selectarea şi afişarea literelor mici dintr-un şir.

#include "stdio.h" #include "conio.h"

void main(void) { int i; char sir[]="aAbBcCdD"; printf("\n Sirul este: %s",sir); printf("\n Literele mici din sir sunt: "); for (i=0;sir[i];i+=2) printf("%c",sir[i]); getch(); }

Funcţii pentru prelucrarea şirurilor de caractere

Funcţii cu prototipul in “stdio.h”

Pentru operaţiile de intrare/ieşire cu şiruri se pot folosi funcţiile scanf() respectiv printf() cu descriptorul de format %s.

Exemplul 5.21

Citirea a două şiruri sub forma nume prenume şi afişarea lor sub forma prenume nume.

#include "stdio.h" #include "conio.h" void main(void) { char nume[25],prenume[25]; printf("\n Numele="); scanf("%s",nume); printf("\n Prenumele="); scanf("%s",prenume); printf("\n %s %s",prenume,nume); getch(); }

Page 178: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

176

Pentru citirea unui şir de la tastatură se poate folosi funcţia gets() cu forma generală:

gets(sir_destinatie);

iar pentru afişarea unui şir pe ecran funcţia puts() cu forma generală:

puts(sir).

Observaţie. Funcţia gets() transferă în sir_destinatie toate caracterele până la apăsarea tastei Enter.

Funcţii cu prototipul în “string.h”

Fişierul ”string.h” conţine prototipurile funcţiilor specializate pentru manipularea şirurilor de caractere. Iată câteva dintre acestea:

Funcţia strcpy() cu forma generală:

strcpy(sir_destinatie, sir_sursa);

copiază sir_sursa în sir_destinatie;

Funcţia strcmp() cu forma generală:

int strcmp(sir1, sir2);

compară cele doua şiruri caracter cu caracter şi întoarce o valoare:

<0 dacă sir1<sir2; =0 dacă sir1=sir2; >0 dacă sir1>sir2.

Comparaţia şirurilor se face lexicografic.

Funcţia strlen() cu forma generală:

unsigned int strlen(sir);

întoarce numărul de elemente dintr-un şir;

Funcţia strcat() cu forma generală:

char *strcat(sir1, sir2);

Page 179: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

177

adaugă sir2 la sfârşitul şirului sir1 (concatenare).

Exemplul 5.22

Se citeşte de la tastatură un număr neprecizat de şiruri de caractere. Citirea se termină când se întâlneşte şirul ”stop”. Programul stabileste şirul “minim” (în sens lexicografic) şi îl afişează împreună cu lungimea sa.

#include "stdio.h" #include "conio.h" #include "string.h"

void main(void) { char min[20],x[20]; printf("\n Introduceti siruri de caractere ! "); printf("\n La sfarsit tastati STOP \n");

strcpy(min,gets(x)); while (strcmp(x,"stop")) { strcmp(min,x)<0 ? min : strcpy(min,x); gets(x); } printf("\n Sirul minim este "); puts(min); printf("\n si are lungimea %i",strlen(min)); getch(); }

� Test de autoevaluare

5.35. Declaraţia

float x[100]; înseamnă

a. rezervarea în memorie a 100 de locaţii la adrese consecutive

b. rezervarea în memorie a 100de locaţii la adrese întâmplătoare

c. rezervarea a 100 de octeţi pentru variabila reală x

Page 180: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

178

5.36. Secvenţa de program

int x[m][n],m=3,n=2; a. este corectă deoarece dimensiunile m şi n ale matricii

sunt cunoscute

b. este greşită deoarece m şi n trebuia să fie declaraţi înainte de x

c. este greşită deoarece la declarare în main(), dimensiunile unui tablou trebuie să fie constante şi nu variabile

5.37. Secvenţa de program

int y[10]; y[10]=7; a. atribuie componentei y[10] a tabloului y valoarea 7

b. este greşită deoarece componentele tabloului sunt y [0],y[1],y[2],...,y[9]

c. este corectă deoarece componentele tabloului sunt y[1],y[2],...,y[10]

5.38. În secvenţa de program

int x[3][2]; x[1,2]=5; a. atribuirea x[1,2]=5 este echivalentă cu

x[1][2]=5

b. atribuirea x[1,2]=5 este corectă sintactic şi înseamnă x[2]

5.39. Următoarele trei declaraţii ale tabloului x,

int x[6]; int x[3][2]; int x[2][3]; a. sunt echivalente

b. nu sunt echivalente

5.40. În urma iniţializării tabloului a

int a[3][2]={1,2,3,4,5,6};

Page 181: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

179

componenta a[1][0] are valoarea

a. 2

b. 3

c. altă valoare decât decât 2 sau 3

5.41. Iniţializarea

int a[3][2]={1,2,3,4,5,6}; este echivalentă cu:

a. int a[3][2]={ {1,2}, {3,4}, {5,6}, };

b. int a[3][2]={ {1,4}, {2,5}, {3,6}, };

5.42. Iniţializarea

float x[2][3]={1,2,3,4,5,6}; este echivalentă cu

a. float x[][]={1,2,3,4,5,6};

b. float x[][3]={1,2,3,4,5,6};

c. float x[2][]={1,2,3,4,5,6};

5.43. Secvenţa de program

int x[10],i; for(i=1;i<=10;i++) scanf(”%d”,&x[i]); a. este greşită sintactic

b. nu iniţializează toate componentele vectorului x

c. produce eroare la execuţie

5.44. Secvenţa de program

char x[]=”abc”; este echivalentă cu:

a. iniţializarea char x[]={’a’,’b’,’c’};

Page 182: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

180

b. iniţializarea char x[4]={’a’,’b’,’c’};

c. iniţializarea char x[]={’a’,’b’,’c’,’\0’};

5.45. Secvenţa de program

char x[]=”abcd”; putch(x[1]); a. afişează caracterul ’a’

b. afişează caracterul ’b’

c. este greşită deoarece elementele dintr-un şir nu se pot referi indexat

5.46. Secvenţa de program

char x[20]=”abcd”; printf(”\n Lungimea sirului=%i”,strlen(x));

afişează mesajul

a. Lungimea sirului=20

b. Lungimea sirului=4

c. Lungimea sirului=5

5.47. Secvenţa de program

char x[]= ”rac”; char y[]= ”arc”; printf(”%d”,strcmp(x,y));

afişează o valoare

a. egală cu zero

b. mai mică strict decât zero

c. mai mare strict decât zero

5.48. Secvenţa de program

char x[]=”ac”; char y[]=”ar”; strcat(x,y); printf(”\n %s”,x);

afişează

a. acar

b. arac

5.49. În secvenţa de program

char x[20];

Page 183: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

181

x=”Ploiesti”; atribuirea

x=”Ploiesti”; a. este greşită

b. este greşită, iar copierea şirului ”Ploiesti” în variabila x se realizează prin strcpy(x,”Ploiesti”);

c. este corectă

5.50. Secvenţa de program

char x[20]; gets(x); puts(x);

afişează acelaşi şir dacă înlocuim gets(x); cu:

a. gets(&x);

b. scanf(”%s”,&x);

c. scanf(”%s”,x);

5.51.În secvenţa de program

int i; char x[20]=”xyzw”; puts(x);

apelul

puts(x);

poate fi înlocuit cu:

a. printf(”\n %s”,x);

b. for(i=0;i<5;i++)

putch(x[i]);

Răspunsurile testelor de autoevaluare

5.1 a 5.2 d 5.3 c 5.4 b 5.5 c

5.6 c 5.7 b 5.8 c 5.9 c 5.10 a

5.11 c 5.12 b 5.13 c 5.14 b 5.15 c

5.16 d 5.17 c 5.18 a 5.19 d 5.20 a

Page 184: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

182

5.21 a 5.22 b 5.23 b 5.24 c 5.25 b

5.26 b 5.27 b 5.28 b 5.29 a 5.30 b

5.31 c 5.32 a 5.33 a 5.34 b, c, d

5.35 a 5.36 c 5.37 b 5.38 b 5.39 b

5.40 b 5.41 a 5.42 b 5.43 b 5.44 c

5.45 b 5.46 b 5.47 c 5.48 a

5.49 a, b 5.50 a, b, c 5.51 a, b

Lucrare de verificare ...................................................✍

Realizaţi o prezentare a structurilor de control în limbajul C.

Scrieţi un program C care citeşte de la tastatură un vector de numere întregi şi afişează media aritmetică a elementelor pare.

Scrieţi un program C care citeşte de la tastatură o matrice nxn de numere întregi reprezentând durata transportului pe care o înregistrează un autoturism între oraşele 1,2,…,n (este posibil ca drumul de la oraşul i la oraşul j să dureze mai mult sau mai puţin faţă de drumul de la j la i) şi afişează durata minimă a drumurilor care pleacă din oraşul x citit la tastatură. Către ce oraş duce drumul identificat?

Rezumat

Instrucţiunile de control ale limbajului C, care sunt implementările, specifice limbajului, ale structurilor algoritmice fundamentale discutate în UI4, sunt următoarele:

instrucţiunea expresie

instrucţiunile de decizie: if (if-else şi varianta if cu ramură vidă) şi switch, la care se adaugă operatorul condiţional ?:

instrucţiunile iterative (repetitive sau de ciclare): while, for şi do - while

Page 185: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

183

instrucţiunile de salt: break, continue, goto, return

Există posibilitatea ca o instrucţiune decizională să includă o altă instrucţiune decizională şi ca o instrucţiune iterativă să includă o altă instrucţiune iterativă; se spune în acest caz că instrucţiunile sunt imbricate sau incluse.

Instrucţiunea break poate încheia execuţia unei prelucrări case din instrucţiunea switch sau poate încheia forţat un ciclu.

Instrucţiunea continue, folosită numai în corpul unui ciclu, forţează execuţia următoarei iteraţii a ciclului, omiţându-se instrucţiunile prezente între cele două iteraţii (locul unde se află plasată în corpul ciclului şi sfârşitul acestuia).

Instrucţiunea goto realizează un salt necondiţionat la o instrucţiune identificată prin eticheta care urmează instrucţiunea goto. Saltul poate fi făcut înainte sau înapoi.

Evident că în programe aceste instrucţiuni se pot combina şi include unele în altele după cum cere algoritmul proiectat pentru a rezolva o anume problemă.

Tablourile, acele structuri de date care reprezintă colecţii omogene de date stocate în locaţii de memorie învecinate, sunt implementările noţiunilor de vector (când există o singură dimensiune), matrice (când se consideră două dimensiuni) sau masiv multidimensional (când se consideră mai mult de două dimensiuni) în limbajele de nivel înalt.

Un exemplu de vector, unul de matrice şi respectiv unul de masiv multidimensional, declarate în C, sunt următoarele:

int v[50]; float a[10][20]; int t[2][2][6][10][3];

Accesul la oricare din elementele tabloului se face cu ajutorul indicilor, care în C încep de la 0.

Dimensiunea zonei continue de memorie alocate este dată (în octeţi) de valoarea

dim1*dim2*dim3*dimn*sizeof(tip).

unde dimi este dimensiunea i, iar tip este tipul de bază al elementelor.

Alocarea spaţiului de memorie pentru elementele tabloului

Page 186: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

184

se face în timpul compilării, iar dimensiunea acestui spaţiu nu poate fi modificată pe parcursul execuţiei programului – un tablou este un tip de dată alocat static. O dată făcută alocarea, compilatorul nu mai face nici o verificare a dimensiunii şi prin urmare gestionarea corectă a zonei de memorie alocate cade exclusiv în sarcina programatorului.

Tablourile se pot iniţializa ca în exemplele:

int v[6]={-7,-2,95,21,5,-23}; float a[3][2]={1,2,3,4,5,6};

Iniţializarea elementelor tablourilor cu mai multe dimensiuni se face după regula “ultimul indice variază cel mai rapid“, care este o generalizare a regulii de memorare “pe linii“ întâlnite la matrici.

Pentru definirea unui şir de caractere, în C nu există un tip special de date. Acestea se construiesc cu ajutorul tablourilor unidimensionale, care se declară ca în exemplul

char sr[10];

Un şir memorat în variabila cu numele sr va putea avea lungimea maximă 9, deoarece ultima poziţie, sr[9],este ocupată cu caracterul sfârşit de şir, ’\0’.

Iniţializarea unui şir se poate face printr-o definiţie a şirului sub forma:

char sr[10]=”aAbBcCdD”;

Funcţiile principale de prelucrare a şirurilor de caractere:

funcţii de citire/scriere: scanf() şi printf() care folosesc descriptorul de format %s, gets() şi puts()

strcpy() care copiază un şir în alt şir

strcmp() care compară lexicografic două şiruri

strlen() care returnează lungimea unui şir

strcat() care concatenează două şiruri

Page 187: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

185

Bibliografie

1. Cristian Marinoiu, Programarea în limbajul C, Editura Universităţii din Ploieşti, Ploieşti, 2000.

2. Brian Kernighan, Dennis Ritchie, The C programming Language, Prentice Hall, 1988.

3. Herbert Schildt C: Manual complet, Editura Teora, Bucureşti, 1997.  

Page 188: Curs Programarea Calculatoarelor Marinoiu Cristian, AIA IFR, An I

186

Bibliografia cursului

1. Liviu Dumitraşcu, Monica Vlădoiu, Mihaela Oprea, Cristian Marinoiu şi colectiv, Borland Pascal în 13 conversaţii cu CD, capitolul 12, Structuri de date. Operaţii elementare, pag. 548-583, Editura Universităţii din Ploieşti, 2001.

2. Luca-Dan Şerbănaţi, V. Cristea, Florica Moldoveanu, Valeriu

Iorga, Programarea sistematică în limbajele Pascal şi Fortran,

Editura Tehnică, Bucureşti, 1984.

3. Gheorghe Barbu, Ion Văduva, Mircea Boloşteanu, Bazele

Informaticii, Editura Tehnică, Bucureşti, 1997.

4. Dana Petcu, Calcul Paralel, Editura de Vest, Timişoara, 1994.

5. Tiberiu Popescu (coordonator). Dicţionar de Informatică, Editura

Ştiinţifică şi enciclopedică, Bucureşti, 1981.

6. A. Petrescu, N. Ţăpuş, T. Moisa, Gh. Rizescu, V. Hărăbor, N.

Mârşanu, Tr. Mihu, abc de calculatoare personale şi … nu doar atât

Vol.I, Ed. Tehnică, Bucureşti, 1990.

7. L. Livovschi, Bazele Informaticii, Editura Didactică şi Pedagogică,

Bucureşti, 1981.

8. Florin Păunescu, Analiza şi concepţia sistemelor de operare,

Editura Ştiinţifică şi Enciclopedică, Bucureşti, 1982.

9. Cr. Marinoiu, Programarea în limbajul C, Editura Universităţii

din Ploieşti, Ploieşti, 2000.

10. J. Glenn Brookshear, Introducere în Informatică, Ed. Teora,

Bucureşti, 1998.

11. Andrew Tanenbaum, Computer Networks, fourth edition,

Pearson Education International, 2003.