Sunteți pe pagina 1din 88

PROGRAMARE PROCEDURALĂ

PROCEDURAL PROGRAMMING

Disciplină obligatorie; sem 1, ore săptămânal – învăţământ de zi: 2 curs, 2 laborator, total
ore semestru 56; 6 credite; colocviu

I. CONŢINUTUL TEMATIC AL DISCIPLINEI

• Algoritmi: Caracteristici. Descriere. Complexitate. Corectitudine.


• Limbaje de programare. Caracteristici.
• Limbajul de programare C: Entităţi sintactice. Operatori.. Expresii. Instrucţiuni.
Funcţii. Directive de preprocesare. Tablouri şi Pointeri. Comunicare inter-
modulară. Funcţia main cu argumente. Pachetele: stdio.h, math.h, string.h
• Alocare statică – Alocare dinamică. Structuri de date dinamice (liste şi arbori).
Aplicaţii ale utilizării tipurilor de date structurate (struct, union, typedef) cu
ajutorul pointerilor: crearea şi explorarea structurilor de date. Pachetele: stdlib.h,
alloc.h
• Operaţii de intrare-ieşire. Fişiere în C şi aplicaţii.
• Corectitudinea programelor C. Metoda aserţiunilor (assert.h).
• Complexitatea programelor (time.h). Metrici software.
• Testarea programelor C.
• Utilizarea bibliotecilor statice (.LIB) şi dinamice (.DLL).
• Metode de proiectare a programelor.

II. BIBLIOGRAFIE MINIMALĂ OBLIGATORIE


1. G. Albeanu, Algoritmi şi limbaje de programare, Editura Fundaţiei România de
mâine, Bucureşti, 2000.
2. G. Albeanu, Programare procedurală, Note de curs (Avizierul virtual /
Blackboard)
3. G. Albeanu (coord.), Tehnici de programare. Lucrări practice de programarea
calculatoarelor, Editura Fundaţiei România de mâine, Bucureşti, 2003.
4. Popa M., Popa M., Programare procedurală (Aplicaţii C şi C++ în structuri de
date şi grafică), Editura Fundaţiei România de mâine, Bucureşti, 2006.
UNIVERSITATEA SPIRU HARET file:///C:/ACTIV/Proc/FINAL/IDD-USH.htm

UNIVERSITATEA SPIRU HARET

FACULTATEA DE MATEMATICA-INFORMATICA

Suport de curs elaborat de

Prof. Univ. Dr. Grigore ALBEANU


pentru disciplina:

PROGRAMARE PROCEDURALA

2C + 2L; Ciclul I; semestrul I

Evaluare: Examen

CUPRINS

INTRODUCERE

Ce este informatica ?
Ce este un program ? Notiunea de algoritm.
Cum rezolvam probleme cu ajutorul calculatorului ?

ALGORITMI: DESCRIERE, COMPLEXITATE, CORECTITUDINE

Notiuni de teoria grafurilor


Scheme logice structurate
Notiuni introductive privind organizarea datelor
Limbaj algoritmic
Analiza complexitatii
Elemente privind corectitudinea algoritmilor

LIMBAJE DE PROGRAMARE

Vocabularul si sintaxa limbajelor de programare


Tipuri de date. Constante. Variabile. Expresii
Programare in C

Bibliografie

1 of 1 12/9/2007 7:18 PM
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM

1. Introducere

1.1. Ce este informatica?


1.2. Ce este un program? Notiunea de algoritm
1.3. Cum rezolvam probleme cu ajutorul calculatorului?

1.1. Ce este informatica?

În anul 1642, matematicianul si fizicianul Blaise Pascal (1623-1662) a inventat prima masina mecanicã, cu
roti dintate, capabilã sã realizeze operatii de adunare si scãdere a numerelor naturale. Totusi, de abia
dupã aparitia masinilor electromecanice, în 1944, John von Neumann a formulat principiul programului
înregistrat si a sugerat constructorilor de calculatoare trei principii care trebuie avute în vedere pentru
realizarea unui calculator:

programele si datele trebuie sã fie codificate sub formã binarã;


programele si datele trebuie stocate într-o memorie a masinii de calcul;
trebuie sã existe o componentã (unitate centralã de prelucrare, procesor) specialã care stie atât sã
execute operatii de calcul, cât si sã extragã, sã decodifice si sã execute instructiunile programului.

Astfel, aproape toate tipurile de sisteme de calcul ce au apãrut mai târziu sunt calculatoare de tip von
Neumann.

Aparitia sistemelor de calcul a dus la aparitia si dezvoltarea unei noi stiinte: informatica (Informatique,
Informatics, Informatik în Europa, respectiv Computer Science în SUA). Informatica reprezintã un
complex de discipline prin care se asigurã prelucrarea informatiilor cu ajutorul sistemelor de calcul.
Astãzi, informatica este prezentã în industrie, bãnci, ferme, artã, medicinã, stiinte sociale etc. si este
structuratã în mai multe domenii precum:

arhitectura sistemelor de calcul: studiazã modul de organizare a sistemului fizic (hardware) pentru a
se obtine o mai mare eficientã, sigurantã si utilitate.
sisteme de operare: studiazã modalitãtile de gestiune eficientã a resurselor fizice si a programelor.
algoritmi si structuri de date: studiazã metodele de rezolvare a problemelor si modurile de organizare
a datelor pentru a obtine programe eficiente.
limbaje de programare: studiazã modalitãtile prin care algoritmii si structurile de date sunt
prezentate calculatorului pentru a fi prelucrate.
ingineria programãrii: studiazã metodele de automatizare a proceselor de proiectare, analizã, testare
si reutilizare a programelor.
calcule numerice si simbolice: studiazã modalitãtile de reprezentare a informatiei numerice pentru
implementarea unor algoritmi numerici robusti, eficienti si de mare precizie.
sisteme de gestiune a bazelor de date: studiazã modalitãtile de structurare si organizare eficientã a

1 of 6 12/9/2007 7:19 PM
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM

colectiilor mari de date ce vor fi supuse diverselor prelucrãri.


inteligenta artificialã: studiazã modalitãtile de reprezentare si manipulare a cunostintelor în vederea
obtinerii de noi cunostinte.
animatia si robotica: studiazã modalitãtile de reprezentare, prelucrare si analizã a informatiei
audio-vizuale.

În sfera sa de preocupãri, Informatica a atras si dezvoltat o mare varietate de discipline precum: logica
matematicã, teoria automatelor, limbaje formale, cercetãri operationale, teoria grafurilor si retelelor,
calcul numeric, teoria fiabilitãtii, geometrie computationalã, teoria calculabilitãtii, baze de date, baze de
cunostinte, sisteme expert etc.

1.2. Ce este un program? Notiunea de algoritm

Solutia unei probleme, din punct de vedere informatic, este datã printr-o multime de comenzi
(instructiuni) explicite si neambigue, exprimate într-un limbaj de programare. Aceastã multime de
instructiuni prezentatã conform anumitor reguli sintactice formeazã un program. Un program poate fi
privit si ca un algoritm exprimat într-un limbaj de programare. Totusi, un algoritm descrie solutia
problemei independent de limbajul de programare în care este redactat programul.

Existã mai multe definitii ale notiunii de algoritm. A. A. Markov, a considerat algoritmul ca fiind o notiune
matematicã primarã si a descris-o astfel: Un algoritm este o retetã care descrie precis si clar un proces de
calcul.
El a descris un mecanism formal pentru a specifica o clasã largã de activitãti si anume: algoritmii normali.
Alte modalitãti de descriere a algoritmilor ce au mai fost propuse sunt: masina Turing, sistemele Post,
functiile recursive etc. În aceastã lucrare, prin algoritm vom întelege o secventã finitã de comenzi explicite
si neambigue care, executate pentru o multime de date (ce satisfac anumite conditii initiale), conduce în
timp finit la rezultatul corespunzãtor. Observãm cã se face distinctie între algoritm (care se terminã în
timp) si procedurã (care poate continua nedefinit).

Conform lui D. Knuth (The art of computer programming, Vol. I, 1997) un algoritm posedã cinci
caracteristici importante:

Un algoritm are caracter finit. El este descris printr-o secventã finitã de etape si trebuie ca, ori de câte
ori sunt parcurse etapele algoritmului pentru anumite date, procesul sã se încheie în timp finit.
Un algoritm are caracter determinist. Actiunile specificate de pasii algoritmului sunt clare, fiind
riguros prezentate.
Un algoritm are date de intrare. Se poate admite cã întotdeauna un algoritm lucreazã asupra unor
date de intrare. Acestea pot fi evidentiate din contextul în care este formulatã problema a cãrei
solutie o reprezintã algoritmul.
Un algoritm furnizeazã cel putin o valoare de iesire ce se aflã într-o relatie specificã cu datele de
intrare.
Un algoritm este eficace.

Trebuie spus cã nu orice problemã admite solutie descrisã algoritmic. Problemele pentru care existã un
algoritm de rezolvare se numesc probleme decidabile. Problemele pentru care s-a demonstrat (matematic)
cã nu admit un algoritm de rezolvare se numesc probleme nedecidabile. Nu este suficient ca o anumitã
problemã (clasã de probleme) sã admitã solutii (chiar si o singurã solutie). Din punctul de vedere al
informaticii, intereseazã dacã existã solutie ce poate fi descrisã algoritmic, deci dacã solutia problemei
poate fi construitã efectiv. De asemenea, pentru rezolvarea anumitor probleme pot exista mai multi

2 of 6 12/9/2007 7:19 PM
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM

algoritmi. Stabilirea celui mai bun dintre acestia se realizeazã în urma unui proces de analizã prin care se
determinã performantele fiecãruia dintre algoritmi.

În finalul acestei sectiuni vom descrie câtiva algoritmi elementari. Acestia vor contribui la realizarea unui
prim contact cu solutiile algoritmice. Mai întâi prezentãm câteva conventii. Datele supuse prelucrãrilor
sunt manipulate cu ajutorul variabilelor. Acestea sunt entitãti ce pot referi elemente ale unei anumite
multimi. Putem vorbi de variabile întregi (respectiv reale, caracter etc.) atunci când acestea se referã la
valori întregi (respectiv reale, caracter etc.). Actiunile realizate în cadrul unui algoritm vor fi descrise prin
verbe: executã, citeste, scrie
etc. Notatiile matematice consacrate vor fi utilizate fãrã explicatii suplimentare. Vom utiliza constructii
precum: dacã, atunci, altfel, cât timp, repetã, pânã când, pentru, de la, pânã la etc., a cãror semnificatie
este cea uzualã. O operatie importantã este aceea prin intermediul cãreia o variabilã "va primi" o anumitã
valoare. Aceastã actiune se mai numeste operatie de atribuire si, în continuare, se va nota prin ":="
Valoarea ce se atribuie unei variabile este rezultatul evaluãrii unei expresii. Expresia poate fi de tip
numeric sau de tip logic. Într-o expresie numericã apar numere (întregi, reale etc.) si operatori aritmetici
precum: + (adunare), - (scãdere), * (înmultire), / (împãrtire) etc. Expresiile logice (numite si expresii
booleene) contin operatori logici: and (si logic), or (sau logic), not (negatie) si operatori relationali (<, >, <=
(mai mic sau egal), >= (mai mare sau egal), != sau <> (diferit), = (egalitate)) folositi între elemente pentru
care aceste operatii au sens. Rezultatul evaluãrii unei expresii logice poate fi: true (adevãrat) sau false
(fals). În descrierea unei expresii pot fi folosite si alte simboluri dacã acestea sunt cunoscute sau explicate.
Utilizarea parantezelor: "(" si ")" pentru indicarea modului de evaluare este, de asemenea, permisã.

Am vãzut cã algoritmii acceptã date de intrare si furnizeazã rezultate (date de iesire). Introducerea un
valori sau a unui sir de valori se va descrie folosind verbul citeste. Afisarea unei valori sau a unui sir de
valori va fi descrisã prin verbul scrie. Vom conveni sã numerotãm pasii (etapele) unui algoritm.
numerotare va fi utilizatã eventual în alti pasi. Acest mod de prezentare a algoritmilor se numeste
descriere în limbaj conventional. În unele lucrãri, limbajul conventional mai este numit si limbaj
pseudocod.

Exemplul 1.1.
Fie a si b douã variabile întregi. Dorim sã schimbãm între ele valorile celor douã variabile. Mai precis, dacã a
= 640 si b = 480, dorim sã obtinem a = 480 si b = 640.

Un mod de a realiza aceastã schimbare presupune utilizarea unei variabile suplimentare, cu rol de
intermediar. Folosind trei operatii de atribuire, algoritmul are urmãtorii pasi:

1. citeste a, b
2. t := a
3. a := b
4. b := t
5. scrie a,b

Lãsãm ca exercitiu realizarea urmãtoarelor transformãri:

i) a --> b --> c --> a


ii) a --> b --> c --> d --> a

Atunci când va fi necesar, ne vom referii la pasii 2, 3 si 4 prin constructia interschimb(a,b).

Exemplul 1.2.
Se cere generarea primilor n termeni (n>1) ai sirului lui Fibonacci. Primii câtiva termeni sunt: 0, 1, 1, 2, 3, 5,
8, 13, ... Mai precis, termenul curent este suma celor doi termeni anteriori.

Vom prezenta douã metode. Prima metodã descrie schema de generare c := a + b, unde a, b desemneazã

3 of 6 12/9/2007 7:19 PM
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM

ultimii doi termeni generati, iar c va fi termenul curent. Deoarece se cer n termeni, este necesar un
mecanism de numãrare (incrementarea unei variabile de contorizare). Valorile contorului vor fi referite
prin variabila k. Algoritmul de generare, în prima variantã, este:

Varianta 1:
1. citeste n
2. k := 2
3. a := 0; scrie a
4. b := 1; scrie b
5. repetã
5.i) c := a + b; scrie c
5.ii) a := b
5.iii) b := c
5.iv) k := k+1
pânã când k = n.

Prin a doua metodã se vor genera termenii doi câte doi. Aceasta înseamnã ca uneori este generat unul în
plus. Descrierea ce urmeazã foloseste numai variabilele a si b pentru a indica termenii sirului.

Varianta 2:
1. citeste n
2. a := 0
3. b :=1
4. k :=2
5. cât timp k < n executã
5.i) scrie a, b
5.ii) a := a + b
5.iii) b := a + b
5.iv) k := k+2
6. dacã k = n atunci scrie a, b altfel scrie a.

Exemplul 1.3. Se considerã o secventã cu n numere întregi. Se cere afisarea numerelor în ordine crescãtoare.
Vom descrie sirul de numere prin x1, x2, ..., xn.
Cea mai simplã metodã presupune interschimbarea a câte douã elemente, pânã când nu mai sunt necesare
interschimbãri. Pasii algoritmului sunt:

1. citeste n
2. citeste x1, x2, ..., xn
3. k:=1;
4. repetã
4.i) ordonat := true
4.ii) pentru i de la 1 pânã la n-k executã
dacã xi > xi+1 atunci
a) interschimb(xi, xi+1)
b) ordonat := false
4. iii) k:=k+1;
pânã când (ordonat = true) or (k = n)
5. scrie x1, x2, ..., xn.

Justificarea metodei este simplã. Trebuie sã observãm cã la prima parcurgere, elementul maxim va ajunge
pe ultima pozitie. La a doua parcurgere, elementul imediat mai mic (decât maximul recent obtinut), va
ocupa penultima pozitie. Când nu sunt necesare interschimbãri sirul este deja ordonat.

4 of 6 12/9/2007 7:19 PM
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM

1.3. Cum rezolvãm probleme cu ajutorul calculatorului?


Am vãzut cã existã probleme pentru care nu poate fi dat un algoritm de rezolvare. Totusi cele mai multe
probleme cu care se confruntã informatica sunt probleme decidabile. Toate temele tratate în aceastã
lucrare formuleazã probleme decidabile.

Se stie cã nu învãtarea unui limbaj de programare este o sarcinã dificilã, ci rezolvarea algoritmicã a
problemelor decidabile. Este clar cã, înainte de a începe scrierea unui program trebuie, mai întâi, sã gãsim
(sau sã cunoastem deja) solutia algoritmicã a problemei puse. Cum se gãseste solutia? Etapele descrise de
G. Pólya (Cum rezolvãm o problemã? Editura Stiintificã, Bucuresti, 1965), pentru rezolvarea unei probleme
de matematicã, sunt valabile si în informaticã.

Înainte de a începe sã vedem cum se face, trebuie sã întelegem atât ipotezele problemei cât si ceea ce se
cere. Deci, întelegerea problemei, ocupã primul loc în procesul cãutãrii unei metode de rezolvare a acesteia
cu ajutorul calculatorului. Trebuie evidentiate datele de intrare si conditiile pe care acestea trebuie sã le
îndeplineascã. Este important sã identificãm esentialul. De multe ori un enunt al unei probleme contine
foarte multe elemente descriptive privind importanta problemei, consideratii de naturã istoricã, exemple,
uneori chiar si etape distincte pentru obtinerea solutiei. Cerinta problemei furnizeazã, de multe ori, chiar
idei privind modul de a ajunge la solutie. Considerarea unor configuratii particulare pentru datele de
intrare si încercarea de a lucra asupra lor, pentru a gãsi solutia, va contribui întotdeauna la o întelegere
mai bunã a enuntului.

Dacã în enunt se sugereazã etapele rezolvãrii, acestea implicând rezolvarea unor subprobleme, atunci
trebuie sã aflãm solutia algoritmicã corespunzãtoare fiecãrei etape. Dacã nu se specificã etape, dar putem
descompune problema în subprobleme mai simple atunci solutia algoritmicã a problemei initiale se va
obtine prin "compunerea" solutiilor subproblemelor. Deci este foarte important sã stim sã rezolvãm
probleme simple, eventual probleme reprezentative pentru anumite clase de aplicatii si sã stim sã
descompunem (respectiv, sã reducem) problema initialã în (la) subprobleme usor de rezolvat si apoi sã
construim solutia finalã. Abordarea prin descompuneri repetate, cu detaliere pas cu pas se numeste
abordare top-down sau rafinare iterativã.
Abordarea prin care pornind de la solutii algoritmice ale unor probleme cunoscute, construim solutii ale
altor probleme care au însã legãturã cu problema de rezolvat, iar în final, urmând aceeasi modalitate
construim solutia problemei a cãrei solutie se cere, se numeste abordare bottom-up. Aceastã metodã
permite reutilizarea programelor existente si este tot mai importantã odatã cu aparitia tehnicilor orientate
obiect. De asemenea, pentru a obtine o solutie a unei probleme este util sã privim problema si comparativ
cu alte probleme întâlnite. Numai dupã investigarea acestor variante putem trece la stabilirea metodei de
abordare.

Pentru probleme de complexitate ridicatã, oricare din metodele de abordare top-down sau bottom-up,
conduc la o solutie modularã, bazatã pe subprograme sau, mai nou, la o solutie orientatã obiect.

Multe din problemele de programare pot fi rezolvate usor dacã solutia verificã anumite principii. Dacã
solutia problemei este o multime de elemente care se poate obtine pas cu pas, pornind de la multimea vidã,
prin adãugarea celui mai bun element neconsiderat încã (si ales conform anui anumit criteriu) spunem cã
avem de-a face cu o abordare de tip greedy. Pentru probleme în care se cere o solutie optimã care satisface
principiul optimalitãtii (principiul lui Bellman) se va aplica metoda programãrii dinamice. Alte strategii
pentru elaborarea algoritmilor sunt: metoda divide et impera, metoda backtracking, euristica etc.

Vreau sa vad începutul capitolului

Vreau sa vad Cuprinsul documentului.

5 of 6 12/9/2007 7:19 PM
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM

Versiune prescurtatã a capitolului 1 din: G. Albeanu. Algoritmi si limbaje de programare. Editura Fundatiei
"România de Mâine", 2000.

6 of 6 12/9/2007 7:19 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

2. Algoritmi: Descriere, Complexitate,


Corectitudine

2.1. Notiuni de teoria grafurilor


2.2. Scheme logice structurate
2.3. Notiuni introductive privind organizarea datelor
2.4. Limbaj algoritmic
2.5. Analiza complexitatii
2.6. Elemente privind corectitudinea algoritmilor

2.1. Notiuni de teoria grafurilor

Un graf neorientat G este definit prin perechea G = (V, E), unde V este o multime nevidã de elemente
numite vârfuri (vertex), iar E este o multime (posibil vidã) de perechi neordonate cu componente
distincte ale lui V care se numesc muchii (edges). Dacã E este multimea vidã spunem cã G este trivial. În
cazul în care multimea V este finitã spunem cã avem un graf finit. Numãrul elementelor multimii V
determinã ordinul grafului finit. O muchie cu vârfurile x si y (numite extremitãti) se noteazã prin [x, y]
sau [y, x]. Spunem cã vârfurile x si y sunt incidente muchiei [x,y].

Un digraf este definit printr-o pereche G=(V, E), unde V este o multime nevidã de vârfuri, iar E este o
parte a produsului cartezian V x V ale cãrei elemente le numim arce. Un arc este notat prin (x,y) cu x
diferit de y, unde x se numeste sursã sau extremitate initialã, iar y se numeste destinatie sau extremitate
finalã. Atributele : trivial, respectiv finit, pentru un digraf se definesc similar.

Un graf (digraf) partial al unui graf (digraf) G = (V, E) este un graf (digraf) G1 = (V, E1), unde E este
submultime a multimii E, deci este graful (digraful) G însusi sau se obtine din G prin suprimarea
anumitor muchii (arce).

Un subgraf (subdigraf) al unui graf (digraf) G este un graf (digraf) H = (U, E'), unde U este submultime
a multimii V, E' este submultime a multimii E, iar muchiile (arcele) din E' sunt toate muchiile (arcele)
din E, care au ambele extremitãti în multimea de vârfuri U.

Uneori, arcele (muchiile) sunt etichetate. Dacã etichetele sunt numere reale pozitive se spune cã digraful
(graful) este ponderat.

În continuare vom considera numai grafuri (digrafuri) finite. De obicei un graf se reprezintã prin
indicarea unor puncte din plan (ce corespund vârfurilor) si a unor segmente de curbã (sau de dreaptã)
pentru indicarea muchiilor (vezi figura 2.1a). În cazul digrafurilor arcele sunt segmente de curbã
orientate, sensul fiind de la sursã spre destinatie (vezi figura 2.1b).

Definitia 2.1.1.

1 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

Fie G = (V,E) un digraf, iar x si y douã vârfuri. Numim x-y drum (de lungime n) o secventã de vârfuri D:
v0, v1, ..., vn dacã v0 = x, vn = y , iar (vi, vi+1) apartine multimii E pentru toti i, ≤ i ≤ n-1. Vârfurile x si y se
numesc extremitãtile drumului D. Un drum fãrã nici un arc este un drum trivial. Un x-y drum se numeste
circuit (sau drum închis) dacã x=y; dacã x diferit de y, se spune cã drumul este unul deschis. Circuitul este
elementar dacã toate vârfurile circuitului, cu exceptia primului si a ultimului vârf care coincid, sunt
distincte douã câte douã.

Definitia 2.1.2. Fie G = (V, E) un graf neorientat, iar x si y douã vârfuri. Secventa de vârfuri L: v0, v1, ..., vn
este un x-y lant (de lungime n) dacã [ vi, vi+1] apartine multimii E, pentru toti i, 0 ≤ i ≤ n-1, iar x=v0 si y=vn.
L este ciclu dacã x=y. Atributul elementar, pentru un lant, poate fi introdus similar.

Uneori, chiar pentru un digraf, putem folosi notiunea de lant, dacã se verificã proprietatea cã oricare
douã arce vecine au o extremitate comunã.

Definitia 2.1.3.
Numim lant (drum) hamiltonian un lant (drum) elementar al unui graf care contine toate vârfurile
grafului.

Definitia 2.1.4.
Fie G = (V, E) un graf netrivial. Spunem cã x, y din V sunt conectate în G dacã existã un x-y lant în G.
Graful G este un graf conex dacã oricare douã vârfuri din V sunt conectate în G. Dacã G este un graf trivial
(E multime vidã) se acceptã cã este graf conex. Dacã G nu este conex atunci existã cel putin douã
componente conexe (subgrafuri conexe maximale, disjuncte douã câte douã relativ la vârfuri). Un digraf G
cu proprietatea cã pentru oricare douã vârfuri x si y existã atât un x-y drum cât si un y-x drum în G se
numeste graf tare conex.

În sectiunea urmãtoare prezentãm o metodã de reprezentare a algoritmilor folosind schemele logice.


Acestea sunt introduse folosind terminologia teoriei grafurilor.

2.2. Scheme logice structurate


O transcriere graficã a etapelor (pasilor) unui algoritm este numitã organigramã. De cele mai multe ori
este folositã denumirea de "schemã logicã". Fiecãrui pas, al algoritmului, i se asociazã un bloc ce
constituie eticheta unui arc. Blocurile folosite într-o schemã logicã descriu instructiuni (comenzi) sau
predicate (expresii logice). Predicatele apar în cadrul instructiunii de ramificare. Celelalte instructiuni
sunt:

1. Instructiunea START: eticheteazã arcul initial (acel arc în a cãrui extremitate initialã nu pot sosi
alte arce). Orice schemã logicã are un unic arc initial. Acesta va indica punctul de unde începe
executia unui program.
2. Instructiunea STOP: eticheteazã un arc final (acel arc din a cãrui extremitate finalã nu pot pleca
alte arce). O schemã logicã poate avea mai multe arce finale. Acestea indicã oprirea executiei
programului descris prin intermediul schemei logice.
3. Instructiunea CITESTE: eticheteazã un arc ce indicã introducerea de la mediul de intrare
(tastaturã, disc etc.) a unei secvente de valori (numite date de intrare). Cuvântul CITESTE este
însotit de variabilele ce descriu datele de intrare.
4. Instructiunea SCRIE: eticheteazã un arc ce indicã înregistrarea la mediul de iesire (display, disc
etc.) a rezultatelor (datelor de iesire). Cuvântul SCRIE este însotit de variabilele sau constantele ce
desemneazã datele de iesire.
5. Instructiunea de atribuire: eticheteazã un arc cu eticheta v := e, unde v este o variabilã, iar e este o
expresie de acelasi tip (numeric sau logic) cu variabila v.
6. Instructiunea de ramificare: este caracterizatã prin n arce ce pleacã din acelasi punct, arce

2 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

etichetate cu predicatele p1, p2, ..., pn definite astfel încât:

p1 or p 2 or ... or pn = TRUE (adevãrat) si


pi and pj = FALSE (fals) pentru oricare i si j diferiti.

Definitia 2.2.1. Se numeste schemã logicã (sau program sub formã de schemã logicã) un graf orientat, în
care:

existã o unicã instructiune START si cel putin o instructiune STOP;


Orice vârf (diferit de extremitatea finalã a unei instructiuni STOP) este extremitatea initialã a unei
unice instructiuni;
Orice arc este etichetat cu una dintre instructiunile: START, STOP, CITESTE, SCRIE, atribuire sau
cu un predicat. In ultimul caz, extremitatea initialã a arcului trebuie sã coincidã cu extremitatea
initialã a unei instructiuni de ramificare.
pentru orice arc existã cel putin un drum care începe cu instructiunea START, se terminã cu o
instructiune STOP si contine arcul considerat.

Schemele logice sunt folosite pentru descrierea algoritmilor. Se pot pune în evidentã structuri
fundamentale precum:

1. structura secventialã
- formatã din arce conectate etichetate cu instructiuni distincte de cea de ramificare. O structurã
secventialã formatã din douã arce etichetate prin a, respectiv b se va nota prin SEQ(a,b) si are
semnificatia " executã a urmat de b".
2. structuri decizionale
(alternative) - contin, obligatoriu, cel putin un predicat si cel putin un bloc functional (instructiune
alta decât START sau ramificativã). Structurile decizionale sunt de urmãtoarele forme:
IF(p; a, b) - Dacã p este adevãrat, atunci executã a altfel executã b (vezi figura 2.2a).
IF0(p; a) - Dacã p este verificat, atunci a (vezi figura 2.2b).
CASE(p1,p2,...,pn; a1, a2, ..., an) - Dacã p1 atunci a1, dacã p2 atunci a2, ..., dacã pn atunci an
(vezi figura 2.2c).
3. Structuri repetitive
(structuri de tip ciclu, structuri iterative) - contin obligatoriu un bloc predicativ si un bloc
functional care se executã de un numãr finit de ori pânã când predicatul îsi schimbã valoarea.
Sunt posibile trei situatii:
WHILE(p; a) - Cât timp conditia p este adevãratã se executã a, apoi se continuã cu
urmãtoarea instructiune ( vezi figura 2.3a: ciclu cu test initial).
REPEAT(p; a) - Repetã a pânã când conditia p este adevãratã, apoi executã instructiunea
urmãtoare ( vezi figura 2.3b: ciclu cu test final).
FOR(p; a, b, c) - Este echivalentã cu SEQ(a, WHILE(p; SEQ(b, c))). Blocul a este un bloc
functional de initializare. Blocul b descrie instructiunea ce se va executa când conditia p este
adevãratã. Blocul c (prezentat explicit în aceastã structurã) va descrie actualizarea stãrilor
variabilelor programului cu rol deosebit în evaluarea conditiei p ( vezi figura 2.3c: ciclu cu
contor).

Exemplul 2.2.1. Urmãtoarea descriere reprezintã o secventã. Uneori secventele se pot eticheta (* vezi
figura 2.4).
ET1 SEQ
write('Introduceti 3 numere:');
read(x,y,z);
media:=(x+y+z)/3;

3 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

writeln('Media = ',media);
ET1 END

Eticheta secventei de mai sus este ET1, iar componentele secventei sunt instructiuni Pascal. Secventa
descrie citirea a trei numere, calculul mediei aritmetice si afisarea rezultatului.

Exemplul 2.2.2. Urmãtoarele secvente ilustreazã structurile decizionale.

a)(* vezi figura 2.5a *)


ET2 SEQ
read(x);>
if (x>0) or (x=0) then write('Numar nenegativ')
else write('Numar negativ');
ET2 END

b)(* vezi figura 2.5b *)


ET3 SEQ
read(titlu);
cod:=0;
if nume='algebra' then cod:=1;
write(cod);
ET3 END

c)(* exercitiu *)
ET4 SEQ
zar:=1+random(6);
case zar of
1, 3, 5 : impar:=impar+1;
2, 4, 6 : par:=par+1;
end
ET4 END

Secventa ET2 descrie citirea unei valori (se presupune cã x este un numãr) si afisarea unui mesaj în
functie de semnul numãrului x. Secventa ET3, citeste un titlu, iar dacã se introduce 'algebra' atunci
codul asociat este 1, în rest codul este 0. În final se scrie codul. Prin secventa ET4 se genereazã un numãr
aleator între 1 si 6. Apoi se analizeazã paritatea numãrului. Dacã secventa ET4 s-ar repeta, atunci
variabila impar ar contine numãrul de aparitii ale numerelor impare. Similar, variabila par va
reprezenta numãrul numerelor pare generate.

Exemplul 2.2.3. Prin urmãtoarele secvente exemplificãm structurile repetitive: While, Repeat si For
(Elaborarea schemelor logice este lãsatã ca exercitiu).
a)ET5 SEQ
read(x);i:=1; cod:=0;
while ((i<n) or (i=n)) and (cod=0) do
if x = a[i]; then cod:=1 else i:=i+1;
write(cod,i);
ET5 END

b)ET6 SEQ
repeat
zar:=1+random(6)
until zar=6;
writeln('A aparut Numarul 6!');
ET6 END

c)ET7 SEQ
read(n); suma:=0;

4 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

for i:=1 to n do
begin read(x); suma:=suma+x end;
writeln('Suma =', suma);
ET7 END

Secventa ET5 descrie citirea unui element x si verificarea ipotezei: "Elementul x se aflã printre cele n
elemente din tabloul a". În secventa ET6 se descrie generarea repetatã de numere pânã la aparitia
valorii 6. Secventa ET7, folosind variabila de contorizare i, citeste n numere, le calculeazã suma si apoi o
afiseazã. Observati prezenta predicatului la iteratiile de tip While si Repeat.

Definitia 2.2.2.
Un algoritm exprimat în functie de structurile SEQ, IF si WHILE se numeste structurat, schema logicã
asociatã se numeste schemã logicã structuratã, iar programul corespunzãtor se numeste program
structurat.

Evident, familia algoritmilor structurati este nevidã. Un rezultat foarte important afirmã: Orice algoritm
poate fi transformat într-un algoritm structurat. Aceastã afirmatie are la bazã teorema Bohm-Jacopini.
Pentru a transforma o schemã logicã (nestructuratã) într-o schemã logicã structuratã se poate folosi
regula variabilei booleene (ce rezultã din demonstratia teoremei Bohm-Jacopini). Cititorul interesat de
detalii poate consulta lucrarea: Corrado Bohm, Giuseppe Jacopini - Flow-diagrams, Turing Machines and
languages with only two formation rules. Comm. ACM. 9 (May, 1966), 366-371. Una din consecintele
importante ale programãrii structurate este eliminarea instructiunii de salt neconditionat (goto) din
programe. Totusi, existã situatii când instructiunea goto este utilã. Lungimea programelor nu va creste,
iar claritatea algoritmului nu va avea de suferit. Important este ca numãrul instructiunilor goto folosite
sã fie foarte mic, iar salturile sã fie locale.

2.3. Notiuni introductive privind organizarea datelor


Organizarea datelor, în vederea prelucrãrii acestora, este un proces complex, dar de o deosebitã
importantã. De modul în care sunt structurate datele, depinde eficienta algoritmilor de prelucrare.
Unele date sunt de tip simplu: data apare ca o entitate indivizibilã atât din punct de vedere a informatiei
pe care o reprezintã cât si în raport cu unitatea centralã de prelucrare. Alte date sunt descrise prin
componente, cu acelasi tip sau cu tipuri diferite. O colectie de date pe care s-a evidentiat un anumit mod
de structurare si s-au stabilit procedeele de înregistrare/identificare a componentelor se va numi
structurã de date. Componentele unei structuri de date pot fi de tip elementar sau pot fi, la rândul lor,
structuri. Identificarea unei componente se poate face prin pozitia pe care o ocupã în structurã sau prin
nume.

Pentru o datã elementarã trebuie specificate: un identificator, atribute (domeniul de valori, modul de
reprezentare în sistemul de calcul, precizia reprezentãrii) si valorile datei (pot fi enumerate sau indicate
printr-o proprietate comunã). Din punct de vedere al domeniului de valori asociat unei date se disting
urmãtoarele clase:

date de tip integer (numere întregi);


date de tip real sau float (cu elemente din multimea numerelor rationale);
date de tip boolean (se referã la valorile de adevãr true (adevãrat), false (fals));
date de tip char (cu elemente ale multimilor ASCII sau Unicode);
date de tip string (obtinute prin concatenarea datelor de tip caracter);
date de tip array
(structurã cu componente de acelasi tip ce ocupã locatii succesive din memoria sistemului de

5 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

calcul, identificate prin pozitie);


date de tip record (structurã cu componente oarecari, identificate prin nume).

Un mod special de organizare a datelor este întâlnit când avem de prelucrat liste. O listã liniarã este o
structurã de date omogenã, secventialã, formatã din elemente apartinând unei multimi date. O listã
poate fi vidã (nu are nici un element) sau plinã (nu mai existã spatiu pentru stocarea unor componente
suplimentare). Este foarte important sã putem accesa un element al listei, sã inserãm sau sã stergem un
element etc.

Listele pot fi stocate în memoria unui sistem de calcul în douã moduri: secvential si înlãntuit. Modul
secvential presupune stocarea elementelor listei în locatii succesive de memorie conform ordinii
elementelor din listã si retinerea adresei primului element al listei (adresa de bazã). Modul înlãntuit
presupune cã fiecare element al listei este înlocuit cu o celulã formatã dintr-o parte de informatie
(corespunzãtoare elementului listei) si o parte de legãturã ce contine adresa celulei urmãtorului element
din listã. Se va retine adresa de bazã a listei, iar ultima celulã va indica, în partea de legãturã, o valoare
specialã (ce nu poate desemna o legãturã).

Structura de date elementarã adecvatã reprezentãrii secventiale a listelor este tabloul unidimensional.

Orice listã liniarã are un început si un sfãrsit pe care le numim bazã, respectiv vârf. O listã liniarã la
care inserarea si extragerea elementelor se face prin vârful listei se numeste stivã (stack). O listã liniarã
în care inserãrile se efectueazã la baza listei, iar extragerile prin vârful listei se numeste coadã (queue).

Listele liniare pot fi transformate în liste circulare considerând cã legãtura ultimului element indicã
adresa bazei listei.

2.4. Limbaj algoritmic


O altã modalitate de reprezentare a algoritmilor o constituie utilizarea limbajului algoritmic. Limbajul
algoritmic foloseste o scriere similarã limbajelor de programare moderne. El permite atât descrierea
instructiunilor algoritmului cât si descrierea exactã a tipului datelor cu care lucreazã algoritmul. Un
algoritm descris folosind limbajul algoritmic este o succesiune finitã de declarãri si instructiuni.
Declarãrile precizeazã tipul si organizarea datelor. Ele apar înaintea instructiunilor ce descriu pasii
algoritmului. Din punct de vedere al scrierii instructiunilor, o instructiune poate ocupa mai multe
rânduri sau pe un rând pot fi scrise mai multe instructiuni. Instructiunile vor fi separate, între ele,
folosind caracterul ';'.

Cuvintele care identificã un tip de date sau o instructiune, numite în continuare cuvinte cheie, apar
evidentiate pentru a fi deosebite de numele variabilelor. O declarare utilizeazã unul dintre cuvintele
cheie integer, real, boolean, char, string, array, record, stack, queue, urmat de o listã de nume de
variabile. Declarãrile sunt separate, între ele, folosind caracterul ';'. Variabilele prezente într-o listã au
tipul si organizarea precizatã prin cuvântul cheie respectiv. De exemplu, declarãrile:
integer array a(10);
record (integer cod; string nume; real media) x, y;
stack S; queue Q; char ch; boolean ind;
indicã faptul cã a este un tablou cu maxim 10 elemente întregi; x si y sunt înregistrãri (cu trei
componente: cod - o valoare întreagã, nume - un sir de caractere, media - un numãr real), S este o stivã,
Q este o coadã, ch este un caracter, iar ind este o variabilã logicã.

O importantã deosebitã o au declarãrile de subprograme. În rezolvarea multor probleme apare


necesitatea executãrii repetate a acelorasi calcule pentru date diferite. Subprogramele permit descrierea
acestor calcule o singurã datã. Subprogramul poate fi apelat ori de câte ori este necesarã efectuarea

6 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

acestor operatii. Un subprogram este identificat printr-un nume si o listã de parametri. Subprogramele
se împart în proceduri si functii. Delararea unei proceduri constã în specificarea cuvântului procedure,
a unui identificator al procedurii si a unei liste de declarãri (între paranteze rotunde) ce indicã
informatiile ce fac obiectul transferului între apelant si apelat. Pentru declararea unei functii se foloseste
cuvântul cheie function. Spre deosebire de proceduri, functiile întorc obligatoriu un rezultat. De aceea,
în declaratii, declararea unei functii începe cu specificarea multimii de valori ce corespunde rezultatului,
a cuvântului function, a identificatorului functiei si a listei parametrilor (similar ca la o procedurã).

Un algoritm este complet cunoscut dacã este descrisã si definitia subprogramelor folosite. Definitia unui
subprogram presupune descrierea (prin instructiuni) modului în care se efectueazã calculele si se
transmit rezultatele. Mai multe detalii prezentãm în finalul acestei sectiuni.

Instructiunile limbajului algoritmic sunt urmãtoarele:

1. Instructiunea de atribuire. Aceastã instructiune are forma: v := E (atribuire simplã) sau (v 1, v2, ...,
vn) := (E1, E2, ..., En) ce realizeazã simultan atribuirile vi :=Ei, pentru oricare i = 1, 2, ..., n.
Operatia de atribuire este permisã când variabila v (variabilele v1, v2, ..., vn) din membru stâng si
expresia E (expresiile E1, E2, ..., En) sunt compatibile (se referã la aceeasi aclasã de obiecte). O
expresie contine paranteze (optional), operanzi (inclusiv apeluri de functii) si operatori adecvati.
2. Instructiuni de intrare/iesire.
Vom presupune cã citirea datelor (de intrare) se face de la un mediu de intrare (de exemplu:
tastatura sistemului de calcul), iar scrierea rezultatelor (de iesire) se face la un mediu de iesire (de
exemplu: ecranul, imprimanta, plotterul etc.). Forma instructiunilor de intrare/iesire este:
read v1, v2, ..., vn
write v1, v2, ..., vn
unde v1, v2, ..., vn sunt variabile de tip elementar.
3. Instructiunea repetitivã While. Aceastã instructiune are forma: while p do S, unde p este un
predicat, iar S este o secventã de instructiui. Deoarece instructiunile sunt separate între ele,
folosind ';' va trebui sã delimitãm secventa S. Pentru aceasta se utilizeazã constructia SEQ..END
prezentatã mai sus. Semnificatia acestei instructiuni este aceeasi ca pentru sub-schema logicã
While(p; S).
4. Instructiunea If_then_else. Aceastã instructiune are forma: if p then S1 [elseS2 ], unde p este un
predicat, iar S1 si S2 sunt secvente de instructiuni. Dacã neîndeplinirea predicatului p nu indicã
vreo actiune, portiunea else
S2 poate lipsi, fapt reprezentat prin includerea între paranteze drepte, exprimarea fiind
echivalentã cu IF0(p; S1). Atunci când atât S1 cât si S2 sunt actiuni prevãzute, instructiunea este
echivalentã cu sub-schema logicã IF(p; S1, S2).
5. Instructiunile insert si extract. Aceste instructiuni sunt necesare pentru lucrul cu liste. Acestea
sunt o prelungire a instructiunii de atribuire. Dacã se specificã o listã L atunci insert i, L (sau L:=i)
exprimã introducerea elementului specificat prin i în lista L, iar instructiunea extract i, L (sau
i:=L) specificã extragerea elementului curent din lista L si depunerea acestuia în i.
6. Instructiunea apel de procedurã. Apelarea unei proceduri se face prin instructiunea apel de
procedurã care are una din formele:
identificator_procedura
sau
identificator_procedura(lista de argumente)
unde identificator_procedura specificã o procedurã declaratã, iar argumentele sunt expresii
separate prin virgulã.

Se presupune cã atunci când se ajunge la un apel de procedurã se stabileste corespondenta între


argumente si parametri, si se executã toate instructiunile specificate în definitia procedurii. Dupã
ultima instructiune a procedurii se continuã cu instructiunea urmãtoare apelului de procedurã.

7 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

Un apel de procedurã este corect atunci când între argumente si parametri existã o concordantã ca
numãr, tip si mod de organizare. Convenim ca atunci când referim o variabilã (într-o procedurã)
de fapt, facem o referire la locatia de memorie corespunzãtoare argumentului respectiv. Spunem
cã se realizeazã un transfer prin referintã. Sunt posibile si alte moduri de transfer, dar acestea nu
sunt considerate momentan.

7. Instructiunea return. Aceastã instructiune provoacã pãrãsirea corpului unui subprogram. În cazul
în care cuvântul return
este urmat de o expresie, valoarea expresiei este folositã ca valoare de retur a subprogramului.
Instructiunea return
fãrã valoare de retur este folositã pentru a pãrãsi executia unei proceduri si a reveni în unitatea de
program din care a avut loc apelul; si anume la instructiunea ce urmeazã imediat acestui apel.
8. Pentru a usura descrierea algoritmilor admitem prezenta, ca instructiuni ale limbajului
algoritmic, a instructiunilor Repeat si For. Instructiunea Repeat este modelatã de structura
repetitivã REPEAT (p; S). Ea are forma:
Repeat S until p;
unde S este o secventã (eventual vidã) de instructiuni, iar p modeleazã o expresie logicã.

Instructiunea For este modelatã de structura iterativã FOR(p; a,b,c) si are forma simplificatã
For v := e1, e2, e3 do S
unde: S este o secventã de instructiuni, iar expresiile e1, e2 si e3 au acelasi domeniu de valori ca
variabila v. În forma prezentatã, instructiunea determinã executarea secventei S pentru v luând
succesiv valorile e1, e1+e3, e1+2e3, ..., fãrã a trece dincolo de e2. Formei de mai sus îi corespunde
structura iterativã:
FOR((v-v2)*v3≤0; SEQ v:= e1; v1 :=e2; v3:=e3 END, S, v := v +v3).

2.5. Analiza complexitãtii


Existenta unui algoritm de rezolvare a unei probleme genereazã, imediat, întrebãri ca: Mai existã un alt
algoritm de rezolvare? Este algoritmul gãsit "cel mai rapid"? Acest paragraf introduce notiunile
fundamentale privind complexitatea algoritmilor si prezintã exemple simple de algoritmi pentru care se
determinã complexitatea.

Analiza complexitãtii unui algoritm presupune determinarea resurselor de care acesta are nevoie pentru
a produce datele de iesire. Prin resursã întelegem timpul de executare, dar uneori este necesar sã
analizãm si alte resurse precum: memoria internã, memoria externã etc. Modelul masinii pe care va fi
executat algoritmul nu presupune existenta operatiilor paralele; operatiile se executã secvential.

Timpul de executare al unui algoritm reprezintã numãrul de operatii primitive executate. Trebuie,
pentru fiecare algoritm, sã definim notiunea de operatie primitivã, independent de masina secventialã pe
care se va executa algoritmul.

În analiza complexitãtii unui algoritm avem în vedere cazul cel mai defavorabil din mai multe motive:

1. Timpul de executare în cazul cel mai defavorabil oferã o limitã superioarã a timpului de executare
(avem certitudinea cã executarea algoritmului nu va dura mai mult).
2. Situatia cea mai defavorabilã este întâlnitã des.
3. Timpul mediu de executare este, uneori, apropiat de timpul de executare în cazul cel mai
defavorabil, dar dificil de estimat.

Analiza exactã a complexitãtii unui algoritm conduce la formule extrem de complicate. De aceea se
folosesc notatii asimptotice, care evidentiazã doar termenul preponderent al formulei.

8 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

Fie f si g douã functii reale. Atunci:

f(x) = o(g(x)) dacã existã si este egalã cu 0 (zero) limita:

f(x) = O(g(x)) dacã existã c si x0 astfel încât

f(x) = theta(g(x)) dacã existã constantele C 1 si C2 pozitive, si x0 astfel încât pentru orice x≥ x0:

f(x) ~ g(x) dacã

f(x) = Omega(g(x)) dacã existã M>0 si un sir x 1, x2, ..., xn, ... Inf astfel încât pentru oricare j>0 are
loc inegalitatea

În general, se considerã cã un algoritm este mai rapid decât altul dacã are un ordin de mãrime pentru
timpul de executare mai mic. Pentru o dimensiune micã a datelor de prelucrat, aceste comparatii pot fi
(însã) eronate.

Notatia theta este utilizatã pentru a specifica faptul cã o functie este mãrginitã (inferior si superior).
Semnificatia notatiei O este de limitã superioarã, în timp ce semnificatia notatiei Omega este de limitã
inferioarã.
Exemple: x3 = o (x5); sin(x) = o (x); (x+1)2 = theta (2x2); x2+3x ~ x2.

Definitia 2.5.1.
Fie A un algoritm, n dimensiunea datelor de intrare si T(n) timpul de executare estimat pentru
algoritmul A. Se spune cã algoritmul A are comportare polinomialã (apartine clasei P) dacã existã p>0
astfel încât T(n) = O(np).

Definitia 2.5.2. O functie care creste mai rapid decât functia putere xp, dar mai lent decât functia
exponentialã ax
cu a>1 se spune cã este cu crestere exponentialã moderatã. Mai precis: f este cu crestere exponentialã
moderatã dacã pentru oricare p>0 avem f(x) = Omega(xp) si oricare M>0 avem f(x) = o((1+ M)x).

Definitia 2.5.3. O functie f are crestere exponentialã dacã existã a>1 astfel încât f(x) = Omega(ax) si
existã b>1 astfel încât f(x) = O(b x).

Printre functiile n -> f(n), nemãrginite, functiile ce cresc cel mai lent sunt, de exemplu, de forma log log n
sau (log log n)1,02. Pentru n = 1000000, log log n ~ 2,6. Deci un algoritm a cãrui complexitate este log log
n este preferabil unui algoritm (elaborat pentru rezolvarea aceleiasi probleme) de complexitate log n.
Algoritmii de tip polinomial sunt mai lenti (cresterea functiei T(n) este mai rapidã) decât algoritmii de
tip logaritmic. Urmeazã apoi algoritmii moderati (cu T(n) de forma nlogn etc.) si cei cu crestere
exponentialã (2n, n33n
etc.). Algoritmii cei mai lenti sunt cei pentru care functia T(n) este foarte rapid crescãtoare (de exemplu:
T(n) = n!).

În informaticã sunt interesanti numai algoritmii care conduc la un timp de calcul cel mult moderat.
Dacã un algoritm necesitã timp de calcul exponential sau factorial, acesta va fi utilizat numai în cazuri

9 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

exceptionale. Tabelul urmãtor ilustreazã cele de mai sus.

n 10 100 1000 10000


n2 100 10000 1000000 100000000
n3 1000 1000000 1000000000 1000000000000
log n 1 2 3 4
log log n 0 0.30103 0.47712 0.60206

Exemplul 2.5.1. (Produsul a douã numere complexe). Considerãm numerele complexe a+bi si c+di (i2 =
-1; a, b, c, d numere reale). Un algoritm pentru calculul produsului (a+bi)(c+di) este urmãtorul:
real a,b,c,d,p,q;
real t1,t2;
P1 SEQ
Read a, b, c, d;
t1:=a*c; t2:=b*d; p:=t1-t2;
t1:=a*d; t2:=b*c; q:=t1+t2;
write p,q;
P1 END

Acest algoritm (notat P1) necesitã 4 înmultiri, o adunare si o scãdere. În final p reprezintã partea realã,
iar q furnizeazã partea imaginarã a produsului celor 2 numere complexe. Urmãtorul algoritm (notat P2)
calculeazã acelasi produs folosind 3 înmultiri, 3 adunãri si 2 scãderi:
real a,b,c,d,p,q;
real t1,t2,t3,t4;
P2 SEQ
Read a, b, c, d;
t1:=a+b; t2:=t1*c; t1:=d-c; t3:=a*t1;
q:=t2+t3;
t1:=d+c; t4:=b*t1;
p:=t2-t4;
write p,q;
P2 END

Algoritmul P1 necesitã 2 locatii temporare, în timp ce algoritmul P2 necesitã 4 locatii suplimentare. În


plus, necesarul de memorie depinde de metoda de reprezentare a numerelor reale într-un sistem de
calcul.

(Determinarea valorii maxime si a indicelui corespunzator, dintr-un sir (tablou)). Fie X un tablou cu n
elemente apartinând unei multimi total ordonate Q: X = (x 1, x2, ..., xn) cu xi din Q pentru i = 1, 2, ..., n.
Fie y o variabilã de tipul Q. Se cautã un indice k, între 1 si n astfel ca
y := max{xi : i=1, 2, ..., n | = xk,
iar k este cel mai mic numãr cu aceastã proprietate.

Pentru rezolvarea acestei probleme putem utiliza urmãtorul algoritm, denumit în continuare MAXIM,
pentru Q = real.
procedure maxim(x,n,y,k)
integer n;real array x(n);
real y; integer i,k;
SEQ
k:=1; y:=x[1];
for i = 2, n, 1 do if y < x[i] then SEQ y := x[i]; k:=i END;
return
END

10 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

Observãm cã T(n) = n-1. Necesarul de memorie pentru stocarea datelor de prelucrat se exprimã în
functie de metoda de reprezentare a informatiei în calculator.

Propozitia 2.5.1.
Pentru determinarea maximului dintre n elemente ale unei multimi total ordonate sunt necesare cel
putin n-1 comparãri (T(n) = n-1).

Exemplul 2.5.3. (Determinarea celui mai mare divizor comun). Fie m si n douã numere întregi pozitive si,
q si r câtul, respectiv restul împãrtirii lui n la m, adicã n = qm+r (0 ≤ r < m). Spunem cã m divide n dacã
restul împãrtirii lui n la m este zero.

Pentru determinarea celui mai mare divizor comun (cmmdc) a douã numere se poate utiliza algoritmul
lui Euclid. Dacã d este un divizor oarecare al numerelor n si m, atunci d divide restul r. Reciproc, dacã d
este un divizor al numerelor m si r, relatia n = mq + r aratã cã d este divizor al numãrului n. Deci:

cmmdc(n, m) = cmmdc(m, r).

Dacã r = 0 atunci n = qm. Deci cmmdc(n, m) = m. Folosind notatia n mod m pentru r, putem scrie:

cmmdc(n, m) = cmmdc(m, n mod m).

Necesarul de memorie pentru stocarea numerelor n si m se poate exprima prin

theta(log m) + theta(log n) ~ theta(log (mn)) biti.

Timpul necesar executãrii algoritmului este dat de urmãtorul rezultat.

Propozitia 2.5.2.
Fie n si m douã numere întregi pozitive. Algoritmul lui Euclid pentru a determina cmmdc(m, n)
efectueazã cel mult [2log2M]+1 operatii de împãrtire întreagã, unde M = max (m, n).

Exemplul 2.5.4. (Sortare prin insertie). Fiind datã o secventã de elemente caracterizate de valorile x1, x2,
..., xn apartinând unei multimi total ordonate T, sã se determine o permutare xi(1), xi(2), .., xi(n) a
secventei date, astfel încât xi(j) ≤ xi(k)
pentru i(j) ≤ i(k), unde " ≤ " este relatia de ordine pe multimea T. Metoda ce va fi prezentatã în
continuare se mai numeste si "metoda jucãtorului de cãrti", si este una dintre cele mai cunoscute metode
de sortare.

Sortarea prin insertie se bazeazã pe urmãtoarea procedurã: Fie un tablou x cu n elemente (x[i] este al
i-lea element din secventa de intrare). Pornim cu subtabloul x[1] si la primul pas cãutãm pozitia în care
ar trebui sã se gãseascã elementul x[2]. Dacã x[2] < x[1], atunci x[2] trebuie sã fie mutat în locul
elementului x[1]. La un pas i (pentru i între 1 si n), avem subtabloul x[1..i-1] ordonat si încercãm sã-l
plasãm pe x[i] astfel încât sã obtinem un tablou sortat între pozitiile 1 si i. Pentru aceasta, se comparã
succesiv x[i] cu elementele tabloului x[1..i-1] pentru a se determina acea pozitie j pentru care x[i] ≥ x[j],
indexul de plasare fiind j+1.

Algoritmul prezentat în continuare utilizeazã insertia directã:


procedure insert_sort(n,x);
integer n;
integer array x(n);
integer i,j,temp;
SEQ
for i = 2, n, 1 do
SEQ

11 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

temp :=x[i];
j:=i-1;
while (j>=1) and (x[j] > temp) do
SEQ
x[j+1] :=x[j];
j:=j-1
END
x[j+1]:=temp
END;
return
END

Este clar cã, timpul de executie nu depinde doar de n, numãrul de elemente de sortat, ci si de pozitia
initialã a elementelor din secventã.

Fie F(n) - numãrul de comparãri necesare, iar G(n) numãrul de mutãri necesare algoritmului insert_sort
pentru sortarea unui tablou cu n elemente.

Propozitia 2.5.3.
2
Complexitatea metodei de sortare prin insertie directã este caracterizatã prin: F(n) = O(n ), G(n) =
O(n2).

2.6. Elemente privind corectitudinea algoritmilor


A verifica corectitudinea unui algoritm înseamnã a verifica dacã algoritmul conduce într-un interval
finit de timp la obtinerea solutiei corecte a problemei pentru care a fost elaborat. Vom vedea în capitolul
5 câteva metode de rezolvare a problemelor, deci de a elabora algoritmi. Metodele descrise în acest
capitol se vor exemplifica pentru algoritmi simpli. Pentru aspecte suplimentare legate de corectitudinea
algoritmilor se poate folosi lucrarea: Tudor Bãlãnescu. Corectitudinea algoritmilor. Editura Tehnicã,
Bucuresti, 1995.

Notatie. Constructia {P}A{Q}, numitã si formulã de corectitudine totalã contine urmãtoarele elemente:

P - comentariu care descrie proprietãtile datelor de intrare (preconditia);

A - algoritmul (secventa de instructiuni) supus analizei;

Q - comentariu care descrie propriet{tile datelor de iesire (postconditia).

Definitia 2.6.1. Un algoritm {P}A{Q} este corect când propozitia urmãtoare este validã:

Dacã

datele de intrare satisfac preconditia P

Atunci

1) executarea lui A se terminã (într-un interval finit de timp) si

2) datele de iesire satisfac postconditia Q.

Folosind elementele fundamentale ale logicii matematice rezultã cã urmãtoarele observatii sunt
adevãrate:

1. Algoritmul {false}A {Q} este corect, oricare ar fi A si Q.

12 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

2. Algoritmul {P}A{true} este corect dacã si numai dacã executarea lui A se terminã atunci când
datele initiale satisfac proprietatea P.

3. Dacã{P}A{Q} si {R}A{Q} sunt formule corecte, atunci {P v R}A {Q} este formulã corectã.

Pentru a stabili corectitudinea algoritmilor complecsi se procedeazã la descompunerea acestora î


elemente simple a cãror corectitudine se analizeazã. În continuare vor fi prezentate reguli pentru a
analiza corectitudinea unor astfel de algoritmi. Pentru o formalizarea avansatã a acestor reguli, cititorul
interesat poate parcurge lucrarea: C. A. R. Hoare et al. Laws of Programming. Comm. ACM. 30(8), 1987,
672-687.

Regula compunerii secventiale (CS):

Dacã A este de forma SEQ B; C END atunci a verifica formula {P}A{Q}, revine la a verifica form
{P}B{R} si {R}C{Q}, unde R este un predicat asupra datelor intermediare.

Este evident cã regula CS poate fi aplicatã iterativ. Mai precis, dacã A este de forma SEQ A1; A2; ..., An
END atunci obtinem regula compunerii secventiale generale:

&t9;CSG: Dacã {P0} A1 {P1}, {P1} A2 {P2}, ...., {Pn-2}An-1{Pn-1} si

{Pn-1}An{Pn} sunt algoritmi corecti,

atunci{P0}A{Pn} este algoritm corect.

Exemplul 2.6.1.
Este usor de verificat cã urmãtorul algoritm este corect (presupunem cã x si y sunt variabile întregi, iar
a si b constante întregi):
{ x = a si y = b}
SEQ
x:=x+y;
y:=x-y;
x:=x-y
END
{ x = b si y = a }

Regula implicatiei (I):

Aceastã regulã este utilã în cazul algoritmilor ce urmeazã a fi aplicati în conditii mai tari decât pentru
cele care au fost deja verificati.

O proprietate P este mai tare decât proprietatea Q dacã este adevãratã propozitia compusã: P -> Q.

Regula implicatiei are urmãtoarea formã:

I: Dacã{P} A {Q} este algoritm corect, P1 -> P si Q -> Q1,

atunci {P1} A {Q1} este algoritm corect.

Regula instructiunii de atribuire (A):

13 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

Fie notatiile:

x Variabilã simplã

e Expresie;

Def(e) Proprietatea satisfãcutã de acele elemente pentru care evaluarea


expresiei e este corectã (Exemplu: pentru integer array b(10),
Def(b(i)):= (i=1, 2, ..., 10));

P(x) Formulã în care apare variabila x;

P(x/e) Formula obtinutã din P(x) prin substituirea variabilei simple x cu


expresia e, ori de câte ori x este variabilã liberã în P, iar dacã e
contine o variabilã y care apare legatã în P, înainte de substitutie
variabila y se înlocuieste printr-o nouã variabilã (care nu mai apare
în e).

Valoarea de adevãr a propozitiei P -> Q(x/e) nu se schimbã dacã în Q(x/e) se efectueazã substitutia
descrisã de atribuirea x := e. Regula atribuirii este deci:

A: Dacã P -> (Def(e) and Q(x/e)) atunci algoritmul {P} x:=e {Q} este corect.

Exemple de instructiuni corecte:

a){x = n!} n:=n+1; x:=x*n {x = n!}

b){(x = a) and (y = b)} t:=x; x:=y; y:=t {(x = b) and (y = a)}

c){(1<=i < n-1) and (s = SUM{b[k]: k=1, ..., i-1})}

s:=s+b[i]; i:=i+1

{(1< i < n) and (s = SUM{b[k]: k=1, ..., i-1})}

dacã b este declarat prin integer array b(n).

Regula instructiunii if (IF si IFR):

Dacã c este o expresie booleanã si A si B sunt algoritmi, pentru cele douã forme ale instructiunii if
valabile regulile de corectitudine:

IF: Dacã

{P and c} A {Q}, {P and not c} B {Q} sunt corecte, iar P -> Def(c) este adevãratã

Atunci formula

{P} if c then A else B {Q} este corectã.

IFR: Dacã

14 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

{P and c} A {Q} este corectã, iar P and (not c) -> Q si P -> Def(c) sunt adevãrate

Atunci

{P} if c then {Q} este formulã corectã.

Se poate observa cã aplicarea regulilor instructiunii de decizie nu este în sine dificilã corectitudinea
acestei instructiuni se reduce la corectitudinea instructiunilor componente.

Exemple de instructiuni corecte:

a){true} if x>y then SEQ t:=x; x:=y; y:=t END {x <= y}

b){(x=a) and (y=b)} if x>=y then m:=x else m:=y {m = max(a,b)}

c){x=a} if x<0 then x := -x {x = |a|}

Regula instructiunii while (W):

Regula instructiunii while trebuie sã precizeze dacã nu apare fenomenul de ciclare, iar prelucrãrile
corecte (în paranteze rotunde apare descrierea formalã).

Fie algoritmul {P} A; while c do S {Q}. Presupunem cã existã o proprietate invariantã I (vezi mai jos) si
o functie de terminare t cu valori numere întregi care satisfac urmãtoarele conditii:

Când I este adevãratã atunci expresia booleanã c este bine definitã (adicã I -> Def(c)).

Proprietatea I rezultã prin executarea secventei A (adicã, {P} A {I} este algoritm corect).

La terminarea instructiunii while, proprietatea finalã Q poate fi dedusã (adicã, I and (not C) ->
Q).

I este proprietate invariantã la executarea unei iteratii: dacã I este adevãratã înainte de executarea
secventei S si expresia booleanã c este adevãratã, atunci executarea secventei S se terminã într-un
interval finit de timp si I este adevãratã la sfârsit (adicã, {I and c} S {I} este algoritm corect).

Dacã rezultatul evaluãrii expresiei c este true si proprietatea I este adevãratã, atunci existã cel
putin o iteratie de efectuat (adicã, I and c -> (t > =1)).

Valoarea lui t descreste dupã executarea unei iteratii (adicã, {(I and c) and (t=a)} S {t < a}).

În aceste conditii, algoritmul considerat este corect.

Exemplul 2.6.2. (Determinarea celui mai mare divizor comun a douã numere întregi). Fie a si b douã
numere întregi, iar m = |a| si n = |b|. Atunci urmãtorul algoritm este corect.

{(x > 0) and (y > 0) and (x = m) and (y = n)}

while x <> y do

if x > y then x := x - y else y := y - x;

15 of 16 12/9/2007 7:20 PM
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM

{x = cmmdc(m,n)}

Într-adevãr, existã proprietatea invariantã

I: (cmmdc(x,y) = cmmdc(m,n)) and (x > 0) and (y > 0),

iar ca functie de terminare se poate lucra cu: t(x,y) = x+y. Verificarea ipotezelor regulii W este simpl˜.

Exemplul 2.6.3. (Al n-lea termen al sirului lui Fibonacci). Fie fn, al n-lea termen al sirului lui Fibonacci.
Urmãtorul algoritm este corect.

{n >= 0}

a:=0; b:=1; k:=n;

while (k > 0) do

SEQ

temp := b;

b := a + b;

a := temp;

k := k-1

END;

{a = fn}

Într-adevãr, luãm functia de terminare t(k) = k, iar proprietate invariantã este:

I: (a = fn-k ) and (b = fn-k+1) and (temp = fn-k) and (0 <= k <=n).

Deoarece instructiunile repetitive for (ciclu cu contor) si repeat (ciclu cu test final) se pot implementa
folosind instructiunile anterioare, pentru demonstrarea corectitudinii acestora se aplicã aceleasi
principii.

Mergi la inceputul capitolului

Text prescurtat dupa G. Albeanu. Algoritmi si limbaje de programare. Editura Fundatiei "România de
Mâine", 2000

16 of 16 12/9/2007 7:20 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

3. Limbaje de programare

3.1. Vocabularul si sintaxa limbajelor de programare


3.2. Tipuri de date. Constante. Variabile. Expresii
3.3. Programare în C

3.1. Vocabularul si sintaxa limbajelor de programare


Vocabularul unui limbaj de programare este format din cele mai simple elemente cu semnificatie lingvisticã
numite entitãti lexicale sau tokens. Elementele vocabularului sunt alcãtuite din caractere Unicode (c
constituie alfabetul limbajului). Standardul Unicode contine ca subset codul ASCII, dar reprezentarea
internã a caracterelor Unicode foloseste 16 biti. Cele mai utilizate simboluri sunt: literele mari si m
alfabetului englez, cifrele sistemului zecimal, diferite semne speciale.

Unitãtile lexicale sunt separate, între ele, prin comentarii si spatii. Pentru aproape toate limbajele
programare se pot evidentia unitãti lexicale precum: cuvinte cheie, identificatori, literali, separatori
operatori. Cuvintele cheie sunt secvente de caractere ASCII rezervate (nu pot avea altã semnificatie)
utilizate pentru definirea unitãtilor sintactice fundamentale. Pentru exemplificare ne referim la limbajele de
programare Pascal si Java:

1. Cuvinte cheie Pascal: absolute, and, array, begin, case, const, div, do, downto, else, end, external, file,
for, forward, function, goto, if, implementation, in, inline, interface, interrupt, label, mod, nil, not, of,
or, packed, procedure, program, record, repeat, set, shl, shr, string, then, to, type, unit, until, uses,
var, while, with, xor.

2. Cuvinte cheie Java: abstract, boolean, break, byte, case, cast, catch, char, class, const, continue,
default, do, double, else, extends, final, finally, float, for, future, generic, goto, if, implements, import,
inner, instanceof, int, interface, long, native, new, null, operator, outer, package, private, protected,
public, rest, return, short, static, super, switch, synchronized, this, throw, throws, transient, try, var,
void, volatile, while, byvalue. Cuvintele cheie subliniate sunt prezente si in limbajul C alaturi de altele.

Identificatorii sunt secvente, teoretic nelimitate, de litere si cifre Unicode, începând cu o literã sau liniuta de
subliniere (în limbajul C). Identificatorii nu pot fi identici cu cuvintele rezervate.

Literalii ne permit introducerea valorilor pe care le pot lua tipurile de date primitive si tipul sir de
caractere. Mai precis, lieralii sunt constante întregi, flotante, booleene, caracter si, siruri de caractere.

Literalii întregi, în general, pot fi descrisi prin reprezentãri în una din bazele de numeratie: 10, 16 s
Lungimea reprezentãrii interne depinde de implementarea limbajului. De exemplu, în limbajul Pascal,
literal întreg, cu semn, este reprezentat pe 16 biti, descrierea sa în baza 16 fiind o secventã a simbolur
asociate reprezentãrii numãrului întreg în baza 16 având prefixul $.

Literalii flotanti reprezintã numere rationale. Ei sunt formati din urmãtoarele elemente: partea întrea
partea fractionarã si exponent. Exponentul, dacã existã, este introdus de litera E sau e urmatã optional de
un semn al exponentului. Exemple: 3.14; 23.5 e+2; 3e-123.

Literalii booleeni sunt TRUE si FALSE, primul reprezentând valoarea booleanã de adevãr, iar celãl
valoarea booleanã de fals. Desi TRUE si FALSE nu sunt cuvinte rezervate, acestea nu pot fi folos

1 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

identificatori (în Pascal, Java s.a).

Literalii caracter sunt folositi pentru a desemna caracterele codului Unicode (sau ASCII, acolo unde es
cazul). Descrierea unui literal caracter se fie folosind o literã, fie o secventã specialã. Secventele specia
(numite secvente escape în C, C++ si Java) permit specificarea caracterelor fãrã reprezentare graficã
precum si a unor caractere speciale. Caracterele ce au reprezentare graficã pot fi descrise între apostrofuri,
ca în exemplele: 'P', 'A', '3', '!'. Secventele speciale se descriu diferit de la un limbaj la altul. Vom
exemplifica folosind limbajele Pascal si Java.

Secvente speciale în limbajul Pascal: 1) Un întreg din domeniul 0, ..., 255 precedat de simbolul #
desemneazã un caracter dat prin codul sãu ASCII. 2) Un caracter imprimabil precedat de semnul
desemneazã un "caracter de control" având codul ASCII în domeniul 0, ..., 31.

Secventele escape în limbajul Java se descriu folosind apostrofuri, semnul \, litere si cifre. Vom exem
indicând câteva secvente predefinite: '\b' (backspace = #8), '\n' (linefeed), '\r' (carriage return) etc.

Un literal sir de caractere este constituit din zero sau mai multe caractere între delimitatori. Secvent
caractere ce formeazã sirul poate contine atât caractere imprimabile cât si secvente speciale. În limbaj
Pascal se utilizeazã apostroful ca delimitator, iar în limbajul C( C++, Java) ghilimelele.

Separatorii sunt caractere ce indicã sfârsitul unui token si începutul altuia. Acestia participã si la
constructia sintaxei limbajelor de programare. Ei nu trebuie confundati cu spatiile care si acestea sepa
unitãti lexicale distincte. Separatorii sunt necesari când unitãtile lexicale diferite sunt scrise fãrã spatii între
ele. Cei mai întâlniti separatori sunt: ( ) { } [ ] ; , . Exemple: x[10], f(x,y), carte.autor etc. Operatorii sunt
simboluri grafice ce desemneazã operatiile definite de un limbaj de programare. În unele limbaje
programare este posibilã redefinirea operatorilor, acelasi simbol fiind utilizat pentru operatii diferite
rezultã din contextul în care apar. Lista minimalã a operatorilor aritmetici include: +(adunare),
/(împãrtire), *(înmultire). Mai sunt admise si operatii precum: % (C, Java) sau mod (Pascal, Modu
(împãrtire întreagã în limbajul Pascal). Alti operatori sunt: operatori logici, operatori relationali, operatori
asupra sirurilor de caractere etc. Toti operatorii pot fi priviti si ca separatori.

O constructie aparte utilizatã în programe pentru explicarea sau documentarea textului program
comentariul. Comentariile sunt delimitate de textul programului folosind anumiti delimitatori. În limb
Pascal, un comentariu este scris între acoladele ã } sau între secventele (*, *). Programele C++, Java p
contine comentarii pe o singurã linie si încep cu //, sau pe mai multe linii si sunt cuprinse între /* si */.

Alte elemente lexicale ce pot fi prezente într-un program sunt etichetele si clauzele. Etichetele sunt siruri de
cifre zecimale/hexazecimale sau identificatori folosite în legãturã cu o instructiune de salt (goto) pen
marcarea unor instructiuni. Clauzele (numite si directive) sunt cuvinte cheie ce desemneazã instructiuni
efect în timpul compilãrii.

Prin sintaxa unui limbaj de programare se întelege, în general, un ansamblu de reguli privind agreg
unitãtilor lexicale pentru a forma structuri mai complexe (declaratii, instructiuni, module, progra
Prezentarea acestor reguli se poate folosind limbajul natural sau mecanisme formalizate. Descrierea
sintaxei în limbaj natural poate conduce la neclaritãti sau specificatii incomplete. Cu ajutorul mecanismelor
formale sintaxa unui limbaj este complet specificatã. Cea mai folositã notatie este cunoscutã sub numel
notatie BNF (Backus-Naum-Form) si a fost folositã pentru prima datã, în anul 1959, la specificarea
limbajului Algol-60. Aceastã notatie are aceeasi putere generativã cu gramaticile independente de c
introduse de N. Chomsky. Totusi, limbajele de programare nu sunt independente de context ci numa
portiuni ale acestora pot fi modelate cu ajutorul limbajelor independente de context. Pentru a putea
specifica un întreg limbaj de programare se poate folosi notatia BNF extinsã. În prezentarea din acest
capitol vom utiliza opt metasimboluri: ::= < > { } [ ] | pentru a defini unitãtile sintactice ale limbajului
Pascal. Metasimbolurile < si > sunt folosite pentru delimitarea numelui unei unitãti sintactice. Presupunem,
de asemenea, existenta unei operatii de concatenare pe multimea unitãtilor sintactice. Metasimbolul ::=

2 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

apare dupã numele unei unitãti sintactice si are semnificatia "se defineste prin". Metasimbolul | este utilizat
pentru a delimita mai multe variante de definire ale unei unitãti sintactice, aceasta fiind obtinutã p
reuniunea variantelor. Metasimbolurile { si } indicã repetarea posibilã (de zero sau mai multe ori)
simbolurilor pe care le delimiteazã. Pentru a desemna prezenta optionalã a unor simboluri se util
delimitatori, metasimbolurile [ si ]. Vom admite, pentru prescurtare metasimbolul ... care indicã
continuarea unui sir de valori conform contextului în care apare. Iatã câteva exemple:

1. <literã> ::= A ... Z descrie multimea literelor mari;

2. <cifrã> ::= 0 ... 9 descrie multimea cifrelor zecimale;

3. <identificator> ::= <literã> { <literã> | <cifrã>} descrie modul de formare a identificatorilor: un sir de
litere si/sau cifre, primul semn fiind o literã.

4. <secventã cifre> ::= <cifrã> { <cifrã>} descrie modul de formare a unei secvente de cifre;

5. <întreg fãrã semn> ::= <secventã cifre> defineste un numãr întreg fãrã semn;

6. <semn> ::= + | -

7. <întreg cu semn>::= [ <semn><întreg fãrã semn> spune cã un întreg cu semn este un întreg fãrã semn
precedat de un semn: + sau -.

Prin diagrame sintactice se realizeazã o reprezentare graficã a modului de agregare a unitãtilor sintactice.
În cele ce urmeazã vom prefera limbajul natural (în anumite cazuri) si notatia BNF extinsã (în alte ca
cititorul interesat asupra diagramelor sintactice poate consulta, de exemplu: N. Wirth: Systematic
Programming: An introduction, Prentice Hall, 1972.

3.2. Tipuri de date. Constante. Variabile. Expresii

Un tip de date este o structurã compusã din: 1) o multime X de valori numite date si 2) o multime d
compozitie pe X (operatii ce se pot efectua cu valori din X). O datã are un singur tip (apartine unei s
multimi). Existã limbaje de programare puternic tipizate (în sensul verificãrii cu regularitate a apartente
unei date la multimea de valori a tipului sãu, încã din faza de compilare). Astfel de limbaje de programa
sunt: Pascal, Modula, Ada etc.

Tipurile de date sunt standard sau definite de utilizator. Tipurile definite de utilizator se introduc
intermediul unei definitii folosind un cuvânt cheie precum type (în Pascal), typedef (în C) sau class (
limbajele C++ si Java). De asemenea se vor utiliza diverse cuvinte cheie pentru a specifica structura tipu
Dacã pentru o anumitã structurã a unui tip nu este stabilit un identificator, spunem cã avem de-a cu u
anonim.

Valorile unui tip de date (elementele multimii X sunt referite fie prin variabile, fie prin constante (literali
sau constante simbolice). O locatie de memorie care poate stoca o valoare a unui anumit tip de date s
numeste, prin abuz de limbaj, variabilã. Orice variabilã trebuie sã fie declaratã pentru a putea fi folositã. O
declaratie contine un tip de valori - ce indicã: ce se stocheazã, cum se stocheazã si în ce operatii interv
valorile stocate - si un identificator pentru a ne referi la variabila ce obiectul declaratiei. Practic o variabilã
este un obiect caracterizat de tip, adresã si valoare, pentru care atributul valoare poate fi modificat.

În limbajul Pascal declaratia variabilelor este precedatã de cuvântul cheie var:

3 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

var <declaratie variabile>{ <declaratie variabile>}

unde

<declaratie variabile> ::= <identificator>{,<identificator>}: <tip>.

În limbajele C, C++ si Java declaratia variabilelor aratã astfel:

<tip> <identificator>{,<identificator>} În functie de locul în care apare declaratia unei variabile, acesteia i
se pot atribui atribute precum: local, global, static etc.

Existã limbaje de programare (de exemplu Java) care definesc o valoare implicitã pentru fiecare variab
atunci când prin program aceasta nu "primeste" nici o valoare. Totusi, cele mai multe limbaje de
programare nu oferã acest serviciu si este necesar sã se realizeze operatii de "initializare" explicitã.

Initializarea unei variabile chiar în momentul declarãrii acesteia, în limbajele de programare care pe
aceasta, se realizeazã folosind o descriere de forma:

IdentificatorulTipului IdentificatorulVariabilei = ValoareInit;


unde se presupune cã ValoareInit este de acelasi tip cu tipul variabilei sau poate fi convertitã (transformatã
foarte usor) într-o valoare de acest tip.

Prezentarea elementelor unui tip este posibilã fie prin intermediul literalilor, fie prin intermediu
constantelor simbolice. Constantele simbolice sunt identificatori asociati unor elemente ale anumitor
multimi. Declararea unei constante simbolice Pascal se realizeazã conform regulii:

const <identificator> = <constantã>;

unde <constantã> este un literal, o expresie constantã (în care intervin literali) sau elemente structura
limbajul C, constantele simbolice se pot introduce prin intermediul directivei #define sau cuvântului cheie
const atunci când sunt declarate variabile ce nu pot fi modificate în program.

Operatiile cu elemente ale unui tip sunt fie predefinite, fie sunt introduse prin declaratii function sau
procedure (în Pascal) sau operator
(în C++). Agregarea variabilelor, constantelor si a operatorilor conduce la constructii numite expre
Expresiile sunt evaluate în cursul executãrii unui program. Rezultatul unei expresii depinde de va
variabilelor în momentul evaluãrii.

Tipurile de date întâlnite în limbajele de programare actuale sunt clasificate în: tipuri de date simple; tipuri
de date structurate, tipuri referintã (pointer), tipuri procedurale. În limbajele C, C++ si Java existã tipu
void. Aceastã multime notatã prin void înseamnã fie multimea vidã, fie o multime neprecizatã.

Tipurile de date simple numite si tipuri primitive (sau tipuri standard) se referã la multimi de elemen
precum: numere întregi, numere rationale, valori de adevãr (logice sau booleene), caractere, valor
apartinând unei enumerãri sau unui interval (subdomeniu). O parte dintre tipurile simple sunt tipur
ordinale, adicã tipuri caracterizate printr-o multime finitã de valori, pe care este definitã o ordine liniarã si,
prin urmare, pentru orice element al unei asemenea multimi se stabileste numãrul de ordine ord(.),
elementul predecesor pred(.) si cel succesor succ(.). Tipurile ordinale sunt cele care se referã la multi
precum: multimea numerelor întregi, multimea valorilor de adevãr, multimea caracterelor, multime
valorilor unei enumerãri, multimea valorilor dintr-un subdomeniu al uneia dintre multimile anterioa
Tipurile rationale (simplã precizie, dublã precizie, precizie extinsã etc.) nu sunt considerate tipuri ordinal
desi sunt tot multimi finite de elemente. Trebuie observat cã metoda de reprezentare în memor
calculatorului a numerelor rationale ar permite considerarea unei ordini liniare si, elementele unei astfel de
multimi ar avea un numãr de ordine.

4 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Tipurile întregi ale limbajului Pascal sunt :

a) Tipul Byte : reprezintã multimea numerelor întregi fãrã semn începând de la 0 pânã la 255, reprezen
intern folosind 8 biti (un byte).

b) Tipul întreg scurt Shortint : reprezintã multimea numerelor întregi cu semn începând de la -128 pânã
127, reprezentate în complement fatã de doi, pe 8 biti.

c) Tipul întreg Integer : se referã la domeniul de valori dintre -32768 si 32767, reprezentate pe 16
complement fatã de doi.

d) Tipul Word : reprezintã multimea numerelor naturale de la 0 la 65535 reprezentate pe 16 biti.

5) Tipul întreg lung Longint : defineste un domeniu reprezentabil, cu semn, pe 32 de biti, în complement
fatã de doi.

Tipuri întregi ale limbajului Java sunt:

a) Tipul byte : este echivalent cu tipul Shortint al limbajului Pascal.

b) Tipul short (întreg scurt): este acelasi cu tipul integer al limbajului Pascal.

c) Tipul int (întreg): corespunde tipului Longint al limbajului Pascal.

d) Tipul întreg lung (long): reprezintã multimea numerelor întregi, reprezentabile cu semn în complemen
fatã de doi, pe 8 bytes adicã 64 de biti.

Tipurile de numere rationale ale limbajului Pascal sunt desemnate prin identificatorii standard real (6 bytes),
single (4 bytes), double (8 bytes), extended (10 bytes) si comp (8 bytes) si descriu submultimi de num
rationale reprezentate în memoria internã în virgulã mobilã. Tipul de date comp este o multime de num
întregi utilizate în calcule fãrã parte fractionarã.

Tipurile de numere rationale ale limbajului Java se mai numesc tipuri flotante. Sunt disponibile multimile
float (4 bytes) si double (pe 8 bytes). Ca si pentru reprezentãrile single, double, extended si comp al
limbajului Pascal, în cazul tipurilor float si double se utilizeazã standardul IEEE 754.

Tipul boolean
este folosit pentru descrierea multimii valorilor de adevãr desemnate prin literalii true si false. Pen
declararea unei variabile de tip boolean în limbajele Pascal si Java se foloseste cuvântul boolean. În
versiunea 7.0 a limbajului Turbo Pascal au fost introduse încã trei tipuri booleene: bytebool, wordbo
longbool. Lungimea reprezentãrii este: boolean - 8 biti, bytebool - 8 biti, wordbool - 16 biti, longbool - 32
biti. Referitor la tipul boolean, în Pascal, sunt adevãrate: false < true, ord(false) = 0, ord(true) =1,
succ(false) = true, pred(true) = false.

Limbajul C++ nu are un cuvânt rezervat pentru variabile logice. Totusi, limbajul permite utilizare
operatiilor uzuale ale calculului cu propozitii: si, sau, negatia prin intermediul operatorilor: &&, ||,
Limbajul trateazã orice valoare nenulã drept true si valoarea zero drept false. Valoarea rezultatã în urm
unei operatii logice este 1 pentru rezultat true si 0 pentru rezultat false.

Pentru declararea variabilelor de tip caracter se utilizeazã cuvântul char. O variabilã de tip caracter poate
avea ca valori coduri Unicode (pe 16 biti, în Java) sau coduri ASCII (pe 8 biti, în Pascal, C, etc.).
caracterelor fiind ordonatã, au sens functiile: ord, pred si succ. Functia ord(.) întoarce codul caracteru
dintre paranteze. O altã functie utilizatã este chr, care transformã o valoare întreagã într-un caracter c
codul Unicode corespunzãtor. Caracterele pot fi comparate între ele pe baza pozitiei lor în setul de
caractere Unicode.

5 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Tipul enumerare
este reprezentat printr-o multime finitã de identificatori separati prin virgule si inclusi între pa
Componentele acestui tip se considerã ordonate, deci se pot aplica functiile: pred, succ si ord. De asemenea
se pot realiza comparatii între elemente. În limbajul Pascal, enumerarea (R, G, B) poate fi utilizatã pentru a
introduce tipul RGB, iar ord(R) = 0, pred(B) = G, R<G, etc. În limbajul C, valorile asociate identificatorilor
pot fi sub controlul total al programatorului, precum în exemplul: enum {v1 = -100, v2 = 5, v3 = 7, v4 = -10
} v; permitând astfel o nouã metodã de definire a constantelor. Unii identificatori pot fi initializati de cãtre
programator urmând ca ceilalti sã primeascã valori în urma compilãrii. În descrierea enum {a, b = 6, c, d}
x; vom avea a = 0, b = 6, c = 7, d = 8.

Componentele de tip enumerare nu pot fi citite de la un mediu de intrare si nici afisate deoarece este
retinutã numai pozitia lor în enumerare. Un identificator prezent într-o listã nu poate fi prezent si într-o
altã listã.

Exemple (Pascal):
type A = (mat, fiz, chim, bio, inf);
B = (ian, feb, mar, apr, mai, iun, iul, aug, sep, oct, nov, dec);

Exemple (C):
typedef
enum {mat, fiz, chim, inf} A;
enum {r, g, b} culoare;

Un subdomeniu este definit ca un interval de valori ale unui tip ordinal, numit tip de bazã. Este suficient sã
se precizeze valoarea initialã si valoarea finalã. De exemplu, subdomeniul 6..12 descrie secventa de numere:
6, 7, 8, 9, 10, 11, 12. Functia ORD (în limbajul Pascal) aplicatã unui element dintr-un interval furniz
numãrul de ordine al elementului considerat ca apartinând tipului de bazã. Reprezentarea internã
variabilelor de tip subdomeniu se în aceleasi conditii ca reprezentarea variabilelor tipului de bazã.

Exemple (Pascal):
type culori = (red, green, blue, yellow, black);
rgb = red..blue;
Mint = 1..100;

Nu se pot defini subdomenii ale tipurilor rationale si nici ale tipurilor structurate, referintã etc.

Pentru tipurile de date descrise mai sus existã operatii predefinite desemnate prin operatori si fun
predefinite. De cele mai multe ori, operatorii sunt binari. Existã însã si operatori unari. Unii dintre
operatori sunt extinsi pentru a actiona si asupra datelor structurate.

Tipurile de date structurate sunt agregãri ale unor tipuri de date deja definite. Limbajele de program
actuale permit definirea urmãtoarelor tipuri structurate: tablou, sir de caractere, înregistrare, multime,
fisier si obiect sau clasã. Tipurile fisier vor fi introduse în 4.7, iar conceptele fundamentale privi
programarea orientatã spre obiecte (definirea claselor) vor fi prezentate în alta parte.

Tipul tablou este implementat diferit de la limbaj la limbaj. Vom exemplifica modurile de definire a acestu
tip în cazul limbajului Pascal. Modul de utilizare a tablourilor în limbajul C va fi studiat altundeva.

Fie T un tip de date oarecare numit tip de bazã si I un tip ordinal cu exceptia tipurilor longint sa
subdomeniu al acestuia. Prin tip de date tablou cu indici din I si elemente din T se întelege multimea
tuturor functiilor x definite pe I cu valori în multimea T. Un tip tablou poate fi introdus prin declaratia:

type <identificator> = array [<tip indice> {,<tip indice>}] of <tip element>;

6 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

unde [ si ] sunt elemente ale limbajului Pascal, iar { si } sunt elemente ale metalimbajului, <tip indice> {,
<tip indice>} descrie multimea I, iar <tip element> descrie multimea T din definitie. Multimea I se poate
obtine ca produsul cartezian al unui numãr oarecare, dar finit de multimi de tip ordinal (fãrã longint), dar
zona din memoria internã utilizatã pentru stocarea elementelor tabloului nu trebuie sã depãseascã o
anumitã dimensiune, dependentã de implementare. Multimea T este orice tip de date cu exceptia tipului
fisier.

Exemple:
type a = array [1..10] of integer;
b = array [-5..5, -10..7] of real;
T = (r, g, b);
c = array [T] of char;
d = array [1..10] of array[-5..5] of array[char] of integer;

Referirea unui element al unui tablou se prin identificatorul tabloului si indexul elementului scris în
paranteze drepte: x['a'] dacã x este un tablou cu <tip indice> = char. Dacã un tablou este multi-dimensional,
referirea la o componentã se poate în mai multe moduri. De exemplu, dacã x este un tablou bidimensio
atunci x[i,j] si x[i][j] reprezintã acelasi element.

Limbajul Borland Pascal permite definirea unui tip numit sir de caractere (string). Lungimea sirurilor est
cel putin 0 (null) si cel mult 255. Din punct de vedere al reprezentãrii interne, pentru un sir de caractere
alocã n+1 bytes (în conventia ASCII pe 8 biti), unde n este lungimea efectivã a sirului. Octetul cu adre
relativã zero este rezervat pentru memorarea lungimii efective. Declararea unui tip sir de caracter se
supune regulii:
type identificator = string[lungime_maxima] | string;

unde <lungime_maximã> stabileste limita superioarã a numãrului de caractere ce pot fi stocate; c


parantezele drepte si aceastã limitã lipsesc se considerã siruri de lungime maximã 255. Un caracter din sir
este accesat similar ca elementul unui tablou, lungimea efectivã a sirului x este obtinutã fie prin ord(x[0])
sau prin length(x).

Exemplu:
Definitia Type T30 = string[30]; introduce T30 ca fiind multimea sirurilor de caractere cu cel mult
caractere.

Tipul de date înregistrare (record) se introduce în Pascal prin:

type <identificator> = <tip record>; unde <tip record > este definit prin urmãtoarele reguli BNF:

<tip record> ::= record <listã de câmpuri> [;]end

<listã de câmpuri> ::= <parte fixã> [; <parte variante>] | <parte variante>

<parte fixã> ::= <sectiune record> {; <sectiune record> }

<sectiune record> ::= <identificator>{, <identificator>}: <tip>

<parte variante> ::= case[ <identificator>:] <tip> of <variantã> {; <variantã>}

<variantã> ::= <constantã> {, <constantã>} :[<listã de câmpuri>] [;])

adicã un element de tip record este în general format dintr-o parte fixã si una variabilã, fiecare dintre
acestea fiind alcãtuitã din câmpuri.

Exemple:

7 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

1) Tipuri de date predefinite în Pascal:

const maxim = 100000;{constanta este de tip longint}

pi = 3.14159;

mint:integer :=maxint-1; {o expresie constanta}

pi2 = pi / 2; {o alta expresie constanta}

stop:char = 'Z';

type T1 = 0..maxint; { subdomeniu al tipului integer; maxint este constanta predefinita 32767}

const st:T1 = 100;

var x,y:T1; {x, y sunt variabile de tip T1}

a, b : real; { a, b sunt variabile de tip real}

flag, poz: boolean; {flag, poz sunt variabile logice}

ch: char;

i,j,k: integer; wi, wj, wk: word;

li, lj,lk:longint;

u:single; v:double; w:extended; {tipuri flotante - standardul IEEE 754}

2) Tipuri de date structurate în Pascal:

Type Data = record

ziua: 1..31;

luna: 1..12;

anul: 1..9999

end;

Figura = (triunghi, patrulater, cerc, elipsa);

Stare = array [Figura] of boolean;

Rvariante = record

{parte fixa}

cod:byte;

nume: string[30];

dataNasterii: Data;

{parte variabila}

8 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

case studii : (medii, superioare) of

medii:(NrClase:byte; Scoala:string[30];);

superioare: (Facultatea:string[20]; specializarea: string[15])

end; {un singur end}

Var d:Data; f: Figura; S: Stare; R: Rvariante;

{Constante denumite impropriu constante cu tip, de fapt sunt variabile initializate}

const d1:Data =(ziua:30; luna:5; anul:1999);

d2:Figura = cerc;

d3: Stare = (true, true, false, false);

d4:Rvariante = (cod:123;

nume:'Ionescu';

dataNasterii: (ziua:12; luna:8; anul:2000);

studii:medii;

Nrclase:12;

Scoala:'Liceul XXXX');

Un identificator de câmp trebuie sã fie unic numai în înregistrarea unde a fost definit. Un câmp al u
variabile de tip record este referit prin identificatorul variabilei si identificatorul câmpului separate
printr-un punct. Exemplu: R.cod, R.nume, R.dataNasterii.ziua, R.studii, R.Nrclase, R.Scoala, d.anul etc.

Tipul multime (prezent în Pascal, Modula etc.) permite definirea multimilor ale cãror elemente sunt
multimi. Fie T un tip scalar diferit de real si de tipurile flotante. Se numeste tip set cu tipul de bazã T
multimea P(T) formatã din toate submultimile multimii T. Definitia unui tip set se prin:

type <identificator> = set of <Tip>;

unde <Tip> este tipul de bazã. Constructia unui element de tip set urmeazã regulile:

<set> ::= [listã de elemente] | []

<listã de elemente> ::= <element> {, <element>}

<element> ::= <expresie> | <expresie>..<expresie>

cu [ , ] elemente ale limbajului Pascal, |, { si } simboluri ale metalimbajului, iar <expresie> reprezintã o
expresie a cãrei valoare apartine tipului de bazã. Astfel, pentru a ne referi la multimea vidã folosim notatia
[], pentru a definii multimea vocalelor scriem ['a', 'e', 'i', 'o', 'u'], iar pentru a definii primele cinci numere
naturale nenule putem scrie în una din formele: [1, 2, 3, 4, 5], [5, 4, 3, 2, 1], [1..5], [1..3, 4, 5] etc.

Cu variabile de tip set se pot efectua urmãtoarele operatii: + (reuniune), - (diferentã), * (intersectie) ce au
ca rezultat un element de tip set, sau operatii relationale cu rezultat de tip logic: = (egalitate), <= (inclus în),
>= (include pe), <> (diferit). Apartenenta unui element t la o multime A este datã de valoarea de adev
expresiei t in A. Aceastã expresie este adevãratã dacã primul operand - element de tip ordinal - este element

9 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

al operandului al doilea - cu multimea de bazã compatibilã cu t.

Dacã tipul de bazã are n valori, o variabilã de tip set corespunzãtoare tipului de bazã va fi reprezenta
memorie folosind n biti, depusi într-o zonã de memorie contiguã cu lungimea (n div 8) + 1 bytes dacã n nu
este divizibil cu 8, respectiv (n div 8) bytes dacã n este multiplu de 8. Prin urmare tipul set of char
reprezentat pe 32 de bytes.

Operatorii sunt simboluri care specificã operatii efectuate asupra unor variabile sau constante denu
operanzi. Combinatiile valide de operanzi si operatorii reprezintã expresii.

Limbajele de programare oferã o multitudine de operatori: operator de atribuire (simbolizat prin := sau =),
operatori aritmetici unari (utilizarea semnului, incrementare, decrementare), operatori aritmetici b
(adunare, scãdere, înmultire, împãrtire, obtinerea câtului si restului împãrtirii a douã numere între
operatori logici (si, sau, negare), operatori relationali (egal, diferit, mai mic, mai mic sau egal, mai mare,
mai mare sau egal, apartine), operatori la nivel de bit (si, sau, negare, sau exclusiv, deplasare stânga
deplasare dreapta), operatori combinati (în limbajele C, C++ si Java), operatori asupra multimilor
(reuniune, intersectie, diferentã), operatori asupra sirurilor de caractere (concatenare) precum si a
operatori.

Evaluarea expresiilor trebuie sã tinã seama de pozitia parantezelor si de proprietãtile operatorilo


(precedentã, asociativitate, conversii implicite în cazul tipurilor compatibile, conversii explicite). Precedenta
stabileste ordinea de evaluare a operatiilor în cazul expresiilor care contin mai multi operatori diferiti.
Dacã într-o expresie se întâlnesc operatii cu aceeasi precedentã atunci ordinea de evaluare este datã de tipul
asociativitãtii (de la stânga la dreapta sau de la dreapta la stânga). Când într-o expresie apar operati
operanzi de tipuri diferite, înainte de efectuarea operatiei are loc un proces de conversie implicitã (când nu
se semnaleazã explicit si nu apare fenomenul de incompatibiltate) prin care tipul cu cardinalul mai m
promovat cãtre tipul mai bogat (se presupune aici cã natura elementelor celor douã tipuri este aceasi).

3.3. Programare în C
Limbajul C a fost creat la AT & T Bell Laboratories in anul 1972 de Dennis Ritchie. Versiunea stan
limbajului C pana in anul 1988 a fost cea furnizata odata cu sistemul de operare UNIX si descrisa in [14]. In
anul 1983 a inceput redactarea standardului ANSI pentru limbajul C. Standardul ANSI a fost finalizat in
anul 1990.

3.3.1. Structura programelor C

In limbajul C programul este o colectie de module distincte numite functii, organizate in una sau mai m
unitati de translatare. Fiecare unitate de translatare poate fi compilata (analizata lexical si sintactic)
separat. O unitate de translatare trebuie sa contina cel putin o declaratie sau o definitie de functie. Ea
consta din fisierul sursa impreuna cu oricare fisier antet si fisiere sursa incluse prin directiva #include. O
unitate de translatare, prin compilare, conduce la un fisier obiect (.obj) relocabil.

Directivele precedate de delimitatorul # se numesc directive preprocesor, acestea specificand opera


anterioare procesului de compilare ce sunt efectuate de o componenta a mediului de programare
preprocesor.

O declaratie C specifica atributele unui identificator sau multime de identificatori. Regulile sintactice ce
stau la baza scrierii declaratiilor sunt redate prin:

<declaratie> ::= <specificator declaratie>

[ <lista declaratori de initializare> ] ;

10 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

<specificator declaratie> ::=

<clasa de memorare> [ <specificator declaratie> ] |

<specificator tip> [ <specificator declaratie> ] |

<calificator tip> [ <specificator declara#ie> ]

<lista declaratori de initializate> ::= < declarator initializare> |

<lista declaratori initializare>, <declarator initializare>

<declarator initializare> ::= <declarator> |

<declarator> = <initializare>

A face o declaratie nu presupune si alocarea memoriei pentru indentificatorul declarat. Exista situati
alocarea se realizeaza in alta unitate de translatare (cazul datelor externe).

Declaratia unui identificator asociaza numelui in mod explicit sau implicit o serie de atribute din m
urmatoare:

Clasa de memorare
- localizeaza zona de memorie in care este plasat elementul declarat (zona de date, un registru al
procesorului, stiva mediului de programare, zona de alocare dinamica) si delimiteaza durata alocarii
(intreg timpul de executare a programului, executarea unei functii sau a unui bloc etc.).

Domeniul numelui
- reprezinta portiunea din program in care poate fi utilizat identificatorul pentru accesarea
informatiei asociate si este determinat de pozitia declaratiei.

Durata de stocare - reprezinta perioada cat elementul asociat exista efectiv in memorie.

Legatura
- indica modul de asociere a unui identificator cu un anumit obiect sau functie, in procesul de editare
a legaturilor.

Tipul datei
(standard sau definit de utilizator) - descrie informatia continuta de elementul definit de identificator.

Clasa de memorare este specificata prin unul dintre cuvintele cheie: typedef, extern, static, auto,
register. Declaratia auto
se poate utiliza pentru variabile temporare - alocate folosind stiva, cu domeniul local. Variabilele declarate
in interiorul unui bloc sunt implicit locale, deci auto este rar utilizat. In limbajul C clasic, o declaratie
register reprezinta un apel la compilator pentru a stoca o variabila int sau char intr-un registru al
procesorului pentru a creste viteza de executare. Versiunile actuale permit specificarea register pentru
orice tip, semnificatia apelului fiind de optimizare a timpului de acces. Specificatorul typedef indica faptul
ca nu se declara o variabila sau functie de un anumit tip, ci se asociaza un nume tipului de date. Sintaxa
este:

typedef <definitie tip> <identificator>;

Specificatorul static
poate sa apara in declaratii locale de variabile pentru a indica durata statica sau in declaratii globale d
functii si de variabile pentru a indica legatura interna. Specificatorul extern este utilizat pentru declaratii

11 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

de functii sau variabile locale sau globale pentru a indica legatura extera si durata statica.

In C (precum si in Pascal), declaratia unei variabile trebuie sa preceada orice referire a ei. Ea poate aparea
in exteriorul oricarei functii, in lista de parametri formali ai unei functii sau la inceputul unui bloc.
Domeniul numelui este regiunea dintr-un program C in care identificatorul este "vizibil". Pozitia
declaratiei determina urmatoarele domenii:

Domeniul bloc - caracterizeaza identificatorii locali (identificatorii declarati in interiorul unui bloc si
au domeniul cuprins intre declaratie si sfarsitul blocului; parametrii formali din definitia unei functii
au ca domeniu blocul functiei).

Domeniul fisier
- caracterizeaza identificatorii declarati in exteriorul oricarei functii - numiti identificatori globali - si
care au domeniul cuprins intre declaratie si sfarsitul fisierului.

Domeniul functie - aplicabil pentru etichetele instructiunilor si este blocul functiei.

Domeniul prototip
- definit pentru identificatorii specificati in lista de parametrii din prototipul unei functii - si care au
domeniul limitat la acel prototip.

Partea din domeniu in care informatia asociata este accesibila se numeste zona de vizibilitate. O declaratie a
unui identificator este vizibila in tot domeniul sau mai putin blocurile sau functiile in care identificatorul
este redeclarat. Pentru identificatorii globali se poate repeta declaratia, dar initializarea trebuie sa se faca o
singura data.

Din punct de vedere al duratei de stocare, sunt posibile trei situatii:

Durata statica:
Obiectele cu durata statica au alocata zona de memorie pe toata durata de executare a programului.
Toate variabilele globale au durata statica. Alte variabile pot avea aceasta calitate prin utilizarea
specificatorilor static sau extern.

Durata locala:
Obiectele cu durata locala sunt cele automatice - spatiul de memorare se aloca (in stiva sau in
registru) la intrarea in executare a blocului sau functiei si este eliberat la iesirea din bloc sau din
functie. In concluzie, orice obiect automatic dispare la incheierea duratei sale de viata, deci informatia
continuta de acesta se pierde.

Durata dinamica:
Pentru obiectele cu durata dinamica, zona de memorie este alocata si eliberata la initiativa
programatorului prin apelarea unor functii C (de exemplu: malloc, free).

Un identificator declarat in diferite domenii, de mai multe ori, sau redeclarat in acelasi domeniu se poat
referi la acelasi obiect sau functie prin procesul numit legare. Legarea poate fi interna, externa sau unic
Daca un identificator are domeniul fisier si clasa de memorare static, el se supune legarii interne. Daca un
identificator are clasa de memorare extern, el se supune aceluiasi tip de legare precum orice declarati
vizibila a identificatorului cu domeniu fisier; daca nu exista declaratii vizibile cu domeniul fisier, se supune
implicit legarii externe. Pentru identificatorii cu legatura externa sunt permise mai multe declaratii
referinta, dar trebuie sa existe o singura definitie. Functiile au implicit legatura externa si durata statica.

In regulile sintactice de mai sus, <calificator tip> se refera la modificatorii de acces (const si volatile) care
controleaza modul in care valoarea unei variabile poate fi modificata. O variabila de tip const nu poate fi
modificata in timpul executiei programului. Declaratia volatile specifica faptul ca variabila poate fi
modificata din exteriorul programului sau intr-un mod care nu rezulta explicit prin program (de exempl

12 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

prin utilizarea adresei variabilei).

Specificatorii de tip indica modul de alocare asociat unei variabile sau tipul rezultatului unei functii. In
exista urmatoarele categorii de tipuri: tipuri de functii, tipuri de variabile si tipul void. Variabilele pot fi de
tip scalar, de tip structurat sau de tip uniune. Tipurile scalare sunt tipuri aritmetice si tipul pointer .
Tipurile structurate cuprind tablourile si inregistrarile (numite in C, structuri). In categoria tipuri
aritmetice intra multimile de elemente specificate prin cuvintele cheie: char, int, float, double; extinse cu
ajutorul modificatorilor de tip: signed, unsigned, short, long. Tot tip aritmetic este considerat a fi si
tipul obtinut prin enumerare.

Dimensiunea zonei de memorie ocupata de un tip sau de o variabila se poate afla prin intermediu
operatorului sizeof cu sintaxa sizeof (<tip>) sizeof <expresie>.

Tipul void indica absenta oricarei valori si este utilizat in urmatoarele situatii: declaratia unei functii fara
parametrii sau fara rezultat, tipul pointer generic si conversii de tip pentru pointeri.

Literalii sunt si ei afectati de existenta modificatorilor de tip prin indicarea unui sufix (U, u, L, l, f, F).
Efectul sufixului asociat unui literal intreg este ilustrat prin situatiile: U sau u - unsigned int sau
unsigned long int (in functie de valoare); L sau l - long int sau unsigned long int (in functie de
valoare); UL, ul, Ul, uL - unsigned long int. Un literal de tip numar zecimal, este automat de tip double;
daca se utilizeaza sufixul F sau f va fi considerat de tip float, iar daca se utilizeaza sufixul L sau l, va fi
considerat de tip long double.

Tabloul este o lista de elemente de acelasi tip plasate succesiv intr-o zona contigua de memorie. Nu exist
limita pentru numarul dimensiunilor tabloului.

Structura este o colectie de date eterogene (corespunde tipului record din limbajul Pascal). O declaratie de
structura precizeaza identificatorii si tipurile elementelor componente si constituie o definitie a unui tip d
date nou. Acestui tip i se poate asocia un nume. In cazul general, sintaxa declaratiei unei structuri este:

<declaratie structura> ::=

struct < id _tip> {

<tip _camp _1> <id _camp _1>;

<tip _camp _2> <id _camp _2>;

...

<tip _camp _i> <id _camp _i>;

...

<tip _camp _n> <id _camp _n>;

} <lista identificatori de tip struct>;

in care:

struct
- este cuvant cheie pentru construirea unui tip inregistrare;

<id_tip> - este un identificator ce desemneaza numele tipului structura ce este declarat;

<tip_camp_i> - tipul campului i;

13 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

<id_camp_i> - identificatorul campului i (campurile structurii se mai numesc si membrii structurii);

<lista identificatori de tip struct> - lista identificatorilor declarati.

Daca numele tipului <id_tip>


lipseste, structura se numeste anonima. Daca lista identificatorilor declarati lipseste, s-a definit doar noul
tip structura. Cel putin una dintre aceste specificatii trebuie sa existe. Daca <id_tip> este prezent, ulterior,
se pot declara noi variabile de tip structura prin intermediul declaratiei:

struct <id_tip> <lista noilor identificatori>;

Referirea unui membru al unei variabile de tip structura se face folosind operatorul de selectie (.) Int
expresie care precizeaza identificatorul variabilei si al campului.

Structurarea datelor la nivel de bit este posibila in limbajul C prin definirea de campuri de biti. Ace
facilitate este utila pentru scrierea aplicatiilor de control al dispozitivelor fizice s.a. Campurile de biti se pot
declara ca membrii ai unei structuri astfel:

struct <id_tip> {

<tip_ camp_ 1> <id_camp_1>:lungime _1;

<tip_camp_ 2> <id_camp _2>:lungime_ 2;

...

<tip_camp_i> <id _camp_ i>:lungime_i;

...

<tip_ camp_n> <id_ camp_n>:lungime_n;

} <lista identificatori de tip struct>;

Totusi, pentru c|mpurile de biti, < tip_ camp_i> poate fi doar int, signed sau unsigned, lungime _i este o
constanta intreaga cu valoarea in domeniul 0-15.

In exemplul:

struct s _bit {

unsigned a:1;

unsigned b:3;

unsigned :4;

unsigned c:3;

unsigned d:2;

} s;

pentru variabila s se vor aloca 16 biti (numerotati 0-15), ce pot fi accesati prin: s.a (bitul 0); s.b (bitii 1-3);
s.c (bitii 8-10); s.d (bitii 11,12). Observam ca bitii 4-7 nu pot fi accesati, pentru ei nu s-a specificat nici un
identificator de camp.

14 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Alocarea campurilor poate ridica probleme de portabilitate, deoarece organizarea memoriei depinde
sistemul de calcul.

Uniunile
sunt entitati care pot contine (la momente de timp diferite) obiecte de tipuri diferite. Practic, mai mu
variabile sunt suprapuse in acelasi spatiu de memorie. Sintaxa declaratiei este similara cu cea a structurii
dar identificatorii declarati ca membrii reprezinta numele cu care sunt referite diferitele tipuri de variabile
ce ocupa aceeasi zona de memorie:

<declaratie uniune> ::=

union <id_tip> {

<tip_var_ 1> <id_var_1>;

<tip_ var_2> <id_ var_2>;

...

<tip_ var_i> <id _var_i>;

...

<tip_ var_ n> <id_ var_n>;

} <lista identificatori de tip union>;

Spatiul alocat in memorie corespunde tipului cu dimensiune maxima. Tipurile uniune sunt utile pen
conversii de date, in implementarea programelor de comunicatie etc.

Tipul enumerare
consta dintr-un ansamblu de constante intregi (cel putin un element), fiecare fiind asociata cate
identificator. Constanta unui element al enumerarii este fie asociata implicit, fie explicit. Implicit, pri
element are asociata valoarea 0, iar pentru restul este valoarea _precedenta+1.

Cel mai simplu program C este constituit din directive preprocesor, declaratii globale si functii. Printr
functii trebuie sa existe una cu numele "main
" cu care va incepe executarea programului. Chiar daca programul este organizat pe mai multe fisiere
sursa, numai intr-un singur fisier, numai o singura functie poate purta numele "main". Celelalte functii
sunt subprograme definite de programator sau functii din biblioteca de subprograme. Limbajul C nu
contine functii predefinite cum sunt cele din unitatea System a mediului Borland Pascal.

Functiile din bibliotecile C sunt declarate impreuna cu constantele, tipurile si variabilele globale asociate, in
fisiere antet, cu extensia ".h", situate in subarborele include al arborelui asociat mediului de programare.
Operatiile de intrare-iesire necesita specificarea fisierului stdio.h, incadrat de delimitatoriii < si >, intr-o
directiv{ # include. Fisierele antet ale programatorului vor fi incadrate folosind delimitatorul ".

O functie C are structura:

<tip_ rezultat> <id_functie> (<lista _parametri_ formali>){

declaratii_locale

secventa_instructiuni

15 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

unde <tip_ rezultat> indica tipul rezultatului returnat de functie, <id _functie> reprezinta numele
(identificatorul) functiei, iar <lista_parametri_ formali> consta in enumerarea declaratiilor parametrilor
functiei sub forma:

<tip_ parametru> <id_ parametru> [ ,<tip_parametru> <id _parametru>]

Acoladele { }
sunt delimitatori ce incadreaza o instructiune compusa (bloc) alcatuita din declaratii si instructiuni.

Secventa de instructiuni a functiilor pentru care <tip _rezultat> este diferit de tipul void, trebuie sa contina
o instructiune return, cu sintaxa generala:

return <expresie>

Rezultatul functiei este valoarea expresiei.

Functia main poate avea parametri si poate intoarce un rezultat. In exemplele ce urmeaza functia main nu
va avea parametri si nu va intoarce nici un rezultat.

Exemplul 3.3.1. (Program C pentru implementarea metodei bisectiei)

/* declaratii pentru functiile din biblioteci */

# include <stdio.h> /* biblioteca functiilor de intrare/iesire */

# include <math.h> /* biblioteca necesara pentru functia abs */

/* declaratii macrodefinitii: Preprocesorul inlocuieste in tot textul sursa, partea stanga (epsilon, pi) cu sirul
din dreapta. O conventie uzuala este folosirea literelor mari pentru identificatori, pentru a usu
recunoasterea lor in program. Sirul se termina cu linie noua. */

# define EPSILON 1E-7

# define PI 3.1415926

/* prototipuri ale functiilor definite in program */

float f(float);

float bisectie( float, float );

/* definitii ale functiilor */

float f( float x){

return (x-1)*(x-2)*(x-PI)*(x-2*PI);

float bisectie(float a, float b){

float c, fc;

int sfa;

sfa = (f(a) < 0.0);

16 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

do {

c = (a+b)/2;

fc = f(c);

if ((fc<0) == sfa) a=c; else b=c;

} while (fabs(b-a) >= EPSILON && fabs(fc) <= EPSILON);

return c;

/* functia main */

void main (void){

float a,b;

printf("\ n");

do {

printf("Introduceti a:"); scanf("%f",&a);

printf("Introduceti b:"); scanf("%f",&b);

} while (f(a)*f(b) >= 0);

printf("Radacina ecuatiei este: %15.8f \ n",bisectie(a,b));

Exemplul 3.3.2.
(Ridicarea la putere a unui numar complex dat sub forma algebrica se poate face cu ajutorul conversiei in
forma trigonometrica si al utilizarii formulei lui Moivre). Se solicita cititorului scrierea unei functii main
pentru folosirea functiilor definite in cadrul acestui exemplu.

#include <stdlib.h> /* pentru iabs */


#include <math.h> /* pentru sqrt, atan2, sin, cos etc. */
typedef struct {float mod; float arg;}F_TRIG;
typedef struct {float re; float im;} F_ALG;
float z_power(float x, int n){
float p=1.0; int m;
m = iabs(n);
if (m == 0) return 1.0; else {
while (m--) p *=x;
}
if (n<0) return 1.0/p; else return p;
}
F_TRIG cnv_trig(F_ALG t) {
F_TRIG s;
s.mod = sqrt(t.re*t.re+t.im*t.im);
s.arg = atan2(t.im, t.re);
return s;
}
F_ARG cnv_alg (F_TRIG s){

17 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

F_ALG t ;
t.re = s.mod * cos (s.arg);
t.im = s.mod *sin(s.arg);
return t;
}
F_ALG c_power(F_ALG z, int n) {
F_TRIG s = cnv_trig(z);
s.mod:=int_power(s.mod, n);
s.arg *= n;
return cnv_alg(s);}

In exemplele de mai sus am folosit functiile printf si scanf. De asemenea am folosit mai multi operatori.
Acestea vor fi prezentate in urmatoarele subsectiuni.

3.3.2. Functiile de intrare-iesire pentru consola

Consola sau dispozitivul standard de intrare-iesire reprezentate de tastatura (zona de date - stdin ) si ecran
(zonele de date - stdout si stderr) permit utilizatorului interactiunea cu programul aflat in executare.
posibile operatii de citire/scriere fara formatare si operatii de citire/scriere cu formatare.

Operatii de citire/scriere fara formatare. Acestea permit lucrul cu caractere (char ) sau cu siruri de
caractere (* char).

Pentru citirea unui caracter din stdin pot fi utilizate functiile: int getchar(void), int getche(void ) si int
getch( void), ultimele doua variante nefiind prevazute de standardul ANSI, dar sunt prezente in vers
Borland (fisierul antet conio.h). Functia getchar intoarce primul caracter din stdin , care corespunde
primei taste apasate, dar numai dupa apasarea tastei Enter. Caracterul este transformat in intreg fara
semn. In cazul unei erori sau la intalnirea combinatiei EOF (sfarsit de fisier) functia intoarce valoa
(codificata prin EOF).

Functia getche
asteapta apasarea unei taste si intoarce caracterul corespunzator pe care il afiseaza pe ecran (nu e nevoie de
Enter ). Functia getch este similara cu getche(), dar nu afiseaza ecoul pe ecran.

Pentru scrierea unui caracter la stdout se utilizeaza functia int putchar (int c) care afiseaza pe ecran
caracterul cu codul ASCII c. Daca operatia reuseste, intoarce caracterul afisat, iar in caz de esec valoare
EOF (-1).

Pentru citirea (resp. scrierea) sirurilor de caractere se lucreaza cu functia gets (respectiv puts). Functia cu
prototipul char *gets (char *s) citeste caractere din stdin si le depune in zona de date de la adresa s, pana
la apasarea tastei Enter. In sir, tastei Enter
ii va corespunde caracterul '\0'. Daca operatia reuseste, functia intoarce adresa sirului, altfel valoarea
NULL ( = 0 ). Functia cu prototipul int puts( const char *s) afiseaza pe ecran sirul de la adresa s sau o
constanta sir de caractere (secventa de caractere intre ghilimele) si apoi trece la linie noua. La succes,
functia intoarce ultimul caracter, altfel valoarea EOF.

Operatii de citire/scriere cu formatare.


La citire, formatarea specifica conversia datelor de la reprezentarea externa in reprezentarea binara.
Pentru operatia ce scriere se efectueaza conversia inversa.

Pentru citirea datelor se utilizeaza functia scanf cu prototipul:

int scanf( const char * format [ , lista_adrese_ variabile] );

iar pentru scrierea datelor se utilizeaza functia printf cu prototipul:

int printf( const char *format, lista_valori);

18 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Sirul de caractere format poate contine in general:

I. specificatori de format: siruri precedate de caracterul '%' care descriu fiecare camp asteptat;

II. caractere de spatiere: spatiu (' '), tab ('\t'), linie noua ('\n');

III. orice alt caracter Unicode.

Fiecarei variabile din lista ii corespunde o specificatie de format (tipul I.). Functia scanf intoarce numarul
de campuri citite si depuse la adresele din lista. Daca nu s-a stocat nici o valoare, functia intoarce valoarea
0. Functia printf intoarce numarul de octeti transferati sau EOF in caz de esec.

Functia scanf citeste succesiv caractere din stdin pe care le interpreteaza prin compararea succesiva a
caracterului citit cu informatia curenta din sirul format. Prezenta unui caracter de tip II determina citire
fara memorare a secventei pana la intalnirea unui caracter de tip I sau III. Prezenta unui caracter de tip III
determina citirea fara stocare a caracterului curent de la tastatura, daca este identic.

La scriere, caracterele de tip II si III se afiseaza pe ecran asa cum apar in sirul format. Forma generala a
unui descriptor pentru scriere este:

% [ flags] [ width] [ .prec] [ lmod] type

specificatiile dintre [ si ] fiind optionale. Elementele de mai sus au urmatoarea semnificatie:

flags - poate fi unul dintre semnele: +, -, 0, spatiu, #. Semnele au urmatoarea semnificatie:

- : aliniere la stanga a argumentului in cadrul campului;

+ : numerele vor fi obligatoriu tiparite cu semn;

0 : indica completarea la stanga cu zerouri (la numere);

spatiu: daca primul caracter nu e semnul, se va afisa un spatiu;

width: este un numar care specifica latimea minima a campului. Argumentul corespunzator va fi afisat pe
un camp cu latime cel putin width. Daca sunt mai putine caractere de scris, se va completa campul cu spatii
la stanga (implicit) sau la dreapta, daca s-a specificat flagul - . Daca s-a specificat flagul 0, se va completa la
stanga cu zero. Daca width
este caracterul *, atunci latimea este data de urmatorul argument din lista (trebuie sa fie neaparat un int).

prec: este un numar care specifica precizia de scriere; pentru %s prec indica numarul maxim de caractere
ce se va scrie; pentru %e, %E si %f prec indica numarul de zecimale; pentru %g si %G prec indica
numarul de cifre semnificative, iar la descriptorii pentru intregi indica numarul minim de cifre. Daca prec
este *, atunci se considera ca latimea de scriere este data de urmatorul argument din lista, care trebuie sa
fie de tip int.

lmod: este un specificator de lungime care corespunde unui argument short sau unsigned short (h), long
sau unsigned long (l), respectiv long double (L).

type: este descriptorul propriu-zis. Se utilizeaza urmatoarele caractere: d, i (int ) - notatie zecimala cu
semn; 0 (int ) - notatie in baza 16 fara semn; x, X (int ) - notatie in baza 16 fara semn cu abcdef pentr x si
ABCDEF pentru X; u (int ) - notatie zecimala fara semn; c (int ) - un caracter; s (char *) - sir de caractere
terminat cu '\0' ; f (double ) - numarul in virgula mobila cu format standard; e, E (double ) - numarul in
virgula mobila cu format exponential; g, G (double ) - in loc de f, e, E; p (void *) - se tipareste argumentul
ca adresa; % - se tipareste %.

19 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Forma generala a unui descriptor pentru citire este:

% [ *] [ width] [ lmod] type

unde:

* - suprima atribuirea urmatorului camp din stdin la urmatoarea variabila;

width, lmod - ca mai sus;

type - descrie tipul de conversie. Cele mai importante specificatii de conversie sunt: d (int *) - intreg
zecimal; i (int *) - intreg oarecare (zecimal, octal sau hexa); o (int *) - intreg octal; u (unsigned int *) -
intreg zecimal fara semn; x (int *) - intreg hexa, c (char *) - caractere; s (char *) - sir de caractere (se va
incheia cu '\0 '); e, f, g (float *) - numere in virgula mobila; p (void *) - valoarea unei adrese asa cum e
tiparita de printf.

In descrierea de mai sus, intre paranteze se indica tipul argumentului supus operatiei de intrare-iesire
Notatia tip * inseamna adresa unei locatii de tipul tip.

3.3.3. Operatori si expresii

Operatorii sunt simboluri care descriu operatii efectuate asupra unor variabile sau constante (numite
generic operanzi). O combinatie corecta de operatori, variabile, constante, apeluri de functii reprezin
expresie. Pentru constructia expresiilor, limbajul C ofera o gama foarte larga de operatori.

Operatorul de atribuire. Operatorul de atribuire (=) permite crearea unei expresii de forma:

<variabila> = <expresie>

ce se evalueaza de la dreapta la stanga. Dupa evaluarea membrului drept, valoarea rezultata este inscrisa in
<variabila>, iar intreaga constructie are valoarea variabilei dupa inscriere.

Operatori aritmetici.
Operatorii aritmetici sunt: + (adunare), - (scadere), * (inmultire), / (impartire), % (impartire mo
impartitor). Ordinea operatiilor este cea binecunoscuta, dar se pot utiliza paranteze pentru schimbare
ordinii operatiilor. Pentru scrierea instructiunii de atribuire <variabila> = <variabila> + 1; se poate uti
forma prescurtata <variabila>++, operatorul ++ fiind numit operator de incrementare. Exista, de asemenea,
si un operator de decrementare (--): <variabila>--; ce este echivalentul instructiunii: <variabila>
<variabila> - 1;

Operatori logici si relationali. Pentru scrierea expressilor booleene se utilizeaza operatorii logici si operatorii
relationali. Exista trei operatori logici: || (SAU logic - SAU INCLUSIV), && (SI logic), ! (NU logic)
Operatorii relationali intalniti in limbajul C sunt urmatorii: < (mai mic strict), > (mai mare strict), <= (m
mic sau egal), >= (mai mare sau egal), == (egal cu), != (diferit de). Ori de cate ori relatia este falsa s
genereaza valoarea 0, valoarea 1 fiind generata atunci cand relatia este adevarata. Trebuie evidenti
operatorii aritmetici au prioritate fata de operatorii relationali.

Operatori la nivel de bit. Operatorii la nivel de bit se pot aplica operanzilor de tip intreg (char, int, short,
long , cu sau fara semn): & (SI logic la nivel de bit),  (SAU logic la nivel de bit), ^ (SAU exclusiv la nivel
de bit), << (deplasare stanga), >> (deplasare dreapta) si ∼ (negare la nivel de bit).

Operatori de atribuire combinati. Pentru realizarea atribuirii

<variabila> = <variabila> <operator> <var _sau_const>;

20 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

se pot utiliza operatorii de atribuire combinati: += (atribuire cu adunare), -= (atribuire cu scadere),


(atribuire cu inmultire), /= (atribuire cu impartire), %= (atribuire cu impartire modulo); expresia fiind
scrisa prescurtat:

<variabila> <operator>= <var _sau_const>;

Operatorul virgula.

In limbajul C, virgula (,) este un operator binar, care leaga expresii oarecare. Constructia <expresie_ 1>,
<expresie_2> este una corecta, constand din evaluarea celor doua expresii, in ordinea in care apar, valoarea
intregii constructii fiind data de valoarea lui <expresie_2>. Asocierea operatorului virgula se face de la
stanga la dreapta, astfel incat o expresie de forma e1,e2,e3 este echivalenta cu: (e1, e2), e3.

Exemple:

1) # define Schimba(a,b) (temp=a, a=b, b=temp)

2) for(i=0, j=1; i<n; i+=1, j+=1) printf("%d, %d", i,j);

Operatorul conditional (?:)

Operatorul conditional este o constructie decizionala a limbajului C care are urmatoarea


<Expresie-booleana> ? <expresie_ 1> : <expresie _2>; avand urmatorul inteles: Daca <Expresie-booleana>
este adevarata atunci intreaga expresie conditionala are valoarea <expresie_1>, in caz contrar, valoarea
expresiei conditionale fiind valoarea <expresie_2>.

Exemple:

1) # define Semn(x) ((x<0) ? (-1) : (1))

2) e = (x<0) ? x*x+3 : sqrt(x);

Alti operatori:
In aceasta categorie includem operatorii specifici tipului referinta, operatorii pentru selectarea elemente
unui tip de date structurat, precum si operatorii introdusi de extensia C++.

3.3.4. Instructiuni C

Cea mai simpla instructiune C este instructiunea <expresie>; ce ofera un echivalent in C pentru
urmatoarele instructiuni Pascal: atribuire, apel de procedura, instructiunea vida. O secventa de instructiuni
incadrata de acolade este considerata ca o singura instructiune si este numita instructiune compusa sau
bloc. Spre deosebire de instructiunea compusa a limbajului Pascal, instructiunea compusa din limbajul
poate contine atat declaratii cat si instructiuni, declaratiile fiind pozitionate la inceputul blocului. In
implicit, identificatorii declarati in blocul delimitat de acolade, au ca domeniu de vizibilitate blocul, iar
timpul de viata este limitat la timpul de executare a blocului.

Programarea unei structuri decizionale, in C, poate fi realizata folosind: instructiunea if...else ; operatorul
conditional (?:) si instructiunea switch. Sintaxa instructiunii if...else este:

<instructiune_if> ::=

if ( <Expresie>) <Instructiune _T>; 

if ( <Expresie>) <Instructiune_ T> else <Instructiune_ F>

unde: <Expresie> are o valoare de tip scalar reprezentand o constructie de tip expresie, <Instructiune_ T>

21 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

reprezinta o instructiune C care se va executa cand <Expresie> are o valoare nenula (adevarat),
<Instructiune_ F> reprezinta acea instructiune C ce se va executa pentru valoare 0 (false) a lui <Expresie>.

Conform celor de mai sus, constructia: e1 ? e2 : e3; poate inlocui instructiunea if...else: if (e1) e2; else e3;

Atunci cand o selectie multipla este controlata de valoarea unei singure expresii, se poate utiliza
instructiunea switch , un pseudo-echivalent C a constructiei Pascal case .

Sintaxa instructiunii switch este:

<instructiune_switch> ::= switch ( <expresie>) {

case <const_ 1> : <lista_ instructiuni> [ break;]

case <const_2> : <lista _instructiuni> [ break;]

...

[ default:] <lista_instructiuni> [ break ;]

unde: <expresie> este o o expresie cu valoare intreaga (tip intreg sau enumerare); <const_1>, <const _2>, ...
sunt constante de selectie, cu valori distincte, convertibile la tipul expresiei <expresie>, iar <lista
_instructiuni> este o secventa de instructiuni C.

Fiecare eticheta case indica o singura constanta, dar se pot asocia mai multe etichete case , scrise
consecutiv, pentru aceeasi secventa de instructiuni.

Instructiunea break intrerupe lista de instructiuni si duce la incheierea instructiunii switch . Daca
valoarea expresie nu apare in lista constantelor de selectie, se executa instructiunile asociate etichetei
default , daca exista.

Programarea ciclurilor poate fi realizata folosind instructiunile de ciclare: ciclul cu test initial (instructiunea
while ), ciclul cu test final (instructiunea do...while ) si ciclul cu test initial si contor (instructiunea for ).

Forma instructiunii while este:

while (<expresie>) <instruc#iune>.

]n particular, <instruc#iune> poate fi chiar instruc#iunea vid{.

Sintaxa instruc#iunii do..while este:

do <instruc#iune> while (<expresie>);

Instruc#iunea dintre do
~i while se execut{ cel pu#in o dat{ ~i se repet{ c|t timp <expresie> este compatibil{ cu valoarea log
“adev{rat”.

Instruc#iunea for, ofer{ cea mai compact{ metod{ pentru scrierea ciclurilor cu test ini#ial ~i are o defini#
care }i extinde domeniul de aplicare fa#{ de alte limbaje de programare. Forma instruc#iunii for este:

for ( <expresie_1> ; <expresie_3> ; <expresie_3> ) <instruc#iune>

~i are efectul similar cu al secven#ei:

22 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

<expresie_1>; while (<expresie_2>) { <instruc#iune> <expresie_3>;}

Cele trei expresii dintre paranteze pot fi toate vide, caz }n care avem de-a face cu un ciclu infinit.

]ntreruperea necondi#ionat{
a unei secven#e de instruc#iuni ~i continuarea dintr-un alt punct al programului este posibil{ prin utilizarea
instruc#iunilor de salt: goto (salt la o instruc#iune etichetat{), break (}n contextul instruc#iunii switch c|t
~i }n instruc#iunile de ciclare pentru a determina ie~irea for#at{ din ciclu, indiferent de valoarea condi#iei
de ciclare) ~i continue
(}n cadrul blocului instruc#iunilor de ciclare pentru a }ntrerupe execu#ia itera#iei curente). ]n
instruc#iunilor while ~i do..while, instruc#iunea continue determin{ activarea testului condi#iei de
ciclare, iar pentru instruc#iunea for se va continua cu evaluarea, }n aceast{ ordine, expresiilor
<expresie_3>, <expresie_2>.

Exemplul 3.4.3. (Evaluarea unei func#ii polinomiale date explicit):

# include <stdio.h>

void main (void) {

float t, val;

do {

printf(“\ n Introduce#i valoare lui t:”);

scanf(“%f”, &t);

val = (((5*t+4)*t-2)*t+3)*t-10;

printf(“\ n Rezultatul evalu{rii este: %f”, val);

printf(“Continua#i [ d/n] ?”);

} while (getche() == ‘d’);}

Exemplul 3.4.4.
(O implementare a algoritmului lui Nicomachus - utilizarea sc{derilor repetate - pentru determinarea celui
mare divizor comun a dou{ numere naturale nenule)

# include <stdio.h>

int cmmdc(int, int);

void main(void) {

int u,v;

while (scanf(“%d %d”, &u, &v) != EOF)

if ( (u>0) && (v>0) )

printf(“%d %d %d \ n”, u,v, cmmdc(u,v));

23 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

int cmmdc(int m, int n){

int temp;

do {

if (m<n) {

temp = m; m = n; n = temp;

m = m - n;

} while (m != n);

return(m);

Exemplul 3.4.5.
(Implementarea algoritmului lui Roy Warshall pentru determinarea matricei existen#ei drumurilor pentru u
graf G cu maxim 20 de v|rfuri.) Se noteaz{ cu x matricea de adiacen#{ a grafului (x[ i,j] = 1 dac{ v{rfurile i ~i
j sunt conectate direct, x[ i,j] =0, }n caz contrar). Se va ob#ine matricea y cu elemente: y[ i,j] =1 dac{
v{rfurile i ~i j sunt conectate printr-un drum, y[ i,j] =0, }n caz contrar.

# include <stdio.h>

# define maxlin 20

# define maxcol 20

# define or | |

# define nl \ n

unsigned char x[ maxlin] [ maxcol] , y[ maxlin] [ maxcol] ;

void main(void){ int i,j,n,k;

do { printf(“ nl Introduce#i dimensiunea grafului (cel mult %d):”, maxlin);

scanf(“%d”, &n); } while ((n<1) or (n>maxlin));

printf(“ nl Introduce#i matricea de adiacen#{: nl”);

for (i=0; i<=n-1; i++) for (j=0; j<n; j=j+1) scanf(“%d”, &x[ i] [ j] );

printf(“ nl S-a introdus matricea: nl”);

for (i=0; i<n; i++) {

for (j=0; j<n; j++) { printf(“%d”, x[ i] [ j] ); y[ i] [ j] =x[ i] [ j] ; }

printf(“nl”);

24 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

for (j=0; j<n;j++) for (i=0; i<n; i++)

if (y[ i] [ j] != 0) for (k=0; k<n; k++) y[ i] [ k] = y[ i] [ k] or y[ j] [ k] ;

printf(“nl Matricea existen#ei drumurilor: nl”);

for(i=0; i<n; i++) {

for(j=0; j<n; j++) printf(“%d”, y[ i] [ j] );

printf(“nl”);

Exemplul 3.4.6. (Evaluarea unei func#iei). Se cere evaluarea func#iei urm{toare pentru un n ~i x da#i:

fn(x) := if (n = 1) then else

if (n = 2) then log3(1+| 3x+5| ) else

if (n = 3) then .

# include <stdio.h>

# include <math.h>

void main(void) { int n; float x,v,a,b,c;

do {

printf(“N in [ 1, 2, 3] :”); scanf(“%d”, &n);

} while ((n-1)*(n-2)*(n-3) != 0);

printf(“x = “); scanf(“%f”, &x);

switch (n){

case 1: a=x*x; v=atan((2+a)/(1+a))+atan(3+2*a);

break;

case 2: v=log(1+fabs(3*x+5))/log(3);

break;

case 3: a=exp((x-3)*log(5)); b=x*x*x*x*x; c = a+b+1;

v=exp(log(fabs(c))/5.0); if (c<0) v=-v;

25 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

break;

printf(“\ n N= %d x = %4.2f --> v =%7.3f”, n, x, v);}

3.5. Recursivitate }n limbajele de programare


3.5.1. No#iunea de recursivitate

]n general, prin recursivitate se }n#elege proprietatea intrinsec{ a unei entit{#i (fenomen, proces etc.) de a fi
definit{ ~i/sau analizat{ folosind entit{#i de aceea~i natur{. Un algoritm }n a c{rui descriere este nece
referirea la el }nsu~i se nume~te algoritm recursiv. Aceast{ clas{ de algoritmi este }nt|lnit{ frecvent. Ea face
posibil{ prezentarea unor descrieri simple ~i elegante ale opera#iilor algoritmului.

Iat{ dou{ moduri diferite utilizate pentru a defini n!, unde n este un num{r }ntreg pozitiv. Prima defini#ie
este nerecursiv{, a doua este recursiv{.

“n! este produsul tuturor numerelor }ntregi cuprinse }ntre 1 ~i n inclusiv.”

“Dac{ n=1 atunci n!=1, altfel n! este produsul dintre n ~i (n-1)!.”

Observ|nd c{ }n a doua defini#ie se folose~te aceea~i descriere dar pentru o valoare mai mic{, adic{ n-1, ~i
c{ procedeul poate continua p|n{ la }nt|lnirea valorii 1, putem demonstra prin induc#ie c{ a doua defini#ie
este corect{.

Limbajele de programare moderne ofer{ posibilitatea descrierii ~i utiliz{rii subprogramelor recursive


Printre aceste limbaje g{sim: Pascal, PL/C, Lisp, APL, C, Java precum ~i altele. Ceea ce caracter
subprogram recursiv este faptul c{ se autoapeleaz{, pentru un domeniu restr|ns de valori.

Exemplific{m implementarea defini#iilor de mai sus }n subprograme Pascal. Func#ia fact_nr descrie
algoritmul de calcul nerecursiv, iar func#ia fact_r codific{ defini#ia recursiv{.

Exemplul 3.5.1. (Calculul factorialului)

Program Demonstrativ_Fact;

var eroare: boolean;

function fact_nr(n:integer):integer;

var p, i:integer;

begin

if n<=0 then begin eroare:=true; fact_nr:=-1 end

else begin

eroare:=false; p:=1; for i:=1 to n do p:=p*i;

fact_nr:=p

end

26 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

end;

function fact_r(n:integer):integer;

begin

if n<=0 then begin eroare:=true; fact_r:= -1 end

else if n=1 then begin eroare:=false; fact_r:=1 end

else fact_r:=n*fact_r(n-1)

end;

var x:integer;

begin

eroare:=false;

for x:= -1 to 7 do

if not eroare then writeln(fact_nr(x), ‘ ‘, fact_r(x))

end.

Trebuie s{ observ{m necesitatea testului “n<=0”, omiterea acestuia, pentru numere }ntregi negative,
conduce la continuarea autoapelului p|n{ la blocarea sistemului.

]ntotdeauna, structura global{ a unui subprogram recursiv este:

subprogram Id(lista de variabile);

SEQ

...

If (conditie_de_oprire_a_autoapelului) then SEQ .... END

else SEQ ...;

apeleaz{ ID(lista de variabile - cu valori modificate);

...

END;

...

END

3.5.2. Tipuri de recursivitate

]ntr-un program Pascal de forma p[ ...; q; ...; r; ...] :

program p;

27 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

...
procedure q;

...
begin ... end;

...
procedure r;

...
begin ... end;

...

begin ... end.

subprogramul r poate sa apeleze subprogramul q, dar q nu poate apela r deoarece r nu este }nc{ decla
Pentru aceasta, limbajul Pascal, propune utilizarea directivei forward. ]n declara#ia propriu-zis{ a lui r
care urmeaz{ subprogramului q, se folose~te un antet redus }n care se specific{ doar numele lui r,
parametrii ~i tipuri (similar prototipurilor de func#ii C). Programul P va avea forma p[ ..; r forward; ..; q;
..; r; ..] :

program p;

...

procedure r (var x:integer); forward;

...

procedure q;

...; var t:integer; ...

begin ...; r(t); ... end;

...

procedure r;

...

begin ...; x:=x+1; ... end;

...

begin

...

end.

28 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Referirea lui r }n q este posibil{ ~i f{r{ folosirea directivei forward, prin simpla inversare a ordinei
declara#iilor lui q ~i r }n p. Se ob#ine forma: p[ ...; r; ...; q; ...] . Dac{ at|t q apeleaz{ r c|t ~i r apeleaz{ q,
inversarea nu rezolv{ problema ~i trebuie folosit{ directiva forward. Referirea mutual{ a dou{ sau mai
multe subprograme }n maniera descris{ mai sus, cu folosirea necesar{ a directivei forward, se nume~te
recursie indirect{. Atunci c|nd un subprogram se apeleaz{ nemijlocit pe el }nsu~i spunem c{ recursia este
direct{.

]n limbajul C, introducerea declara#iilor f{r{ defini#ii ale func#iilor (prototipuri), nu numai c{ p


recursivit{#ii indirecte este rezolvat{, dar compilatorul are ~i posibilitatea de a efectua verificarea
validit{#ii apelurilor (num{rul ~i tipul parametrilor) precum ~i eventualele conversii de tip pentru
parametri ~i rezultat. Vom prezenta un exemplu de program C }n care apare fenomenul de recursivitate
Mai multe exemple (subprograme recursive codificate }n C sau Pascal) vor fi introduse }n capitole
urm{toare.

Exemplul 3.5.2.
(Metoda inser#iei binare pentru ordonarea cresc{toare a unui tablou unidimensional cu numere }n virgu
mobil{).
]ncep|nd cu al 2-lea element, se determin{ - prin c{utare binar{ - pozi#ia pe care trebuie s-o ocupe un
element, cunosc|nd numai elementele deja prelucrate, apoi deplaseaz{ anumite elemente pentru a-l depune
la locul potrivit.

# include <stdio.h>

# include <conio.h>

# define max 100

typedef float vector[ max] ;

int n,i,k; vector a;

int poz(int st, int dr, int j) {

/* determin{ pozi#ia elementului a[ j] }n ~irul a[ st] ,..., a[ dr] */

int mijloc;

if (st == dr) if (a[ j] < a[ st] ) return (st); else return (j);

else if (dr-st == 1)

if (a[ j] <a[ dr] ) if (a[ j] >= a[ st] ) return (dr);

else return (st);

else return(j);

else { mijloc = (st+dr)/2;

if (a[ mijloc] <= a[ j] ) return (poz(mijloc, dr, j));

else return (poz(st, mijloc, j));

}}

29 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

void deplasare(int j, int pozi#ie) {

int i, temp;

if (j > pozitie) {

temp = a[ j] ;

for (i=j; i>=pozi#ie+1; i--) a[ i] = a[ i-1] ;

a[ pozi#ie] = temp;

void main(void) {

clrscr(); printf(“n>“); scanf(“%d”, &n);

for (i=0; i<=n-1; i++) { printf(“%d:”, i); scanf(“%f”, &a[ i] );}

for (i=1; i<=n-1; i++) { k=poz(0,i-1,i); deplasare(i,k); }

printf(“Sirul ordonat:\ n”);

for (i=0; i<=n-1; i++) printf(“%5.2f”, a[ i] );

gotoxy(1,25); printf(“Apas{ orice tast{!”); getch();

3.6. Tipul referin#{ }n limbajele de programare


Tipul referin#{ reprezint{ adrese ale unor zone de memorie. Variabilele ce stocheaz{ adrese ale unor zone
de memorie se mai numesc ~i pointeri. Pointerii sunt necesari pentru a permite lucrul cu variabile
dinamice, care pot fi create ~i distruse }n timpul execut{rii unui program. Datorit{ diferen#elor sintactice
}n definirea ~i utilizarea pointerilor, care exist{ }ntre limbajele de programare Pascal ~i C, }n cele ce
urmeaz{ se va discuta mai }nt|i tipul de date referin#{ }n Pascal, apoi declararea ~i opera#iile cu poin
limbajul C.

3.6.1. Tipul referin#{ }n Pascal

]n limbajul Pascal este permis{ utilizarea a dou{ clase de variabile: statice ~i dinamice. Variabilele statice
sunt alocate }n timpul compil{rii, iar locul ocupat de ele }n memorie nu poate fi modificat }n execu#ie; e
exist{ pe durata }ntregii execu#ii a blocului (program, procedur{ sau func#ie). Variabilele statice su
declarate }n sec#iunea VAR.

Variabilele dinamice nu apar }ntr-o declara#ie explicit{ }n sec#iunea VAR, ~i accesul la acestea nu se poate
face direct. Crearea ~i distrugerea variabilelor dinamice se realizeaz{ cu procedurile New ~i Getmem
respectiv Dispose ~i Freemem. Aceste subprograme aloc{, respectiv elibereaz{ spa#iul de memorie pentru
variabile dinamice. Adresa zonei de memorie alocat{ unei variabile dinamice va fi stocat{ }ntr-o variabil{ de
tip special, numit referin#{. Lungimea zonei alocate depinde de tipul variabilei dinamice. De exemplu,
pentru adrese ale locatiilor de tip intreg se aloca 2 bytes, pentru locatii care s{ stocheze numere }n virg

30 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

mobil{ dubl{ precizie (double) se aloc{ 8 bytes. Spa#iul de memorie supus aloc{rii/eliber{rii dinamice
nume~te “HEAP”.

Definirea unui tip referin#{ se poate face }n sec#iunea type, astfel:

type PT = ^ T;

unde semnul ^
semnific{ “o adres{“. Mul#imea valorilor de tip PT const{ dintr-un num{r nelimitat de adrese; fiecare
adres{ identific{ o variabil{ de tip T. La aceast{ mul#ime de valori se mai adaug{ valoarea NIL care
identific{ nici o variabil{. Limbajul Pascal permite ca }n momentul }nt|lnirii tipului variabilei dinamice
acesta s{ nu fi fost definit; acest tip va fi, totu~i, declarat }n aceea~i declara#ie de tip (referire }nainte sau
autoreferire).

Exemplu: (Referire }nainte)

type referinta = ^articol; articol = record u, v: integer end;

var p,q:referinta; (* referire la variabile de tip articol *)

r: ^real; (* referire variabile dinamice *)

s: ^boolean; (* de tip ra#ional, respectiv logic *)

Exemplu: (Tip de date recursiv) O list{ este fie vid{, fie este identificata prin primul element ~i prin sublista
ce urmeaza acestuia. Defini#ia are caracter recursiv ~i este specificat{ prin:

type reper = ^lista;

lista = record

element: string[ 10] ; sublista: reper

end;

var p, q, r: reper;

begin

new(p);

new(q);

q^.sublista:=NIL;

p^.sublista:=q;

p^.element:=‘PRIMUL’;

q^.element:=‘ULTIMUL’;

end.

Dup{ crearea unei variabile dinamice a c{rei adres{ este depus{ }ntr-o variabil{ de tip referin#{, ea po
accesat{ prin a~a numita dereferen#iere: numele variabilei de tip referin#{ este urmat de semnul ^. Acest
semn poate fi urmat ~i de un alt calificator (de c|mp, ca }n exemplul 2; de tablou etc.). ]ntotde

31 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

dereferen#ierea unei variabile cu con#inut NIL declan~eaz{ o eroare de execu#ie.

Exist{ un tip predefinit Pointer, care este un tip referin#{ f{r{ tip de baz{. Astfel, o variabil{ de acest tip
poate s{ repereze o variabil{ de orice tip, motiv pentru care acestui tip i se mai spune ~i tip generic sau
liber. Declararea unei variabile de acest tip se face prin Var <identificator>:pointer; Variabilele de acest
tip sunt compatibile cu valoarea NIL, dar nu pot fi dereferentiate: scrierea simbolului ^ dup{ o astfel de
variabil{ constituie eroare. Variabilele de tip pointer sunt utile pentru memorarea unor variabile de tip
legat.

Valorile de tip referin#{ pot fi create cu operatorul @ ~i cu func#ia standard Ptr. Aceste valori sunt tratate
ca referin#e pentru valori dinamice.

3.6.2. Tipul referin#{ }n C

Facilit{#ile oferite pentru lucrul cu variabile de tip referin#{ (numite }n continuare pointeri) reprezint{ unul
dintre atuurile foarte importante ale limbajului C. Din punct de vedere al zonei adresate se disting 2
categorii de pointeri cu roluri ~i propriet{#i distincte: pointeri de date (con#in adrese de variabile s
constante din memorie) ~i pointeri de func#ii (con#in adresa codului executabil al unei func#ii). O a
categorie permite utilizarea pointerilor generici, numi#i ~i pointeri void.

3.6.2.1. Pointeri de date.

Sintaxa unui pointer de date este:

TIP *vpt;

Simbolul * precizeaz{ c{ vpt este numele unei variabile pointer, iar TIP este tipul obiectelor a c{ror adres{ o
va con#ine (adic{ tipul de baz{).

Pentru toate opera#iile }n care intervin pointeri, compilatorul interpreteaz{ zona de memorie adresat{
pointer ca obiect de tipul indicat la declarare, cu toate atributele tipului: num{rul de bytes necesa
semnifica#ia con#inutului zonei.

Declara#ia void
*vpt; este permis{ ~i permite declararea unui pointer generic. Tipul de baz{, }n declararea de mai sus, nu
este specificat. ]n cazul unui pointer void, dimensiunea zonei de memorie adresate ~i interpretare
informa#iei nu sunt definite, iar propriet{#ile sunt diferite de cele ale altor pointeri de date.

O variabil{ pointer este tot un obiect, deci are sens declararea unui pointer (ac#iune de indirectare) d
pointer. ]ntotdeauna, }nainte de utilizare, o variabil{ pointer trebuie ini#ializat{ (cu valoarea NULL =
adresa unei variabile existente sau adresa returnat{ de un apel de alocare a memoriei). Pointerii de orice tip
pot fi compara#i cu NULL pentru a verifica egalitatea sau inegalitatea.

Folosirea variabilelor pointer este posibil{ prin intermediul operatorilor unari: operatorul & (adresa
}ntoarce adresa unui variabile oarecare ~i, operatorul * (indirectare) pentru accesul la variabila adresat{ de
un pointer.

Fie declara#iile:

TIP var;

TIP *pvar;

32 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

atunci: &var (se cite~te “adresa variabilei var”) este de tip TIP *, deci atribuirea pvar = &var este corect{.
De asemenea, *pvar
(se cite~te “la adresa pvar”) reprezint{ obiectul de tip TIP adresat de pvar. Construc#ia *pvar poate
utilizat{ oriunde folosirea unei variabile este permis{ (inclusiv modificare).

Atribuirea este permis{ }ntre pointeri dac{ sunt de tipuri compatibile. ]n cazul pointerilor generici, e
necesar{ utilizarea operatorului “cast” de forma (TIP *).

Exemplu: (Un pointer poate indica obiecte diferite pe parcursul execu#iei programului)

void main(void){

int a=1, b=2, *c=&a; float d=3.14; void *e; printf(“%d”,*c);

*c=10; printf(“%d %d”,*c,a);

(*(c=&b))++; printf(“%d %d %d”,a,b,*c);

e=&d; printf(“%f%f”, d, *(float *)e);

e=&a; printf(“%d %d”, a, *(int *)e);

Al{turi de atribuire, }n limbajul C, sunt permise ~i opera#ii de comparare, adunare ~i sc{dere (


incrementare ~i decrementare):

compararea a doi pointeri folosind operatori rela#ionali. De exemplu, secven#


a {...; int *a, *b; ...; if (a<b) printf(“%d %d”, a, b); ... }este corect{.

compararea unui pointer cu valoarea NULL. Secven#a de alocare a 5 loca#ii de tip


float:

{...; if ((ptr=malloc(sizeof(float)*5))=NULL)

printf(“Mem. insuficient{”); else ... }

este echivalent{ cu:

{...; if (!(ptr=malloc(sizeof(float)*5)))

printf(“ Mem. insuficient{“); else ...}.

adunarea dintre un pointer de obiect ~i un }ntreg, conform unei reguli specifice: Pentru variabila
pointer declarat{ prin:
TIP *varpt; opera#iile: varpt + n ~i varpt - n corespund adun{rii (resp. sc{derii la (resp. din) adresa
varpt a valorii n*sizeof(TIP). Pentru aceste opera#ii, operanzii nu pot fi de tip void ~i nici pointeri de
func#ii.

sc{derea a doi pointeri de acela~i tip (excluz|nd cazurile


void
~i pointeri de func#ii), av|nd ca rezultat num{rul de obiecte de tipul respectiv. De exemplu, pentru
declara#iile: ...; int n; float *a, *b; ..., atribuirea n=b-a; este echivalent{ cu atribuirea lui n a valorii
(adr_b - adr_a)/sizeof(float).

Limbajul C permite utilizarea variabilelor tablou ca pointeri. Mai precis un nume de tablou f{r{ index este

33 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

un pointer constant de tipul elementelor tabloului ~i are ca valoare adresa primului element din ta
Opera#iile aritmetice de mai sus sunt definite consider|nd c{ obiectele adresate constituie un tablou.

Referitor la leg{tura dintre tablouri ~i pointeri, se impun urm{toarele observa#ii:

se pot da exprim{ri echivalente privind adresa unui element oarecare al unui tablou: dac{
tab este un tablou cu elemente de tip int, atunci construc#ia &tab[ i] este echivalent{ cu tab+i. Este
evident c{ expresia &tab[ 0] == tab este adev{rat{.

se pot realiza exprim{ri echivalente privind elementele tabloului: dac{


tab este tabloul de mai sus, atunci tab[ i] este echivalent cu *(tab+i). La parcurgerea unui tablou,
utilizarea pointerilor poate fi mai rapid{ dec|t indexarea. Urm{toarele secven#e determin{ lungimea
unui ~ir de caractere.

Secven#a:

... int k; char sir[ 50] ;

... for (k=0; sir[ k] ; k++); printf(“%d”, k);

...

realizeaz{ aceea~i opera#ie ca secven#a:

... int k; char sir[ 50] , *ad=sir;

... for(k=0; *ad; ad++) k++; printf(“%d”,k); ....

Observa#i diferen#ele de implementare. Referitor la constantele ~ir de caractere, compilatorul C


aloc{ zona de memorie necesar{ ~i }nscrie codurile ASCII ale caracterelor ~i codul final ‘\0’.
Urm{toarele exprim{ri sunt corecte:

char *sir; ...; sir=“Acesta este un sir”;

char *sir=“Al doilea sir”;

char sir[ ] =“Al treilea sir”;

]n privin#a tablourilor multidimensionale trebuie remarcat c{ numele tabloului este un pointer de


tablouri, iar c|nd numele unui tablou apare f{r{ indexare ca operand }ntr-o expresie sizeof, el refer{
}ntregul tablou.

incrementarea pointerilor este echivalent{ cu accesarea elementelor unui tablou: dac{ consider{m
declara#ia
int *p; atunci opera#ia *(p+i) este echivalent{ cu srierea p[ i] .

Pentru alocarea memoriei din spa#iul HEAP, biblioteca de func#ii a compilatorului C ofer{ un se
subprograme. Prototipurile func#iilor de alocare/eliberare se afl{ }n fi~ierele alloc.h ~i stdlib.h. Cele mai
folosite func#ii sunt: malloc() ~i free(). Func#ia care realizeaz{ alocarea unei zone de memorie ar
prototipul:

void *malloc(unsigned nr_bytes);

unde nr_bytes reprezint{ dimensiunea }n octe#i a zonei solicitate. Dac{ alocarea a reu~it, func#ia }ntoarce
un pointer care con#ine adresa primului octet al zonei alocate. ]n caz contrar (spa#iul disponibil e

34 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

insuficient), rezultatul returnat este NULL (=0). Cum tipul rezultatului este void, trebuie utilizat
operatorul cast
pentru conversie de tip la atribuire, iar pentru precizarea dimensiunii zonei solicitate se poate utili
operatorul sizeof.

Eliberarea spa#iului alocat trebuie solicitat{ de c{tre programator. Acesta va utiliza func#ia cu prototipul:

void free(void *ptr);

unde parametrul ptr indic{ adresa de }nceput a zonei care trebuie eliberat{. Este obligatoriu ca ptr s{ fi fost
rezultatul unui apel al func#iei malloc.

Alte func#ii de alocare/eliberare disponibile }n implementarea Borland/Turbo C sunt: calloc(), corel


realloc(); farmalloc(); farcalloc(); farfree() etc.

3.6.2.2. Transferul parametrilor }n C.

]n limbajul C transferul implicit al parametrilor, }ntre subprograme, este prin valoare. Dac{ dorim ca
func#ie s{ modifice o variabil{ parametru formal, trebuie s{ transmitem func#iei adresa variabilei, ia
interiorul func#iei s{ folosim operatorul *. Func#ia schimba () din exemplul urm{tor inverseaz{ valorile
dou{ variabile av|nd tipul TIP. Pentru a schimba efectiv, func#ia are nevoie de adresele celor dou{
variabile:

schimba(TIP *u, TIP *v) {

TIP t;

t=*u; *u=*v; *v=t;

Apelul functiei pentru a schimba con#inutul a dou{ loca#ii este:

...

TIP a,b;

...

schimba(&a, &b);

...

Transferul parametrilor prin referin#{ este permis }n limbajele Pascal ~i C++. Astfel }n limbaju
subprogramul schimba, se scrie:

procedure schimba(var x, y:TIP);

var t:TIP;

begin

t:=x; x:=y; y:=t

end;

35 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Prin folosirea parametrilor formali referin#{, limbajul C++ permite realizarea transferului prin referin#{
de o manier{ apropiat{ limbajului Pascal. Secven#a de program C++ demonstrativ{ este:

void schimba(TIP &, TIP &);

void main (void) {

TIP u,v;

...

schimba(u,v);

...

void schimba(TIP &x, TIP &y){

TIP t;

t=x; x=y; y=t;

Relativ la transmiterea tablourilor }ntre unit{#i de program C, trebuie spus c{ este implementat transfer
prin referin#{ deoarece tablourile con#in, }n general, o cantitate mare de date. Pe de alt{ parte chiar
numele tabloului este echivalent cu adresa sa. Pentru tablourile multidimensionale, compilatorul treb
cunoasc{ modul de organizare a tabloului pentru ca elementele s{ poat{ fi referite indexat }ntr-o func#
Pentru un tablou multidimensional, este esen#ial ca func#ia s{ cunoasc{ toate dimensiunile tabloului ma
pu#in prima. Fie scrmat
func#ia care tip{re~te elementele unei matrice de numere }n virgul{ mobil{. Urm{torul cod C reprezin
solu#ia corect{ a problemei.

void scrmat(float (*a)[ ] , int m, int n){

int i,j;

for (i=0; i<m; i++) {

for (j=0; j<n; j++) printf(“%f”, ((float * ) a)[ i*n+j] );

printf(“\n”);

La apel (scrmat(p,5,7);) se transmite adresa matricei (p) interpretat{ de tip float (*)[ ] , adic{ pointer c{tre
un tablou. Pentru a ob#ine adresa elementului a[ i] [ j] se utilizeaz{ expresia a+(i*n+j)*sizeof(float).

3.6.2.3. Pointeri de func#ii

Variabilele pointer care con#in adresa de start a unei func#ii permit: transferul func#iei asociate
parametru, apelul func#iei prin intermediul pointer-ului.

36 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

]ntotdeauna, o declara#ie de forma:

tip_r (* pfct) (<l_param>);

introduce pfct ca pointer cu tipul de baz{ “func#ie cu lista de parametrii l_param ~i cu rezultat tip_r”.

Trebuie observat rolul parantezelor pentru a distinge }ntre un pointer de func#ie ~i o func#ie care
}ntoarce un pointer.

Declara#ia

tip_r * fct(...);

este prototipul unei func#ii care }ntoarce un pointer, }n timp ce prin declara#ia

tip_r (* fct) (...);

se introduce fct ca pointer c{tre o func#ie.

Urm{torul tabel indic{ diverse situa#ii }n care apar pointeri, tablouri, func#ii.

Expresia Semnifica#ia expresiei

(* x) x este un pointer

(* x)[ ] x este un pointer la un tablou

(* (* x[ ] )) x este un pointer la un tablou de pointeri.

(* (* x)[ ] x este un pointer la un tablou de pointeri la


)() func#ii care }ntorc pointeri

int (*p)[ ] ; p este un pointer la un tablou de }ntregi

int (**p)[ ] p este un pointer la un pointer la un masiv de


; }ntregi

int *(*p)[ ] p este un pointer la un masiv de pointeri la


; }ntregi

int * (*f)(); f este un pointer la o func#ie care }ntoarce un


pointer la un }ntreg.

Exemplu: (Utilizarea func#iei standard qsort ce implementeaz{ algoritmul Quick Sort pentru sortare intern{).
Func#ia qsort, are prototipul (descris }n fi~ierul stdlib.h):

37 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

void qsort (void *tab, int n, int m, int (* comp) (const void *, const void *));

unde tab este tabloul de sortat cu n elemente, fiecare element av|nd dimensiunea m. Func#ia de comparare
trebuie scris{ de utilizator, comp
fiind un pointer la aceast{ func#ie. Dup{ compararea a dou{ elemente, func#ia va }ntoarce: 0 dac{
elementele sunt egale, o valoare negativa dac{ primul element este mai mic dec|t al doilea ~i o valoare
pozitiv{ altfel. Sensul rela#iilor mai mic, mai mare, egal este abstract ~i trebuie specificat de programator
Fie func#iile:

int comp_int (const void *x, const void *y) {

return * ((int *)x) -*((int *)y);

int comp_str (const void *x, const void *y) {

return strcmp(x,y);

Urm{toarele secven#e de apel realizeaz{:

ordonarea cresc{toare a unui tablou cu 500 de numere }ntregi:

int vector[ 500] ;

qsort(vector, 100, sizeof(int), cmp_int);

ordonarea cresc{toare a unui tablou de 500 de ~iruri de caractere, fiecare put|nd avea maxim 65 de
octe#i:

char x[ 500] [ 65] ; qsort(x,100,65,cmp_str);

3.7. Fi~iere
Organizarea datelor, necesar{ pentru prelucrarea acestora, presupune realizarea unor opera#ii
identificarea, clasificarea ~i descrierea atributelor caracteristice; gruparea datelor }n colec#ii; stoc
colec#iilor pe suporturi de date (}n general de tip magnetic); specificarea ~i implementarea procedu
prelucrare a datelor precum ~i alte proceduri (manuale sau automate) de }ntre#inere a suporturilo
informa#ii.

Structurile de date necesare prelucr{rii colec#iilor mari de date sunt at|t interne c|t ~i externe. Structura de
date de tip extern o reprezint{ fi~ierul. Un fi~ier este o mul#ime de date omogene ca interpretare ~
prelucrare. Din punct de vedere al sistemului de operare un fi~ier are anumite caracteristici (nume,
atribute, informa#ii pentru asigurarea accesului ~i a securit{#ii datelor). Intern, un fi~ier este o colec#ie de
articole (date de tip record - }n Pascal, struct
- }n C). Lungimea unui articol este dat{ de suma lungimii c|mpurilor componente. Dac{ toate articolele unui
fi~ier au aceea~i lungime spunem c{ fi~ierul are articole de lungime fix{, altfel fi~ierul este cu articole
lungime variabil{.

Implementarea fizic{ difer{ de la un limbaj de programare la altul. De asemenea difer{ ~i subprogramele


care permit realizarea opera#iilor asupra fi~ierelor. Limbajele Pascal ~i C permit definirea ~i prelucrarea
at|t a fi~ierelor cu articole de lungime fix{ c|t ~i a celor ce con#in articole de lungime variabil{. Pe suportul
extern, datele stocate sunt secven#e de octe#i. Numai }n momentul prelucr{rii, aceste succesiuni

38 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

interpreteaz{ adecvat, fiind posibil{ prelucrarea octet cu octet sau prelucrarea blocurilor de octe#i.

Pentru organizarea extern{, pe suport de date, sunt posibile mai multe metode: organizarea secven#i
(singura permis{ de limbajele Pascal ~i C), organizarea relativ{ ~i cea indexat{ (permise de limba
specializate, de exemplu COBOL).

Pozi#ia din care se cite~te, respectiv }n care se scrie, este dat{ de un indicator de articol (notat, }n
continuare, prin IA).

Accesul pentru scrierea datelor sau pentru citirea datelor stocate depinde de modul de organizare ale
Accesul secven#ial este posibil pentru orice mod de organizare, el presupune }nregistrarea articolelor
ordinea }n care devin disponibile ~i citirea articolelor }n ordinea }n care au fost }nscrise pe suport.

Pentru citirea }n acces secven#ial, este foarte important controlul identific{rii sf|r~itului fi~ierului. Dup
citirea ultimului articol (a ultimei linii sau a ultimului octet) indicatorul este pozi#ionat pe marcatorul d
sf|r~it de fi~ier (EOF - End Of File). Sesizarea sf|r~itului de fi~ier se face diferit }n func#ie de limbajul de
programare:

la citirea articolului (FORTRAN, COBOL); adic{ dup{ citirea ultimului articol, mai este necesar{ o
citire pentru a vedea dac{ s-a ajuns la sf|r~it.

independent de opera#ia de citire (Pascal, C, etc.), adic{ dac{ indicatorul IA este dup{ ultimul articol,
automat se consider{ sf|r~it de fi~ier; urm{toarea citire va produce eroare de intrare/ie~ire.

]n consecin#{, algoritmii de prelucrare depind de modul de sesizare a marcajului EOF. De regul{,


}ncercarea de citire din fi~ier dup{ ce s-a atins marcajul EOF este urmat{ de apari#ia unei erori.

Accesul direct este permis numai pentru fi~ierele cu o anumit{ organizare, entitatea de citire este articolu
sau blocul ~i sunt memorate pe discuri magnetice, CD sau VideoDisk (suporturi adresabile). Valoarea IA,
nu se calculeaz{ }n func#ie de valoarea sa anterioar{ (ca }n cazul accesului secven#ial) ci direct cu ajutoru
unei func#ii f cunoscute de sistem IA(k)=f(k). Sunt posibile dou{ moduri de acces direct: acces dup{ chei
acces dup{ num{rul articolului. ]n cazul accesului dup{ cheie (implementat de exemplu }n COBOL)
presupune c{ fiecare articol are un c|mp, numit cheie, care este folosit la }nregistrare/citire pentr
identificarea articolului. Pentru accesul relativ, implementat }n limbajele Pascal ~i C, articolul este localizat
prin num{rul s{u relativ. Articolul k are num{rul relativ k-1.

Asupra fi~ierelor se pot executa opera#ii de gestiune divizate pe dou{ niveluri: opera#ii globale (}ns
fi~ierului }ntr-un folder (catalog), deschiderea pentru consultare/actualizare a unui fi~ier, }nchiderea u
fi~ier, redenumirea, ~tergerea, copierea fi~ierelor, etc.) ~i opera#ii la nivel de articol (scriere sau citire de
articole).

]n programele Pascal, C, Java, ~. a. , opera#iile de intrare-ie~ire sunt realizate prin intermediul


subprograme (proceduri ~i func#ii }n Pascal, func#ii }n C, metode }n Java). Pentru unele opera#ii es
necesar{ utilizarea mai multor subprograme (de exemplu, }n Pascal, pentru opera#ia de deschidere s
necesare fie apelurile Assign+Reset, fie apelurile Assign+Rewrite.)

3.7.1. Fi~iere }n C

Bibliotecile standard C ofer{ o gam{ larg{ de func#ii care implementeaz{ opera#iile de intrare-ie~ire
orientate pe fi~iere. Dispozitivele periferice, ale sistemului de calcul, sunt v{zute tot ca fi~iere, da
identificatori predefini#i. Prototipurile func#iilor de bibliotec{ privind lucrul cu fi~iere sunt cuprinse
fi~ierul antet stdio.h. Se pot distinge 3 categorii: sistemul de intrare-ie~ire standard ANSI C; sist
intrare-ie~ire compatibil UNIX ~i, func#ii specifice implement{rii mediului de dezvoltare, neprev{z
standardul limbajului. ]n cele ce urmeaz{ ne vom ocupa de prima categorie. Celelalte categorii se pot studia
folosind manualul on-line sau manualul firmei produc{toare a mediului de dezvoltare.

39 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Conceptul de baz{ relativ la opera#iile de intrare-ie~ire standard este cel de pointer la fi~ier. Mai precis, }n
fi~ierul stdio.h este definit un tip de structur{, numite FILE. Din punct de vedere intern, fi~ierele prezente
}n func#iile de intrare-ie~ire sunt specificate prin variabile de tip FILE *.

Declararea unui pointer la fi~ier se realizeaz{ prin scrierea

FILE * <identificator>;

Prin opera#ia de deschidere, se aloc{ o zon{ de memorie care va con#ine: numele extern al fi~ierului, adresa
unei zone tampon util{ }n realizarea transferurilor ~i informa#ii utile privind starea opera#iilor
intrare-ie~ire. Aceast{ conexiune logic{ rezultat{ }n urma deschiderii unui fi~ier se nume~te stream (sau
flux de date). Eliberarea zonelor alocate se realizeaz{ }n urma opera#iei de }nchidere.

Dispozitivele de intrare-ie~ire standard au asociate permanent c|te un asemenea pointer al c{rui nu


predefinit: stdin (conola pentru intrare), stdout (consola pentru ie~ire), stderr (consola pentru ie~ire),
stdaux (pentru primul port al interfe#ei seriale ), stdprn (pentru primul port al interfe#ei paralele); ultimi
doi identificatori fiind caracteristici implement{rii BORLAND pentru calculatoare compatibile IBM
Microsoft.

De asemenea, }n fi~ierul stdio.h, mai sus definite constantele FILENAME_MAX (pentru a indica lungimea
maxim{ a numelui unui fi~ier, din punct de vedere extern) ~i FOPEN_MAX (care precizeaz{ num{rul
maxim de fi~iere ce pot fi deschise simultan).

Se disting dou{ categorii de tipuri de transfer:

un stream de tip text care transfer{ secven#e de caractere organizate }n linii; }n C separarea liniilor
se face prin caracterul LF. Pentru adaptarea la dispozitivul fizic poate fi necesar{ }nlocuirea
caracterului LF cu secventa CR-LF.

un stream binar care transfer{ o secven#{ de octe#i f{r{ alte prelucr{ri.

Distingerea }ntre cele dou{ categorii nu este obligatorie; programatorul este cel care trebuie s{ rez
eventualele probleme de conversie a datelor.

Deschiderea fi~ierelor se realizeaz{ folosind func#ia fopen care returneaz{, c|nd toate condi#iile de
prelucrare sunt }ndeplinite, un pointer c{tre structura FILE. Este unica modalitate prin care se atribuie
corect o valoare unui pointer la fi~ier. Prototipul func#iei fopen este:

FILE * fopen(const char * nume_fis, const char * mod_acces);

unde nume_fis
este un ~ir de caractere (constant{ sau ob#inut prin atribuire) care specific{ numele extern al fi~ierului, iar
mod_acces
este un ~ir de caracter (constituit similar) care descrie modul de acces. ]n cazul unei opera#ii de desch
corecte, pointerul returnat de apel este diferit de NULL, }n caz contrar rezultatul apelului este NULL.

Modurile posibile de acces sunt:

deschidere flux de tip text (“r” sau “rt”), respectiv flux binar (“rb”) pentru citire (mod
reset);

deschidere flux de tip text (“w” sau “wt”), respectiv flux binar (“wb”) pentru scriere (cu distrugerea
fi~ierului anterior, dac{ acesta exista- mod
rewrite);

40 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

deschidere flux de tip text (“a” sau “at”), respectiv flux binar (“ab”) pentru ad{ugare la sf|r~it (mod
append);

deschidere flux de tip text (“r+” sau “r+t”), respectiv flux binar (“r+b”) pentru actualizare (citire ~i
scriere folosind acela~i pointer la fi~ier);

deschidere flux de tip text (“w+” sau “w+t”), respectiv flux binar (“w+b”) pentru actualizare (dac{
fi~ierul exista anterior, con#inutul s{u se pierde);

deschidere flux de tip text (“a+” sau “a+t”), respectiv flux binar (“a+b”) pentru actualizare cu scriere
la sf{r~itul fi~ierului.

]nchiderea fi~ierelor se realizeaz{ apel|nd func#ia fclose definit{ astfel:

int fclose(FILE * <identificator>);

care }ntoarce EOF }n caz de eroare sau 0 }n caz normal. Prin }nchidere }nceteaz{ conexiunea logic{ d
pointer ~i fi~ier cu scrierea datelor din zona tampon de ie~ire (}n cazul deschiderii pentru
scriere/actualizare), respectiv cu pierderea datelor din zona tampon de intrare (}n cazul desc
citire/actualizare).

Detectarea sf|r~itului de fi~ier se realizeaz{ prin utilizarea macrodefini#iei feof cu prototipul:

int feof(FILE * <identificator>);

al c{rei rezultat este nenul (s-a detectat EOF) respectiv zero (nu s-a detectat EOF).

Exemplul 3.7.4 (Copierea unui fi~ier de tip text f1.txt }n fi~ierul text f2.txt).

#include <stdio.h>

int main(void) {

FILE *sursa, *dest;

if ((sursa=fopen(“f1.txt”, “rt”)) == NULL) {

fprintf(stderr,”Nu se poate deschide f1.txt !”);

return 1;

if ((dest=fopen(“f2.txt”,”wt”)) == NULL) {

fprintf(stderr, “Nu se poate deschide f2.txt!”);

return 2;

while (!feof(sursa)) fputc(fgetc(sursa),dest);

fclose(sursa);

fclose(dest);

41 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

return 0;

Asocierea unui nou fi~ier la un flux deschis deja se realizeaz{ folosind func#ia freopen cu prototipul:

FILE * freopen(const char * <id_fis_extern>, const char * <mod_acces>, FILE * p_fis);

unde p_fis este identificatorul fluxului existent care se va }nchide }n urma apelului ~i se va deschide fi~ierul
cu numele <id_fis_extern> }n modul de prelucrare <mod_acces> atribuind pointerul la structura creat{
variabilei p_fis. Func#ia returneaz{ valoarea atribuit{ lui p_fis.

For#area scrierii zonelor tampon asociate fi~ierelor deschise pentru scriere se realizeaz{ folosind func#ia
fflush cu prototipul:

int fflush(FILE * <id_fis>);

care returneaz{ EOF }n caz de eroare, respectiv 0 }n cazul normal.

Multe aplica#ii necesit{ lucrul cu fi~iere temporare care s{ fie ~terse automat la }nchidere sau la terminarea
normal{ a programului. ]n sprijinul programatorului, pentru a }nlesni astfel de activit{#i, biblioteca C ofer{
o func#ie cu prototipul: FILE *tmpfile(void);
care la apel creeaz{ un fi~ier temporar }n modul “wb+”. Func#ia }ntoarce un pointer la acel fi~ier. A
succesive vor deschide fi~iere distincte.

Alte opera#ii la nivel de fi~ier sunt:

~tergerea unui fi~ier - folosind func#ia

int remove(const char * nume_fis);

schimbarea numelui - folosind func#ia

int rename(const char *f_nou, const char *f_vechi);

Ambele func#ii }ntorc o valoare nenul{ }n caz de eroare ~i zero }n cazul normal.

Opera#iile de transfer se realizeaz{ folosind urm{toarele func#ii clasificate }n func#ie de tipul fluxului (text,
respectiv binar) ~i de tipul opera#iei (scriere, respectiv citire).

I. Flux de tip text

a) Scriere cu format. Se pot folosi urm{toarele func#ii: fprintf, printf, sprintf, vfprintf, vprintf, vsprinf. Ne
vom referi numai la func#iile fprintf ~i printf.

Func#ia fprintf este o func#ie cu num{r variabil de parametrii av|nd prototipul:

int fprintf(FILE *fp, const char *format, ...);

unde fp se refer{ la fluxul de date deschis }n vederea realiz{rii transferului, iar format respect{
specifica#iile descrise }n sec#iunea 4.4.2.

Func#ia printf a fost descris{ }n sec#iunea amintit{ anterior ~i este echivalent{ cu fprintf(stdout,format,
...).

b) Citire cu format.

42 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

Se pot folosi urm{toarele func#ii:fscanf, scanf, sscanf. Vom utiliza numai func#iile fscanf ~i scanf. Func#ia
fscanf este o func#ie cu num{r variabil de argumente ~i are prototipul:

int fscanf(FILE *fp, const char *format, ...);

Parametrii apelului au acelea~i semnifica#ii ca mai sus, iar func#ia scanf este echivalent{ cu scanf(stdin,
format, list{_adrese).

c) Citire de caractere din fi~iere text.


Se pot utiliza func#ia fgetc ~i macrodefini#ia getc. Func#ia cu prototipul int fgetc(FILE *fp); }ntoarce
urm{torul caracter din fp ca un }ntreg f{r{ semn, convertit la int sau EOF dac{ s-a detectat sf|r~itul de
fi~ier sau a ap{rut o eroare. Macrodefini#ia cu prototipul int getc(FILE *fp); este echivalent{ cu func#ia
fgetc. Reamintim posibilitatea utiliz{rii apelului getchar() echivalent cu getc(stdin).

d) Scriere de caractere }n fi~iere text. Scrierea unui caracter c }ntr-un fi~ier text cu identificatorul intern
fp se realizeaz{ folosind func#ia cu prototipul:

int fputc(int c, FILE *fp);

care returneaz{ c
}n cazul succesului, respectiv EOF }n caz de e~ec. Se poate utiliza ~i macroinstruc#iunea cu prototipul int
putc(int c, FILE *fp); similar{ cu fputc, iar apelul putchar(c); este echivalent cu putc(c, stdout);.

e) Citirea unui ~ir de caractere din fi~iere text se realizeaz{ folosind func#ia cu prototipul:

char *fgets(char *s, int n, FILE *fp);

la al c{rei apel se citesc, }n s, cel mult n-1 caractere din fi~ierul fp la care se adaug{ caracterul ‘\0’ ~i se
returneaz{ s sau NULL }n caz unei erori sau la }nt|lnirea codului EOF.

Reamintim utilizarea func#iei cu prototipul:

char *gets(char *s);

care cite~te urm{toarea linie de la consol{ ~i o depune }n s.

f) Scrierea unui ~ir de caractere }ntr-un fi~ier text se realizeaz{ }n urma apelului func#iei cu prototipul:

int fputs(const char *s, FILE *fp);

care }ntoarce EOF }n caz de eroare, respectiv num{rul de caractere transferate }n caz de succes. Pentr
scriere la consol{ se utilizeaz{ func#ia:

int puts(const char *s);

II. Flux binar

]n aceast{ categorie intr{ func#iile de intrare/ie~ire }n acces direct care citesc/scriu din/}n fi~iere f{r{ nici o
conversie ~i f{r{ a se face vreo interpretare a datelor. No#iunea fundamental{ este cea de zon{ compact{
octe#i (}nregistrare) care se cite~te sau se scrie. Citirea/scrierea se face de la / la pozi#ia curent{ din fi~ier,
care poate fi modificat{ cu func#ii speciale dup{ cum vom vedea mai jos. Dup{ executarea opera#iei, pozi#ia
indicatorului (de octet }n cazul limbajului C) este actualizat{ automat, pentru a indica urm{toar
}nregistrare. Citirea a nrec }nregistr{ri din fi~ierul cu identificatorul fp, fiecare av|nd lungimea L, cu
stocare }n tabloul ptr se realizeaz{ folosind apelul:

n = fread(ptr, L, nrec, fp);

43 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

care }ntoarce un }ntreg n


ce furnizeaz{ num{rul de }nregistr{ri citite. Dac{ s-a }nt|lnit EOF sau eroare atunci n va fi 0.

Pentru scrierea a nrec }nregistr{ri de lungime L fiecare, din zona cu adresa ptr }n fi~ierul cu identificatorul
intern fp se folose~te apelul:

m = fwrite(ptr, L, nrec, fp);

unde m va reprezenta num{rul de }nregistr{ri scrise, cu m < nrec numai }n caz de eroare.

Pentru a avea acces la orice zon{ a fi~ierului, biblioteca C ofer{ un set de func#ii care permit:

citirea valorii indicatorului de pozi#ie. Func#ia


fgetpos }nscrie valoarea indicatorului }n variabila poz ~i }ntoarce 0 }n caz de succes. Prototipul
func#iei este:

int fgetpos(FILE *fp, long int *poz);

Func#ia ftell
}ntoarce pozi#ia curent{ }n fi~ier }n caz de succes ~i -1L }n caz de e~ec. Aceasta are prototipul:

long int ftell(FILE * fp);

modificarea valorii indicatorului de pozi#ie. Sunt disponibile func#iile: fsetpos, fseek ~i rewind.
Func#ia
fsetpos are prototipul:

int fsetpos(FILE *fp, const long int *poz);

~i atribuie indicatorului valoarea variabilei poz ~i }ntoarce 0 }n caz de succes.

Func#ia fseek face o deplasare a indicatorului de pozi#ie cu nr_octe#i relativ la o pozi#ie de referin#{
specificat{ prin constanta }ntreag{ origine. Se pot utiliza urm{toarele valori: 0 = SEEK_SET (}nceput de
fi~ier), 1=SEEK_CUR (pozi#ie curent{), 2 = SEEK_END (sf|r~it de fi~ier). Valoarea }ntoars{ de fseek este
0 pentru succes ~i nenul{ }n caz de e~ec. Prototipul func#iei fseek este:

int fseek(FILE *fp, long nr_octe#i, int origine);

Folosind func#ia rewind are loc pozi#ionarea la }nceputul fi~ierului. Prototipul func#iei rewind este:

void rewind(FILE *fp);

Pentru a ob#ine informa#ii despre un fi~ier se pot utiliza func#iile stat ~i fstat cu prototipul declarat }n
fi~ierul stat.h din catalogul sys. Ne vom referi la func#ia stat. Aceasta are prototipul:

int stat (char *cale, struct stat * statzona);

unde: cale reprezint{ numele fi~ierului sau catalogului, iar statzona este adresa unei structuri de tip stat
ale c{rei c|mpuri descriu starea entit{#ii }n discu#ie. De exemplu, c|mpul st_size furnizeaz{ dimensiunea
unui fi~ier, }n octe#i.

Exemplul 3.7.5.
(Aflarea dimensiunii unui fi~ier folosind func#iile de citire-modificare a indicatorului de pozi#ie).

#include <stdio.h>

44 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

long filesize(FILE *fp);

int main(void){

FILE *f;

f=fopen(“F_test.txt”,”w+”);

fprintf(f, “Aflarea dimensiunii unui fisier folosind functiile\n”);

fprintf(f, “de citire-modificare a indicatorului de pozitie.\n”);

printf(“%ld”,filesize(f));

return 0;

long filesize(FILE *fp){

long cp, lung;

cp = ftell(fp);

fseek(fp, 0L, SEEK_END);

lung=ftell(fp);

fseek(fp, cp, SEEK_SET);

return lung;

Exemplul 3.7.6. (Metode de sortare a datelor stocate }n fi~iere). Sortarea datelor stocate }ntr-un fi~ier se
poate realiza cu aducerea integral{ a datelor }n memoria volatil{ (sortare intern{) sau cu aducerea }
memoria principal{ a c|te unui articol (sortare extern{). Metodele prezentate aici nu sunt din cele
performante, ele ilustreaz{ accesul la datele stocate }n fi~iere ~i principalele modalit{#i de prelucrare. O alt{
metod{ de sortare a datelor externe utilizeaz{ procedeul interclas{rii colec#iilor ordonate. Principiul a
metode va fi explicat }n contextul rezolv{rii problemelor prin metoda divide et impera.

a) Sortarea intern{.
Metoda se poate aplica numai fi~ierelor de dimensiune redus{ (ca num{r de articole sau ca lungim
articolelor). Se pot descrie mai multe solu#ii posibile:

Stocarea integral{ a datelor }n memoria principal{. Se va utiliza un vector de articole, compararea


fiind realizat{ prin intermediul cheii de sortare. Pentru sortare intern{ se poate utiliza oricare dintre
metodele cunoscute. ]n final vectorul sortat se }nregistreaz{ }n fi~ierul redeschis pentru scriere.
Con#inutul vechi va fi automat distrus.

Sortare cu manipularea cheii de sortare ~i a pozi#iei articolului }n fi~ier (indexul articolului). Aceast{
metod{ presupune memorarea }ntr-un vector numai a valorii cheii de sortare, }mpreun{ cu num{rul
relativ al articolului fi~ierul de sortat. Compara#iile asupra valorilor cheii de sortare vor conduce la
interschimb{ri }n vectorul intern, Ob#inerea fi~ierului sortat se va face prin parcurgerea }n acces
secven#ial a fi~ierului ini#ial ~i scrierea articolelor, }n ordine, }n fi~ierul rezultat. Programul care

45 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

urmeaz{ ilustreaz{ aceast{ strategie.

#include <stdio.h>

typedef struct {char nume[ 20] ; float media;} articol;

FILE *fin, *fout;

float x[ 300] ; int index[ 300] ;

long filesize(FILE *fp);

/* se include definitia de la exemplul 4.7.5 */

void main (void){

long i,j,n,itemp; float xtemp; articol a;

fin=fopen(“f1.dat”,”rb”); fout=fopen(“f2.dat”,”wb”);

n=filesize(fin)/sizeof(articol);

for (i=0; i<n; i++){

fread(&a,sizeof(articol),1,fin); x[ i] =a.media;index[ i] =i;

for (i=0; i<n-1; i++)

for (j=i+1; j<n; j++)

if (x[ i] >x[ j] ) {

itemp=index[ i] ; index[ i] =index[ j] ; index[ j] =itemp;

xtemp=x[ i] ; x[ i] =x[ j] ; x[ j] =xtemp; }

for (i=0; i<n; i++) {

fseek(fin,index[ i] *sizeof(articol),SEEK_SET);

fread(&a, sizeof(articol), 1, fin);

fwrite(&a, sizeof(articol), 1, fout);

fclose(fin); fclose(fout);

b) Sortare extern{.
Aceast{ abordare este caracteristic{ fi~ierelor de dimensiune mare, pentru care nu se poate aplica o metod
de tip a2. Opera#iile trebuie realizate direct }n fi~ier. Ilustr{m utilizarea func#iilor fseek, fread ~i fwrite
}n implementarea metodelor de sortare prin interschimbare ~i prin selec#ie. Se utilizeaz{ elementele
descrise }n cadrul programului a2.

46 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

sortare prin interschimbare:

FILE *fp; int ok; long i, n; articol a[ 2] ;

fp=fopen(“fis.dat”,”r+b”);

n= filesize(fp)/sizeof(articol);

do {ok=0;

for(i=0; i<n-1; i++) {

fseek(fp, i*sizeof(articol), SEEK_SET);

fread(a, sizeof(articol), 2,fp);

if (a[ 0] .media > a[ 1] .media) {

fseek(fp, i*sizeof(articol), SEEK_SET);

fwrite(a+1, sizeof(articol),1,fp);

fwrite(a,sizeof(articol),1,fp);

ok = 1;

}while (ok);

sortare prin selec#ie:

FILE *fp; long i,j, n; articol a, b;

fp=fopen(“fis.dat”,”r+b”); n= filesize(fp)/sizeof(articol);

for(i=0; i<n-1; i++) {

fseek(fp, i*sizeof(articol),SEEK_SET);

fread(&a, sizeof(articol), 1, fp);

for(j=i+1; j<n; j++) {

fseek(fp, j*sizeof(articol), SEEK_SET);

fread(&b, sizeof(articol),1,fp);

if (a.media>b.media) {

47 of 48 12/9/2007 7:21 PM
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM

fseek(fp, i*sizeof(articol), SEEK_SET);

fwrite(&b, sizeof(articol), 1, fp);

fseek(fp, j*sizeof(articol), SEEK_SET);

fwrite(&a, sizeof(articol), 1, fp);

a=b;}

}}

Vreau sa merg la inceputul capitolului

Vreau sa vad Cuprinsul documentului.

Versiune prescurtata a capitolulul 4 din: G. Albeanu, Algoritmi si limbaje de programare. Editura "Fundatiei
România de Mâine", 2000

48 of 48 12/9/2007 7:21 PM
Bazele Informaticii: Bibliografie suplimentara file:///C:/ACTIV/Proc/FINAL/BIB.HTM

Bibliografie suplimentara
1. Aho A. V., Hopcroft J. R., J. D. Ullman, The Design and Analysis of Computer Algorithms, Addison-Wesley Comp,
1975.

2. Albeanu G., Algoritmi si limbaje de programare. Editura Fundatiei "România de Mâine", 2000

3. Albeanu G., Programarea in Pascal si Turbo Pascal. Culegere de probleme. Editura Tehnicã, 1994.

4. Albeanu G., Sisteme de operare, Editura Petrion, 1996.

5. Bãlãnescu T., Corectitudinea algoritmilor, Editura Tehnicã, Bucuresti, 1995.

6. Barbu Gh., Vãduva I., M. Bolosteanu, Bazele Informaticii, Editura Tehnicã, 1995.

7. Bohm C., G. Jacopini, Flow-diagrams, Turing Machines and languages with only two formation rules. Comm. ACM.,
9, 1966, 366-371.

8. Calude C., Complexitatea calculului. Aspecte calitative. Editura stiintificã si Enciclopedicã, Bucuresti, 1982.

9. Dahl, O.J., Dijkstra E. W., C. A. R. Hoare, Structured programming, Academic Press, London, 1972.

10. Enescu Gh., Logica simbolicã, Editura stiintificã, Bucuresti, 1971.

11. Flanagan D., Java in a Nutshell: A Desktop Quick Reference for Java Programmers, O Reilly & Associates, INC.

12. Hoare C. A. R. s.a., Laws of Programming, Comm. ACM., 30(8), 1987, 672-685.

13. Ichim I., Gh. Marinescu, Metode de aproximare numericã, Editura Academiei RSR, 1986.

14. Isaacson E., H. B. Keller, Analysis of Numerical Methods, Wiley, 1966.

15. Kerninghan B. W., D. M. Ritchie, The C Programming Language, Englewood Cliffs, Prentice Hall, 1978, 1988.

16. Knuth D., The art of computer programming, Vol. 1, Fundamental Algorithms, 3rd ed., Addison Wesley Longman,
1997; Arta Programãrii Calculatoarelor. Vol. 1, Algoritmi Fundamentali, Teora, 1999.

17. Knuth D., The Art of Computer Programming. Seminumerical Algorithms, Vol. 2, 1981; Tratat de programare a
calculatoarelor. Algoritmi seminumerici, Editura Tehnicã, 1983.

18. Knuth, Moris, Pratt, Fast pattern matching in strings, SIAM Journal on Computing, 6, 2, 1975.

19. Livovschi L., H. Georgescu, Sinteza si analiza algoritmilor. Editura Stiintificã si Enciclopedicã, 1986.

20. Mateescu E., I. Maxim, Arbori, Editura Tara fagilor, 1996.

21. Niculescu R., Albeanu G., V. Domocos, Programarea calculatoarelor. Probleme rezolvate in limbajul Pascal, Editura
Tempus, 1992.

22. Novikov P.S., Elemente de logicã matematicã, Editura Stiintificã, Bucuresti, 1966.

23. Pan V., Strassen's algorithm is not optimal, Proc. 19th Annual Symposium on the Foundations of Computer Science,
1978.

24. Pólya G., Cum rezolvãm o problemã? Editura Stiintificã, Bucuresti, 1965.

25. Popovici C., Georgescu H, L. State. Bazele Informaticii I, Tipografia Universitãtii Bucuresti, 1990.

26. Popovici C., Rudeanu S., H. Georgescu, Bazele Informaticii II, Tipografia Universitãtii, 1992.

27. Rudeanu S., Latici si algebre booleene, Tipografia Universitãtii Bucuresti, 1982.

1 of 2 12/9/2007 7:22 PM
Bazele Informaticii: Bibliografie suplimentara file:///C:/ACTIV/Proc/FINAL/BIB.HTM

28. State L., Elemente de logicã matematicã si demonstrarea automatã a teoremelor. Tipografia Universitãtii Bucuresti,
1989.

29. Strassen V., Gaussian elimination is not optimal, Numeriche mathematik, 13, 1969, 354-356.

30. Vãduva I., Modele de simulare cu calculatorul. Editura Tehnicã, 1975.

31. Vãduva I., Sisteme Informatice, Tipografia Universitãtii Bucuresti, 1981.

32. Wirth N., Systematic Programming. An Introduction, Prentice Hall, 1972.

33. Wirth N., Algorithms + Data Structures = Programs, Prentice Hall, 1976.

34. Wirth N., The programming development by stepwise refinement, Comm. ACM., 14 , 1971, 221-225.

35. Wirth N., Modula: A language for modular programming, Software Practice and Experience, 7, 1977, 3-35.

36. Waite M., R. Lafore, Data Structures & Algorithms in Java, Waite Group Press, 1998; Structuri de date si algoritmi in
Java, Teora, 1999.

37. Winograd S., On the multiplication of 2x2 matrices, IBM Research Report 267, 1970.

Vreau sa vad inceputul listei

Vreau sa vad Cuprinsul.

Data ultimei actualizari: 26 Februarie 2002

2 of 2 12/9/2007 7:22 PM
Se consideră programul:
1 #include <stdio.h>
void main(void){
int n, a;
printf("a = "); scanf("%d", &a);
printf("n = "); scanf("%d", &n);
printf("a = (a>>n)<<n are rezultatul : %d",
a = (a>>n)<<n
);
5 min }
Ce se afişează pentru:
i) a = 7, n = 2;
ii) a = 8, n = 2;
iii) a = 8, n = 4;
Se consideră programul:
#include <stdio.h>
2 int a, b; float x;
int f(int c){
int a; /* linia T */
a = 7; b = 3; return a+b+c;
}
void main(void){
a = 1; b= 2; x = f(a)/10;
printf("%3d %3d", a, b); printf(" %5.1f", x);
5 min }

Ce va afişa, dacă:
a) lipseşte linia T
b) nu lipseşte linia T
3 Se consideră programul:
#include <stdio.h>
int suma(int max){ int i; static int s = 0;
for (i=s; i<max; i++) s+=i;
return s;
}
void main(void){ int j, n= 5;
for (j=0; j<n; j++) printf("%3d",suma(j));
5 min }

Ce afişează ?
4 Se consideră programul:
#include <stdio.h>
void main(void){
int t[4]={0, 1, 2, 3}; int *p = &t[1];
printf("%d\n", *p++);
printf("%d\n", *++p);
printf("%d\n", ++*p);
}
5 min
Ce afişează ?
Se consideră programul:
5 #include <stdio.h>
int a[5] = {0, 1, 2, 3, 4};
int i = 4; int j =2;
void main(void){
printf("\n%d", a[i]);
printf("\n%d", i[a]);
}

3 min
Ce afişează?
a) 4, 4
b) 4, 0
c) Construcţia i[a] nu este corectă.
6 Declaraţia
char *x[];
îl defineşte pe x ca:

a) pointer către tablouri de tip char;


b) tablou de pointeri către elemente de tip
1 min char
c) a şi b
7 Ce afişează secvenţa de program ?

#include <stdio.h>
void main(void){
putchar (getchar()-'A'+'a');
putchar('\n');
}
2 min
dacă se introduce:
i) A
ii) G
iii) X
Se consideră programul:

8 #include <stdio.h>
char i = 0x63;
signed char j = 9, k;
void main(void){
printf(" i = %d \n", i = i & 0x5f);
printf(" j = %d \n", ~j);
printf(" k = %d \n", k = j | 0x30);
}
6 min
Ce valori vor avea variabilele i , j şi
k după executarea acestuia?
Interpretaţi rezultatul.
Fie programul:

9 #include <stdio.h>
unsigned f(unsigned n){
unsigned i, p;
for (p = 1, i = 1; i<=n; i++) p *= i;
return p;
}
void main(void){
for (int n = 0; n<=20; n++) printf("%d \n", f(n));
4 min }

Exista numere naturale n pentru care


programul nu afişează rezultatul
corect ? Argumentaţi !
Fie programul:

10 char *dup2(const char *str){


static char p[1000];
int n, k; for(n=0; str[n]!='\0';n++);
for(k=0; k<n; k++){ p[2*k]=str[k]; p[2*k+1] = str[k]; }
p[2*n]='\0';
return p;
}
int main(int argc, char *argv[]){
char *p1, *p2;
if(argc != 3){printf("Utilizaţi: %s sir1 sir2\n", argv[0]);
return 0;
9 min }
p1=dup2(argv[1]);puts(p1); p2=dup2(argv[2]);puts(p2);
puts(p1); puts(p2);
return 1;
}

Studiaţi comportamentul programului şi simulaţi executarea


acestuia. Precizaţi intrările şi ieşirile programului.

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