You are on page 1of 92

Programare procedurala

Programare procedurala
Anul I Semestrul I Informatica (cod MI1103) si Matematica Informatica (cod MB1206) Facultatea de Matematica si Informatica
Evaluare: - lucrari de verificare, teme de casa si activitate la laborator (pondere 35%) - proiect de semestru (pondere 35%) - Examen (E) (pondere 30%)

Obiective: studentul va fi familiarizat cu elemente fundamentale el programarii procedurale cum ar fi variabila, tip de data, proceduri si functii, transferul parametrilor, precum si cu elemente minimale de ingineria software-ului.

Tabla de materii (pe scurt)


Lectia 1
Scop:

Introducere in C++ structura unui program, intrari/iesiri, variabile, instructiunea for exercitii diverse

Aplicatii:

Saptamana: 01-07.10 Lectia 2


Scop:

Fundamente (I) constante, identificatori, declaratii, tipuri fundamentale, masive, enumerari exercitii diverse

Aplicatii:

Saptamana: 07-14.10 Lectia 3


Scop:

Fundamente (II) pointeri, structuri(masive), conversii, typedef, constante exercitii diverse

Aplicatii:

Saptamana: 14-21.10 Lectia 4 Fundamente (III)

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/index.html (1 of 3)10/2/2005 8:13:33

Programare procedurala

Scop:

Atributele datelor, operatori si expresii exercitii diverse

Aplicatii:

Saptamana: 21-28.10 Lectia 5


Scop:

Fundamente (IV) Instructiuni exercitii diverse .

Aplicatii:

Saptamana: 28-03.11 Lectia 6


Scop:

Fundamente (V) Scopul, vizibilitatea si tipul identificatorilor, includerea enumerarilor, etichete, declaratii exercitii diverse

Aplicatii:

Saptamana: 03-10.11 Lectia 7


Scop:

Functii (I) Declararea si argumentele functiilor, argumentele liniei de comanda exercitii diverse

Aplicatii:

Saptamana: 10-17.11 Lectia 8


Scop:

Functii (II) Pointeri la functii, recursivitate exercitii diverse .

Aplicatii:

Saptamana: 17-21.11 Lectia 9


Scop:

Functii (III) Prototip, functii cu numar variabil de argumente, utilizarea functiilor C in C++, parametri impliciti exercitii diverse

Aplicatii:

Saptamana: 21-28.11 Lectia 10


Scop:

Functii (IV) Transmiterea parametrilor prin referinta, functii inline, redefinirea functiilor exercitii diverse

Aplicatii:

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/index.html (2 of 3)10/2/2005 8:13:33

Programare procedurala

Saptamana: 28-04.12 Lectia 11


Scop:

Structuri (I) Structuri si functii, masive de structuri exercitii diverse .

Aplicatii:

Saptamana: 04-11.12 Lectia 12


Scop:

Structuri (II) Structuri cu autoreferire, campuri, uniuni . exercitii diverse

Aplicatii:

Saptamana: 11-18.12 Lectia 13


Scop:

Intrari si iesiri standard Intrari si iesiri pe consola si fisiere exercitii diverse .

Aplicatii:

Saptamana: 18-25.12 Lectia 14


Scop:

Preprocesorul C Directivele preprocesorului exercitii diverse .

Aplicatii:

Saptamana: 03-10.01.99

Bibliografie
D.M.Popovici, I.M.Popovici, C++. Tehnologia orientata spre obiecte. Aplicatii, Ed. Teora, Bucuresti, 2000, ISBN:973-20-0320-0.

Laboratoarele aferente in format electronic vor fi disponibile pe pagina web a Laboratorului de Grafica si Realitate Virtuala. http://www.univ-ovidius.ro/lgrv

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/index.html (3 of 3)10/2/2005 8:13:34

Lectia 1

LECTIA 1 INTRODUCERE IN PROGRAMAREA PROCEDURALA (Limbajul C)


Obiective Prezentare generala Intrari si iesiri Variabile

OBIECTIVE<home>
G G G G

Prezentare generala Structura unui program Intrari/iesiri Variabile

PREZENTARE GENERALA <home>


Conceptul de procedura, prezent in limbaje precum Pascal, Fortran, Basic sau C (sub diferite denumiri cum ar fi functie, procedura sau subrutina) permite segmentarea programului in module, numite proceduri. Filozofia transversala a paradigmei de programare procedurala (PP) aduce cu "divide et impera", fiecare procedura fiind mult mai simpla decat intregul program. Acest mod de programare faciliteaza dezvoltarea aplicatiilor in echipa, fiecare procedura putand fi implementata si testata independent de restul aplicatiei, fapt care faciliteaza, in plus, detectarea si corectarea erorilor de programare. Mai mult, adoptand aceasta paradigma de programare, devine posibila obtinerea programelor fara utilizarea instructiunii goto, care complica enorm lizibilitatea, depanarea si mentenanta acestora. Claritatea si "independenta" procedurilor face, in plus, posibila obtinerea bibliotecilor de proceduri, reutilizabile in diverse aplicatii. Un program in aceasta paradigma poate fi privit drept o colectie de date si proceduri ce se apeleaza intre ele si manipuland colectia de date. Conceptul de procedura permite structurarea acestor manevrari ale datelor, si deci reduce intr-o oarecare masura complexitatea acestor operatii, fara insa a reduce si complexitatea datelor. Unul din neajunsurile programarii procedurale il constituie tocmai efectul secundar al utilizarii neadecvate a variabilelor globale in cadrul unei aplicatii.

STRUCTURA UNUI PROGRAM

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia01.html (1 of 4)10/2/2005 8:13:34

Lectia 1

Un program in C, indiferent de marimea lui, consta din una sau mai multe functii care specifica operatiile efective ce trebuie efectuate. In limbajul C, functiile nu contin subfunctii (sau functii imbricate). Functia main() joaca un rol foarte important in viata unui program in C pentru ca executia oricarui astfel de program incepe cu ea. Prin urmare un program C nu poate avea decat o singura functie main(). Functia main() poate fi plasata oriunde in cadrul codului sursa al programului. Deoarece main()este o functie similara (ca structura si functionalitate) cu oricare alta functie din C, ea poate avea propriile sale tipuri de date locale, constante si variabile. In plus, functia main() poate sa intoarca o valoare, valoare care sa semnaleze o eventuala eroare in program. Pentru a defini blocuri in program, in C se utilizeaza caracterele {, }, pentru inceputul, respectiv sfarsitul blocului. Acoladele sunt analoge lui BEGIN-END din Pascal. Fiecare instructiune dintr-un program C se incheie prin caracterul ";". Programele scrise in C contin si directive de compilare. In acest limbaj exista urmatoarele directive de compilare: #define, #undef, #include, #error, #if. Directiva #define este utilizata de programator pentru:
G G G

G G

a defini constante a inlocui cuvinte rezervate sau simboluri cu alti identificatori definiti de programator a crea identificatori pentru tipurile de date definite de programator, folosind tipurile de date standard a prescurta comenzi pentru a defini pseudofunctii.

Directiva #include permite includerea unor linii de cod sursa din alt fisier in fisierul curent, ca si cum s-ar introduce de la tastatura acele linii de cod in codul sursa al programului curent. Sintaxa directivei #include este urmatoarea: #include <fisier> #include "nume_fisier" Cele doua forme ale directivei difera prin modul in care se comanda compilatorului cautarea fisierului inclus. Prima forma cere compilatorului sa caute fisierul inclus intr-un catalog special, care contine numai asemenea fisiere, iar a doua forma extinde cautarea fisierului de inclus si in catalogul curent. Un program in C poate sa contina si comentarii explicative. Comentariile care nu depasesc o linie sunt
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia01.html (2 of 4)10/2/2005 8:13:34

Lectia 1

precedate de caracterele "//". Pentru inserarea unui comentariu in cadrul codului sursa, acesta este incadrat de caracterele /*, */.

IESIRI <home>
Functia printf() poate fi considerata o functie de conversie de format, cu scop general. Primul sau argument este un sir de caractere ce se va tipari, fiecare caracter % indicand argumentele (al doilea, al treilea ) ce se vor substitui, si forma in care se vor tipari. Fiecare constructie cu % in primul argument al lui printf() face pereche cu al doilea, al treilea, argument, insa aceste perechi trebuie sa corespunda atat ca numar, cat si ca tip. Functia printf() recunoaste:
G G G G G G G G G

"%f" tipareste numarul ca flotant; "%d" intregi zecimali; "%s" pentru un sir de caractere; "%c" pentru un caracter; "%%" pentru semnul %. \t pentru tab \b pentru backspace \" pentru caracterul " \\ pentru caracterul \

VARIABILE<home>
Prin variabila se intelege o locatie de memorie care poate gazdui un obiect ales dintr-o multime prestabilita de obiecte. O variabila apare in doua ipostaze:
G G

locatie de memorie; pastratoare a unei valori.

Variabila este caracterizata si prin modul de identificare a sa. Din acest punct de vedere inseamna ca o variabila va avea un identificator, ii va corespunde o adresa si va avea o valoare. In limbajul C, toate variabilele trebuie declarate inainte de a fi folosite, de obicei la inceputul liniei, inaintea oricarei instructiuni executabile. O declaratie consta dintr-un tip si o lista de variabile care au acel tip. In C exista urmatoarele tipuri de date predefinite:
G

int (variabilele sunt intregi)

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia01.html (3 of 4)10/2/2005 8:13:34

Lectia 1
G G G G

char (de tip caracter) double (numar flotant in dubla precizie= real pe 64 biti) float(virgula mobila = real pe 32 biti) void (indica absenta oricarei valori )

Gama de tipuri de date devine mai flexibila prin adaugarea urmatorului set de modificari de tip:
G G G G

signed unsigned short (intreg scurt) long (intreg lung)

acestia afectand domeniul de valori si precizia datelor de tipul respectiv. Exista, de asemenea, tablouri, structuri, uniuni si clase de astfel de tipuri de baza, pointeri la ele si functii care le returneaza. Compilatorul face diferenta intre majuscule si minuscule atunci cand analizeaza variabilele si identificatorii. Numele unei variabile trebuie sa inceapa cu o litera si sa contina alte litere, cifre si caracterul _. In C, numele unei variabile poate avea orice lungime. Cand se declara o variabila intr-un program, este necesar ca acesteia sa i se asocieze un tip de date. Limbajul C permite atribuirea de valori variabilelor, in momentul declararii acestora. Sintaxa pentru declararea variabilelor este: tip numeVariabila ; tip numeVariabila=valoareinitiala; int i; double x=3.14; Asa cum se preciza mai sus, in C se pot declara si liste de variabile de acelasi tip. int j, i=2, k=3; double x=3.14; double y=2*x, z=4.5, a=45.7; Valorile cu care sunt initializate variabilele pot contine alte variabile, definite anterior, sau constante.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia01.html (4 of 4)10/2/2005 8:13:34

Lectia 2

LECTIA 2 FUNDAMENTELE LIMBAJULUI C (I)


Obiective Prezentare generala Constante Tipuri fundamentale Identificatori Masive Declaratii Enumerari

OBIECTIVE <home>
G G G G G G

constante; identificatori; declaratii; tipuri fundamentale; masive; enumerari.

PREZENTARE GENERALA <home> CONSTANTE<home>


In majoritatea limbajelor, scopul unui program este acela de a procesa anumite date. Aceste date pot aparea sub forma constantelor sau ca locatii de memorie, acestea fiind identificate cu ajutorul variabilelor. O constanta poate fi de forma unui numar intreg real ( sau in virgula flotanta ), sub forma unui caracter sau sir de caractere. Constantele intregi sunt reprezentate ca intregi cu semn si ocupa cel putin 2 octeti. O constanta poate fi considerata fara semn ( pozitiva deci ) cand se utilizeaza sufixul u sau U. Prin aceasta se modifica numai domeniul de valori, nu si dimensiunea spatiului necesar memorarii sale. Pentru a modifica dimensiunea spatiului alocat unei constante intregi sau reale se va utiliza sufixul l sau L. Constantele reale pot ocupa 4 octeti, daca sunt declarate cu sufixul f sau F, sau pot ocupa 8 octeti daca nu au nici un sufix. Constantele de tip caracter sunt alcatuite dintr-un singur caracter cuprins intre apostrofuri. Constantele caracter ocupa un singur octet, insa li se poate mari spatiul rezervat cu ajutorul literei L folosita ca un prefix al unui grup de 2 caractere cuprinse intre apostrofuri.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia02.html (1 of 5)10/2/2005 8:13:37

Lectia 2

Sirurile de caractere sunt delimitate de ghilimele. Aceste constante sunt memorate in locatii succesive de memorie, numarul lor fiind egal cu numarul caracterelor sirului plus unu, cel din urma octet reprezentand spatiul rezervat terminatorului de sir, caracterul nul , \0.

IDENTIFICATORI<home>
Identificatorii sunt formati cu ajutorul caracterelor alfanumerice si liniuta de subliniere. Primul caracter al unui identificator nu poate fi o cifra. In cadrul multimii identificatorilor posibili, o clasa aparte o reprezinta cuvintele cheie. Identificatorii inceputi cu liniuta de subliniere atrag atentia programatorului asupra faptului ca aceste cuvinte cheie sunt posibile variabile interne, asm, _asm, case, _ds. O alta categorie de identificatori, apropiata de cea a cuvintelor cheie, este cea a identificatorilor utilizati in cadrul bibliotecilor incluse in programele C. Este buna evitarea utilizarii lor in alte contexte decit cele stabilite in cadrul bibliotecilor.

DECLARATII<home>
Toate variabilele folosite trebuie declarate inainte, cu toate ca anumite declaratii pot fi facute in functie de context. O declaratie specifica un tip si este urmata de o lista de una sau mai multe variabile de acelasi tip. int i,n; int i; sau int n; char c,linie[80]; char c; char linie[80]; Variabilele pot fi initializate chiar in momentul declaratiei lor, cu toate ca exista anumite restrictii. char backslash=\\; int i=0; float eps=1.0e-5; Daca variabila in discutie este externa sau statica, initializarea are loc o singura data, inainte ca programul sa-si inceapa executia. Variabilele automate initializate explicit sunt initializate la fiecare apel al functiei in care sunt continute.

TIPURI FUNDAMENTALE<home>

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia02.html (2 of 5)10/2/2005 8:13:37

Lectia 2

Tipurile de date se pot imparti in 2 categorii : tipuri fundamentale si tipuri derivate. Tipurile fundamentale ale limbajului C sunt: a). char reprezinta tipul caracter pe un octet; b). int reprezinta tipul intreg pe 2 octeti; c). long - reprezinta tipul intreg pe 4 octeti; d). float reprezinta numar real pe 4 octeti; e). double - reprezinta numar real pe 8 octeti; Aceste tipuri fundamentale admit diferite variante numite tipuri de baza de date. Aceste tipuri de date sunt: Tip
char unsigned char signed char int unsigned int signed int short int unsigned short int signed short int long int signed long int unsigned long int float double

Reprezentare (in biti)


8 8 8 16 16 16 16 16 16 32 32 32 32 64

Domeniu
-128127 0255 -128127 -3276832767 065535 -3276832767 -3276832767 065535 -3276832767 -21474836482147483746 -21474836482147483746 04294967295 3.4E-383.4E+38 1.7E-3081.7E+308

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia02.html (3 of 5)10/2/2005 8:13:37

Lectia 2

long double

80

3.4E-49321.1E+4932

MASIVE<home>
Masivele de date sau tablourile, din randul carora provin vectorii si matricile, sunt tipuri de date foarte apropiate pointerilor si referintelor. Tablourile sunt definite prin intermediul perechilor de paranteze "[" si "]". char linie[80]; Acest exemplu defineste "linie" ca fiind un sir de 80 de caractere si in acelasi timp "linie" va constitui un pointer la caracter. Daca pc este un pointer la un caracter, declarat prin char pc atunci atribuirea pc=&linie[0]; face ca pc sa refere primul element al tabloului "linie" ( de indice zero ). Aceasta inseamna ca pc contine adresa lui linie[0]. Acum, atribuirea c=*pc va copia continutul lui linie[0] in c. Trebuie tinuta seama de diferenta ce exista intre numele unui tablou si un pointer. Un pointer este o variabila astfel ca pc=linie si pc++ sunt operatii permise. In schimb un nume de tablou este o constanta si nu o variabila, iar constructiile de tipul linie=pc sau linie++ sunt interzise. Singurele operatii permise a fi efectuate asupra numelor masivelor, in afara celor de indexare, sunt cele care pot actiona asupra constantelor. Este posibila definirea masivelor multidimensionale cu ajutorul tablourilor de tablouri. char ecran[25][80]; Tablourile sunt memorate pe linii. Prima dimensiune a unui masiv se foloseste numai pentru a determina spatiul ocupat de acesta, ea nefiind luata in consideratie decat la determinarea unui element de indici dati. Este permisa omiterea primei dimensiuni a unui tablou, daca tabloul este extern, alocarea facinduse in cadrul altui modul, sau cand se efectueaza initializarea tabloului in declaratie, in acest ultim caz fiind determinata dimensiunea din numarul de elemente initializate. Initializarea masivelor poate avea loc chiar in cadrul declararii acestora. int point[2]={10,19}; char mesaj[6]="Salut";

ENUMERARI<home>
Tipurile enumerate sunt introduse prin sintaxa : enum nume {membru1,membru2,} var1,var2,; enum culori {ROSU,VERDE,ALBASTRU};

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia02.html (4 of 5)10/2/2005 8:13:37

Lectia 2

culoare_punct,culoare_linie; enum culori culoare_cerc,culoare_fond; Acest exemplu defineste tipul de data culori si declara variabilele culoare punct si culoare linie, urmate de declararile a inca doua variabile, culoare cerc si culoare fond . In limbajul C , numele ce urmeaza cuvantului "enum" este chiar numele tipului de data si nu o eticheta de tip. Daca nu exista riscul aparitiei confuziilor, este permisa declararea variabilei si prin suntaxa urmatoare: culori cerneala; Membrii unui tip enumerat sunt numai de tip intreg. Valoarea fiecaruia este obtinuta prin incrementarea cu 1 a valorii membrului anterior; primul membru avand implicit valoarea 0. Este permisa initializarea unui membru cu o valoare oarecare, avandu-se in vedere ca doi membri ai aceluiasi tip nu pot avea aceeasi valoare.Valorile membrilor urmatori se vor stabili conform regulilor mentionate . enum ANOTIMP {iarna=1,primavara,vara,toamna}; enum BOOLEAN{fals,adevarat} conditie; enum DIRECTIE{up,down,right,left,none=0}; // ilegal Putem defini tipuri enumerate fara a specifica numele acestora. Procedand astfel putem grupa un set de constante fara a denumi acea multime. enum {bine,foarte_bine,cel_mai_bine}; In ceea ce priveste utilizarea variabilelor de tip enumerat, limbajul C permite atribuiri de tipul conditie=0, dar acest tip de atribuiri genereaza avertismente din partea compilatorului. Este bine ca astfel de atribuiri sa fie insotite de conversia de tip corespunzatoare. conditie=fals; conditie=(enum BOOLEAN)0; Datele de tip enumerat definite in interiorul structurilor C nu sunt vizibile in afara acestora. Structurile sunt cele introduse prin cuvintele cheie struct, union.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia02.html (5 of 5)10/2/2005 8:13:37

Lectia 3

LECTIA 3 TIPURI DE DATE DERIVATE


Obiective Prezentare generala Pointeri Structuri Referinte Utilizarea constructiei typedef Definirea constantelor Masive Conversii de tip

OBIECTIVE <home>
G G G G G G

examina componentele ce formeaza un tip de data pointer; studia structurile; studia masivele de structuri; examina conversiile de tip; examina utilizarea constructiei typedef; examina definirea constantelor.

PREZENTARE GENERALA <home>


Scopul acestei lectii este acela de a prezenta utilizarea in C a pointerilor, referintelor, masivelor, conversiilor si a definirii constantelor in vederea construirii unor programe cat mai flexibile folosindu-ne de ceea ce ne ofera limbajul C si care il deosebeste fata de celelalte limbaje de programare de nivel inalt - folosirea pointerilor si a referintelor. Prin utilizarea acestora utilizatorul poate avea control asupra anumitor locatii de memorie, organizandu-si mai bine algoritmul de implemnetare, pentru realizarea unei cat mai mari flexibilitati si portabilitati a programului. Pe langa acestea, limbajul C mai contine in arhitectura sa si alte tipuri derivate foarte des utilizate in scrierea programelor si anume structurile, uniunile si masivele de structuri. Utilizand aceste concepte proprii lui C, programatorul poate construi algoritmi foarte complecsi prin definirea unor structuri noi de date diferite de cele fundamentale. De exemplu, odata definita o structura, aceasta va constitui un nou tip de data, putandu-se defini in continuare pointeri la acea structura, masive ale caror elemente sunt de tipul acestei structuri si, chiar mai mult, elemente de acest tip pot interveni in defiinirea acestor structuri.

POINTERI<home>

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (1 of 14)10/2/2005 8:13:41

Lectia 3

Pentru a putea defini notiunea de pointer, se impune clarificarea notiunii de variabila in limbajele de programare. Variabila este o locatie de memorie care poate memora un obiect, ales dintr-o colectie de obiecte, manevrat in cadrul unui program. Multimea este domeniul de definitie al variabilei, iar locatia este o zona de memorie capabila sa memoreze orice valoare din domeniul de definitie. Referirea la o variabila se realizeaza prin:
G G G

utilizarea identificatorilor; expresiile selectoare; expresiile referinta.

Folosirea exacta a numelui simbolic necesita cunoasterea echivalentelor acestuia pe nivelul conceptual si cel al implementarii. Conceptual, legand notiunea de variabila de existenta unei locatii de memorie, apare o dubla ipostaza a variabilei: cea de pastratoare de date si cea de data insasi, deoarece identificarea locatiei reprezinta o informatie si implicit o data. La nivelul implementarii, unei variabile i corespunde o zona din memoria calculatorului. Conform celor relatate mai sus este evidenrt de ce unei variabile i corespunde doua valori:
G G

stanga (l -value), data de adresa zonei de memorie (referinta); dreapta (r -value), valoarea mamorata in zona respectiva (conform figurii de mai jos).

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (2 of 14)10/2/2005 8:13:41

Lectia 3

In cazul tablourilor, se va memora si un descriptor (sablon al elementelor memoratre in acesta). Asa cum se va vedea in continuare, exista situatii in care aceeasi zona de memorie poate avea mai multe nume simbolice, acesta fiind cazul structurilor union. Un pointer este o variabila care contine adresa unei alte variabile, de orice tip. Pentru a defini un pointer, vom specifica tipul datei a carei adresa urmeaza sa o memoreze. int *ip; // Pointer catre un intreg char **s; // Pointer la un pointer pe caractere Datorita acestui aspect, este clar ca, cel putin in procesul de transmitere al parametrilor unei functii, codul utilizand pointeri este mult mai compact decat codul creat fara utilizarea lor, prin intermediul pointerilor fiind posibila adresarea oricarei variabile referite de acestia. In acest context, sa consideram o variabila de tip i si un pointer, pi, catre un intreg. Cum operatorul & furnizeaza adresa unei variabile, instructiunea pi=&i asigneaza variabilei pi adresa lui i (conform figurii de mai sus). Un alt operator unar ce insoteste clasa pointerilor este *, acesta furnizand continutul locatiei de memorie de la adresa indicata de operandul sau, deci de catre un pointer. Astfel, daca j este tot un int atunci j=*pi asigneaza lui j continutul locatiiei indicate de pi. In acest context, are loc urmatoarea echivalenta: j=*pi; <=> j=i aceste atribuiri fiind precedate de : int i,j; int *pi; pi=&i; Pointerii pot aparea in expresii. De exemplu, daca pi indica pe i deci contine adresa lui i, atunci *pi poate aparea in orice context in care ar putea aparea i, cum ar fi : j=*pi+1; // adica j=i+1; printf("%d\n",*pi); d=sqrt((duoble)*pi); In expresii ca: j=*pi+1; operatorii unari * si & sunt prioritari fata de cei aritmetici, altfel, aceasta expresie aduna 1 si asigneaza valoarea obtinuta lui y ori de cate ori pointerul pi avanseaza.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (3 of 14)10/2/2005 8:13:41

Lectia 3

Referiri prin pointeri pot aparea si in membrul stang al atribuirilor. Daca pi contine adresa lui i atunci *pi=0 il pune pe i ca 0, iar pi+=1 il incrementeaza pe i ca si (pi)++. In acest ultim exemplu, parantezele sunt necesare, fara ele expresia incrementand pe pi in loc sa incrementeze ceea ce indica pi, deoarece operatorii unari = si + sunt evaluati de la dreapta la stanga. In sfarsit, deoarece pointerii sunt variabile, ei pot fi manevrati ca orice alta variabila. Daca pj este un alt pointer la int, atunci pj=pi; copiaza continutul lui pi in pj, astfel ca pj se modifica odata cu pi. Pointerii pot fi si catre elemente fara tip, void. Putem atribui unui pointer void valoarea unui pointer non-void, fara a fi necesara o operatie de conversie de tip, typecast. char *cp; // Pointer catre un caracter void *vp; // Pointer catre void

MASIVE<home>
Masivele de date sau tablourile, din randul carora provin vectorii si matricile, sunt tipuri de date foarte apropiate pointerilor si referintelor. Pe parcursul prezentarii se va demonstra ca orice operatie care poate fi rezolvata prin indexarea tablourilor poate fi rezolvata si cu ajutorul pointerilor. Versiunea de rezolvare cu pointeri este mai rapida decat cea cu masive. Tablourile sunt definite prin intermediul perechilor de paranteze " [ ]". De exemplu: declaratia char linie[80]; Defineste linie ca fiind un sir de 80 de caractere, si in acelasi timp, linie va constitui un pointer la caracter. Daca pc este un pointer la caracter, declarat prin char *pc; Atunci atribuirea pc=&linie[0];
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (4 of 14)10/2/2005 8:13:41

Lectia 3

face ca pc sa refere primul element al tabloului linie (de indice 0); aceasta inseamna ca pc contine adresa lui linie[0]. Acum, atribuirea c=*pc; va copia continutul lui linie[0] in c. Daca pc indica un element oarecare a lui linie, atunci prin definitie, pc+1 indica elementul urmator si, in general, pc-i indica cu i elemente inaintea elementului indicat de pc, iar pc+i cu i elemente dupa acelasi element. Astfel, daca pc indica elementul linie[0], *(pc+1) refera continutul lui linie[1], pc+i este adresa lui linie[i], iar *(pc+i) este continutul lui linie[i]. Aceste remarci sunt adevarate indiferent de tipul variabilelor din tabloul linie. Definitia adunarii unitatii la un pointer si, prin extensie, toata aritmetica pointerilor consta, de fapt, in calcularea dimensiunii memoriei ocupate de obiectul indicat. Astfel, in pc+i, i este inmultit cu lungimea obiectelor pe care le refera pc inainte de a fi adunat la pc. Corespondenta intre indexare si aritmetica pointerilor este, evident, foarte stransa. De fapt, referinta la un tablou este convertita de compilator intr-un pointer spre inceputul tabloului. Efectul este ca, numele unui tablou este o expresie de tip pointer. Aceasta are cateva implicatii utile. Din moment ce numele unui tablou este sinonim cu locatia elementului sau zero, asignarea: pc=&linie[0]; poate fi scrisa si pc=linie; Trebuie tinut seama de o diferenta ce exista intre numele unui tablou si un pointer. Un pointer este o variabila, astfel ca pc=linie si pc++ sunt operatii permise. In schimb, un nume de tablou este o constanta si nu o variabila, constructii de tipul linie=pc sau linie++ fiind interzise. De fapt, singurele operatii permise a fi efectuate asupra numelor masivelor, in afara celor de indexare, sunt cele care pot actiona asupra constantelor.

ARITMETICA ADRESELOR.C este consistent si constant cu aritmetica pointerilor, pointerii,


tablourile si aritmetica adresarii constituind unul din punctele forte ale limbajului. C garanteaza ca nici un pointer care contine adresa unei date nu va contine valoarea 0, valoare rezervata semnalelor de eveniment anormal. De fapt aceasta valoare este atribuita constantei simbolice NULL pentru a indica mai clar, aceasta este o valoare speciala pentru un pointer. In general, intregii nu pot fi asignati pointerilor, zero fiind un caz special.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (5 of 14)10/2/2005 8:13:41

Lectia 3

Exista situatii in care pointerii pot fi separati. Daca p si q indica elemente ale aceluiasi tablou, operatorii <,>,=, etc., lucreaza conform asteptarilor. P<q este adevarata, de exemplu in cazul in care p indica un element anterior elementului pe care il indica q. Relatiile == si != sunt si ele permise. Orice pointer poate fi testat cu NULL dar nu exista nici o sansa in a compara pointeri situati in tablouri diferite. Mai poate sa apara si situatia nefericita in care codul va merge pe un echipament, si sa nu functioneze pe altul.

TABLOURI MULTI-DIMENSIONALE. Este posibila definirea masivelor multidimensionale


cu ajutorul tablourilor de tablouri: char ecran[25] [80]; exceptie facand tablourile de referinte, acestea din urma nefiind permise, datorita faptului ca nu sunt permisi pointeri la referinte. Tablourile sunt memorate pe linii, si deci, ultimii, de la stanga la dreapta, indici variaza mai repede decat primii. Prima dimnesiune a unui masiv se foloseste numai pentru a determina spatiul ocupat de acesta, ea nefiind luata in consideratie decat la determinarea unui element de indici dati. Este permisa omiterea primei dimensiuni a unui tablou, daca tabloul este extern, alocarea facandu-se in cadrul altui modul, sau cand se efectueaza initializarea tablolui in declaratie, in acest ultim caz fiind determinata dimensiunea din numarul de elemente initializate. Initializarea masivelor poate avea loc chiar in cadrul declararii acestora: int point[2]={10,19}; char mesaj1[6]={'S','a','l','u','t','\0'}; char mesaj2[6]="Salut"; Se observa ca sirul de caractere al lui mesaj1 are 6 caractere avand drept terminator de sir caracterul nul. Diferenta intre cele doua siruri nu se afla in continutul lor, ci in cadrul initializarii lor. In cazul initializarii prin acolade, { }, caracterul nul nu este subinteles, prezenta acestuia ramanand la dispozitia utilizatorului, in schimb, folosind ghilimelele va trebui sa dimensionam corespunzator sirul de caractere, tinand cont de prezenta terminatorului de sir.

STRUCTURI<home>
Limbajul C poseda inca un tip derivat de date care este utilizat intens in elaborarea programelor si care
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (6 of 14)10/2/2005 8:13:41

Lectia 3

este foarte apreciat. Este vorba despre strctura (struct) care incapsuleaza unul sau mai multe elemente. Spre deosebire de masiv unde elementele sunt toate de acelasi tip, la structura elementele, denumite membrii, pot fi de tipuri diferite. Deci, o structura este o colectie de date, eventual de tipuri diferite, si care pot fi referite atat separat, cat si impreuna. Definirea unei structuri se face cu cuvantul cheie struct. De exemplu: struct Coordinate { Int x; Int y; } Structura a carei denumire este Coordinate este formata din doi membrii, x si y fiecare de tipul intreg. struct punct { float x,y;} p; S-a definit p ca fiind de tip punct, punctul fiind compus din doua elemente reale x si y. Declaratia unei structuri se va termina in mod obligatoriu cu punct si virgula. Asupra elementelor unei structuri putem actiona prin intermediul operatorului de apartenenta , ".". p.x=10; p.y=30; Exista posibilitatea efectuarii de opeartii cu intreaga structura, atribuirea fiind una dintre ele: p={10,30}; O declaratie de structura care nu este urmata de o lista de variabile, nu produce alocarea memoriei, ci descrie organizarea structurii. Membrii unei strcturi pot avea tipuri diverse. Poate aparea ciudat, insa un membru al unei structuri, o eticheta sau o variabila simpla pot avea acelasi nume, fara a da ocazia unei ambiguitati. Acesta se dataoreaza operatorului ".", acesta legand numele membrului de numele structurii. Odata definita o structura, aceasta va constitui un nou tip de data, putandu-se defini in continuare pointeri la acea structura, masive ale caror elemente sunt de tipul acestei structuri si, chiar mai mult, elemente de acest tip pot interveni in definirea altor structuri. struct record { char name[40];

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (7 of 14)10/2/2005 8:13:41

Lectia 3

char address[64]; float weight; } Primii trei membrii sunt masive, iar al patrulea este un float. Numele record este de fapt un sablon (template) pentru obiectele cu care se va lucra. Definirea propriu-zisa inca nu a fost facuta. Ca sa alocam realmente spatiu vom proceda astfel: struct record rec; Initializarea membrilor "variabilei" rec se face prin intermediul functiei strcpy in felul aratat in continuare: ....... struct Record rec; strcpy(rec.name, "Rozor Cristian"); ... rec.weight=145; ... Un alt aspect al utilitatii structurilor il constituie tratarea tablourilor de structuri. De exemplu: punct hexagon[6]; punct octogon[8]; Accesul catre membrii componenti ai fiecarui element al unui vector se realizeaza prin combinarea celor doua sintaxe, cea indexata, caracteristica masivelor, cu cea utilizata in cazul structurilor: hexagon[i].x=10; In cazul definirii unui pointer la o structura, accesul la componentele acestei structuri se va efectua prin expresii de forma: punct *pptr; pptr->x=10; //echivalent cu p.x=10; (*pptr).y=30 //echivalent cu p.y=30; parantezele neavand decat rolul de a indica ordinea in care actioneaza cei doi opeartori, "*" si ".", prioritar fiind "*".

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (8 of 14)10/2/2005 8:13:41

Lectia 3

UTILIZAREA CONSTRUCTIEI typedef <home>


Un mod de a evita utilizarea cuvintelor enum, struct sau union in cadrul programelor C este de a defini tipul de data. Pentru aceasta vom utiliza typedef. Typedef struct {float x,y;} punct; pentru a defini noul tip de data, si apoi, il vom utiliza in declararea variabilelor. Punct p; Asa cum s-a vazut in exemplele anterioare, in C typedef nu mai este necesar in astfel de situatii, C considerand numele tipurilor de date ca fiind identificatorii utilizati in definirea agregatelor de tipuri. Deci, in C putem scrie: struct punct {float x,y;}; urmand ca variabilele sa fie declarate prin: punct p; Exista totusi situatii diferite de cele anterioare, in care instructiunea typedef isi dovedeste utilitatea. Acestea sunt cazurile in care dorim sa definim tipuri sinonime de date, de regula prescurtari ale tipurilor recunsocute. Exemple: typedef unsigned int ui; // Defineste tipul ui typedef char *string; // Defineste tipul string In implementarea ANSI C , pentru a defini o structura trebuie folosit cuvantul cheie struct. Spre exemplu presupunand ca exista sablonul point se poate defini obiectul mypoint astfel: struct Point mypoint; sau se mai poate scrie point mypoint;

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (9 of 14)10/2/2005 8:13:41

Lectia 3

sau se poate recurge la constructia urmatoare pentru mai multa flexibilitate typedef <type> Name; adica se atribuie numelui simbolic Name tipul de data type care va putea fi apoi utilizat in locul acelui tip. typedef struct tagPoint { Int x,y; } point; Ceea ce s-a scris mai sus este o declaratie si anume: se atrbuie numelui simbolic Point tipul struct. Insa obiectul declarat trebuie sa aiba un nume. Pentru aceasta s-a ales tagPoint. Dupa aceasta in cadrul programului se va defini variabila p sau mypoint astfel: point p,mypoint; Compilatorul, in schimb va vedea de fapt o linie de cod de genul urmator: struct tagPoint p,mypoint;

CONVERSII DE TIP <home>


Conversiile de tip se pot realiza atat implicit, cat si explicit. Un exemplu de situatie in care are loc conversia implicita este aceea in care este asteptat un intreg si apare un caracter.. Lucrurile, in acest caz, se desfasoara fara complicatii, dar nu totdeauna avem situatii atat de simple. De aceea este de preferat a se utiliza conversiile explicite in locul celor implicite. De exemplu: int i=8,j=9; double d; d=(double)i; // in sintaxa C Totusi, deosebirea majora intre cele doua variante nu consta in forma, ci in faptul ca C permite conversii la tipuri definite de utilizatori asemeni apelurilor de functii, ANSI C neavand acesta capacitate. Cand intr-o expresie apar operanzi de mai multe tipuri, ei se convertesc intr-un tip comun, dupa un numar restrans de reguli. In general, singurele conversii care se fac automat sunt acelea cu sens, de exemplu, convertirea unui numar intreg intr-un flotant in expresii de tipul f+i. Expresiile fara sens, de exemplu, folosirea lui float ca indice de tablou este interzisa.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (10 of 14)10/2/2005 8:13:41

Lectia 3

In primul rand char si int pot fi amestecati in expresiile aritmetice, orice char fiind convertit intr-un int. Aceasta permite o flexibilitate remarcabila in anumite tipuri de transformari de caractere. De exemplu prezentam functia atoi() care converteste un sir de cifre in echivalentul lor numeric: atoi (char s[]) //converteste un sir s intr-un intreg { int i,n=0; for (i=0; s[i]>='0'&& s[i]<='9';++i) n=10*n+s[i]-'0'; return n; } Expresia: s[i]-'0' reprezinta valoarea numerica a caracterului aflat in s[i] deoarece valorile lui 0, 1, etc., formeaza un sir crescator, pozitiv si continuu. In general daca un operator binar ca + sau *, are operanzi de tipuri diferite, tipul inferior este promovat la tipul superior inaintea executiei operatiei. .Rezultatul insusi este de tipul superior. Mai precis, pentru ficare operator aritmetic se aplica urmatoarea secventa de reguli de conversie: char si short se convertsec la int, iar float este convertit la double, iar rezultatul este double. Altfel, daca un operand este long, celalalt este convertit in long, iar rezultattul este long. Altfel daca un operand este unsigned, la unsigned este convertit si operandul celuilalt, iar rezultatul este tot unsigned. Altfel, operanzii trebuie sa fie de tip int, iar rezultatul este un int. Conversiile se fac si in asignari; valoarea membrului drept este converitita la tipul din stanga, care este tipul rezultatului. Un char este convertit intr-un int fie cu extensie de semn sau fara. int i; char c; i=c; c=i; valoarea lui c este neschimbata. Acest lucru este adevarat si cand extensia de semn este implicita si cand nu este implicita. Daca x este float si i este int, atunci: x=i;
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (11 of 14)10/2/2005 8:13:41

Lectia 3

i=x; provoaca amandoua conversii: float in int provoaca trunchierea oricarei parti fractiunare; double este convertit in float prin rotunjire. Intregii lungi sunt convertiti in scurti sau in char prin pierderea bitilor de ordin superior in exces. Deoarece argumentul unei functii este o expresie, conversia de tip are loc si cand argumentele sunt pasate functiei; in particular, char si short devin int, iar float devine double. Iata de ce se va declara argumentul unei functii ca fiind int si double, chiar daca functia este apelata cu char si float. In final, convesia explicita de tip poate fi fortata in orice expresie cu o constructie numita typecast. De exemplu, rutina din biblioteca, sqrt(), are nevoie de un argument double si va produce nonsens daca i se transmite altceva.. Astfel daca n este un intreg : sqrt((double)n); Sau sqrt(double(n)); Il converteste pe n in double, inainte de a-l pasa lui sqrt().

DEFINIREA CONSTANTELOR <home>


Definirea constantelor este ca si la variabile un proces de alocare de spatiu de memorie. Insa o constanta este exact opusa unei variabile, deoarece ea nu isi modifica valoarea dupa cum arata si denumirea.

CONSTANTE LITERALE.
Sunt constante a caraor valoare este precizata prin introducerea directa de la tastatura. Valoarea 1234 este o constanta de tip literal din punct de vedere C. Tot asa sunt si constantele 3.14159, "Afisarea unei date". Exista o varietate de formate pentru constante. Valorile intregi pot de exemplu sa fie exprimate in trei coduri si anume: zecimal, hexazecimal si octal. Constanta 255 este exprimata in cele trei moduri astfel: max=255; //zecimal max=0xFF //hexazecimal max==377 //octal Intregii zecimali contin cifre cuprinse intre 0 si 9. In hexa 0 - 9 si A - F, iar in octal 0 - 7. Valorile

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (12 of 14)10/2/2005 8:13:41

Lectia 3

constantelor lungi (long) trebuie sa fie insotite de litera L. asa cum este exemplificat mai jos: long population; population=655982L; Constantele in virgula mobila folosesc doua notatii, zecimala si stiintifica: float pi; pi=3.14159; //notatia zecimala Notatia stiintifica se prefera in contextul valorilor foarte mari sau foarte mici. De exemplu viteza luminii (in m/s) s-ar exprima astfel in aceasta notatie: float lightspeed; lightspeed=3E+8; ceea ce in notatia obisnuita (zecimala) ar corespunde valorii 30000000.0. O valoare foarte mica, spre exemplu 0,0000000043 se exprima 4.3E-9. Constanta tip sir de caractere este intotdeauna incadrata de ghilimele. printf("distanta este==%d\n",distanta); Constantele de tip caracter sunt incadrate de apostrofi, ca in exemplu: char ch; ch='Q'; Tipul de date char este de fapt un intreg cu valori intre 0..255. Deoarece caracterele sunt reprezentate prin intregi, acestia pot avea semn sau nu. De exemplu: signed char byte; byte=-87;

CONSTANTE SIMBOLICE.
O alta modalitate mai flexibila de a defini constante ce trebuiesc folosite global este de a folosi directiva define, ca in exemplul urmator: #define PI 3.14159 #define ANDROMEDA 130000
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (13 of 14)10/2/2005 8:13:41

Lectia 3

Aceste denumiri nu sunt variabile ci, numai simboluri pe care compilatorul le considera ca avand o alta semnificatie. Ele pot fi folosite oriunde acolo unde este contextual sa ne referim la literali in program. In exemplul: long diametrul_galaxiei; diametrul_galaxiei=ANDROMEDA; se atribuie de fapt constanta 130000 variabilei diametrul_galaxiei. Directiva #define are trei parti: cuvantul cheie, denumirea simbolica si valoarea. In mod traditional se obisnuieste ca denumirea sa fie mentionata cu majuscule. Directiva #define nu defineste obiectul de fapt. Ea defineste un nume simbolic pentru o valoare literala. La intalnirea denumirii respective compilatorul va inlocui (translitera) acel simbol cu literalul in sine.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia03.html (14 of 14)10/2/2005 8:13:41

Lectia 4

LECTIA 4 FUNDAMENTELE LIMBAJULUI C++ (III)


Obiective Prezentare generala Atributele datelor Accesibilitatea Clase de memorie Operatori Durata de viata Expresii conditionale

OBIECTIVE <home>
G G G G G

atributele datelor clase de memorie durata de viata accesibilitate operatori si expresii

PREZENTARE GENERALA <home> ATRIBUTELE DATELOR <home>


Orice data utilizata in cadrul limbajului C, poseda urmatoarele 5 caracteristici:
G G G G G

TIPUL se determina modul in care datele sunt memorate si operatiile permise cu cu acestea CLASA DE MEMORIE specifica locul in care sunt memorate datele DURATA DE VIATA reprezinta intervalul de timp in care acestea exista ACCESIBILITATEA reprezinta posibilitatea de a accesa date in programe multi-fisier SCOPUL reprezinta domeniul de vizibilitate a datelor

CLASE DE MEMORIE<home>
Acest atribut al datelor determina tipul de memorare asociat acestora. Exista 4 categorii de memorare, fiecare fiind specificat utilizand unul din urmatoarele cuvinte-cheie: auto date aflate in stiva. In mod implicit, toate variabilele si functiile locale apartin clasei de memorie auto. Astfel, ele apartin stivei asociate functiei apelate (stiva=bloc de memorie de dimansiune finita in care datele sunt tratate dupa principiul "ultimul venit este primul servit" ) si vor fi apelate in momentul apelului functiei si eliberate la iesirea din functie. register- date ce pot fi memorate intr-un registru al masinii. Deasemenea, o variabila register este si ea
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia04.html (1 of 4)10/2/2005 8:13:58

Lectia 4

locala functiei in care a fost definita, dar daca este posibil, va fi depusa intr-un registru al calculatorului. static date rezidente in modulul de definitie al acestora. Cuvantul-cheie static poate fi, de asemenea, utilizat asociat unor variabile interne oricarei functii. Astfel de variabile nu se regasesc in stiva dar se inscriu in clasa celor statice. Din acest motiv, ele exista pe toata durata executiei programului (asemeni variabilelor globale ), dar pot fi accesate numai in interiorul functiilor in care au fost definite. extern date definite intr-un modul extern. Aceasta clasa de memorie este rezervata datelor ce se afla in afara oricarei functii.

DURATA DE VIATA <home>


Acest atribut al datelor reprezinta intervalul de timp in care variabila exista, adica cat timp ii este rezervat spatiul in de memorie. Memoria poate proveni din trei surse:
G

in cazul variabilelor auto, durata de viata a acestor variabile va fi egala cu durata apelului functiei in cadrul careia au fost definite acestea; variabila va fi depusa in cadrul stivei asociate modulului de definitie sau intr-un registru al calculatorului. in cazul variabilelor statice, timpul de viata al acestora este egal cu timpul de executie al intregului program; aceste variabile se vor situa in segmentul de date al programului. memoria necesara stocarii unei variabile poate fi alocata dinamic de catre utilizator, caz in care durata de viata a acesteia este controlata de catre programator; variabila va fi depusa in memoria heap (memoria rezervata obiectelor dinamice).

ACCESIBILITATEA<home>
O etapa importanta in stabilirea domeniilor de accesibilitate este legarea atributelor la variabile.Exista doua momente in care se pot executa astfel de legaturi:
G G

la compilare, caz in care avem legare statica (legare interna) in momentul rularii programului, caz in care avem legare dinamica.

In plus, in situatia in care datele apartin unui alt modul si sunt utilizate in cel curent, acestea vor fi externe celui din urma, fapt pentru care, in acest modul, datele vor poseda legare externa. Spre deosebire de clasele de memorie, legarea atributelor actioneaza atat asupra variabilelor, cat si asupra functiilor.

OPERATORI<home>
In marea lor majoritate, actiunile desfasurate in cadrul oricarui program se datoreaza expresiilor formate prin combinatii de date si operatori.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia04.html (2 of 4)10/2/2005 8:13:58

Lectia 4

Operatorii limbajului C [] & / <= && %= ^= () * % >= || += |= . + << == ?: -= , -> >> != = <<= # ++ ~ < ^ *= >>= ## ->* -! > | /= &= sizeof

In functie de numarul de operanzi, operatorii se pot clasifica in trei categorii:


G G G

operatori unari - cu un operand operatori binari - cu doi operanzi operatori ternari - cu trei operanzi

Precedenta operatorilor in C PRIORITATE 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. OPERATORI ( ) [ ] -> . ! ~ + - ++ -- & * (tip) sizeof ->* */% +<< >> < <= > >= == != & ^ | && || ?: = *= /= %= += -= &= ^= |= <<= >>= , EVALUARE -> <-> -> -> -> -> -> -> -> -> -> -> <<->

EXPRESII CONDITIONALE <home>


Instructiunea :
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia04.html (3 of 4)10/2/2005 8:13:58

Lectia 4

if (a<b) z=a; else z=b; calculeaza in z maximul dintre a si b. Limbajul C ofera o alternativa de a scrie acest lucru, cu ajutorul operatorului ternar ?: , precum si alte constructii similare. e1 ? e2 : e3 Expresia e1 se evalueaza prima; daca ea este adevarata, atunci se evalueaza expresia e2 si aceasta este valoarea expresiei conditionale; altmiteri, se evalueaza e3 si aceasta este valoarea expresiei. Numai una dintre expresiile e2 si e3 se evalueaza. De exemplu, pentru a pune in z maximul dintre a si b, folosind o expresie conditionala, vom proceda astfel: z= (a<b) ?b:a; Expresiile conditionale conduc adesea la un cod succint. De exemplu, bucla urmatoare tipareste n elemente ale unui tablou, 10 pe linie, cu fiecare coloana separata printr-un blanc si cu fiecare linie, inclusiv ultima, terminata cu un singur caracter linie noua. for (i=0;i<n;i) printf("%6d%c",a[i],(i%10==9||i==n-1)?'\n':' '); Un caracter linie noua se tipareste dupa fiecare al zecelea element si dupa fiecare al n-lea element.Toate celelalte elemente sunt urmate de un spatiu. Cu toate ca seamana cu un truc, este instructiv sa incercati sa scrieti lucrul acesta fara a folosi expresia conditionala.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia04.html (4 of 4)10/2/2005 8:13:58

Lectia 5

LECTIA 5 INSTRUCTIUNILE LIMBAJULUI C


Obiective Prezentare generala

OBIECTIVE <home>
Expresiile sunt utilizate in scrierea instructiunilor. O instructiune este o expresie care se incheie cu simbolul ";". Instructiunile pot fi scrise pe mai multe linii de program, spatiile nesemnificative fiind ignorate. Pe o linie de program putem scrie mai multe instructiuni, simbolul ";" fiind terminator de instructiuni. Instructiunile pot aparea in diferite forme: atribuiri, declaratii, instructiuni conditionale, de ciclare, de salt sau instructiuni compuse. Instructiunile limbajului C++ sunt: A) Instructiuni de nivel zero: H vida; H expresie; H compusa; B) Instructiuni conditionale: H if; H switch; H while; C) Instructiuni de ciclare: H for; H do-while; D) Instructiunea de transfer al controlului: H exit; H return; H continue; H break; H goto;

PREZENTARE GENERALA <home> INSTRUCTIUNI INSTRUCTIUNEA vida


file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia05.html (1 of 6)10/2/2005 8:13:57

Lectia 5

Se reduce la caracterul ";". Nu are nici un efect. Se utilizeaza frecvent in cadrul instructiunilor alternative si repetitive.

INSTRUCTIUNEA expresie
Se obtine scriind ";" dupa o expresie si are formatul: expresie; Daca expresia din compunerea unei instructiuni expresie este o expresie de atribuire, spunem ca instructiunea respectiva este o instructiune de atribuire. Un alt caz frecvent este cel in care expresia este un operand ce reprezinta apelul unei functii. In acest caz instructiunea expresie este o instructiune de apel a functiei respective. Observatie: nu orice expresie urmata de ";" formeaza o instructiune expresie efectiva. De exemplu a; desi este o instructiune expresie, ea nu are nici un efect.

INSTRUCTIUNEA compusa
Este o succesiune de instructiuni incluse intre acolade, succesiune care poate fi precedata si de declaratii: { declaratii instructiuni } Declaratiile aici definesc variabile.

INSTRUCTIUNEA if
Aceasta instructiune are urmatoarele formate: forma 1: if(expresie) instructiune
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia05.html (2 of 6)10/2/2005 8:13:57

Lectia 5

forma 2: if(expresie) instructiune1 else instructiune2 Observatie: modul de utilizare al instructiunii if din C este identic cu cel - cunoscut voua - din Pascal. Deoarece o instructiune compusa este considerata ca fiind un caz particular de instructiune, rezulta ca instructiunile din compunerea lui if pot fi instructiuni compuse. De asemenea instructiunile respective pot fi chiar instructiunea if. In acest caz se spune ca instructiunile if sunt imbricate.

INSTRUCTIUNEA exit
Are forma void exit(int cod) isi are prototipul in bibliotecile stdlib si process. La apelul acestei functii au loc urmatoarele actiuni:

G G G

se videaza zonele tampon ale fisierelor deschise in scriere; se inchid toate fisierele deschise; se intrerupe executia programului.

Valoarea 0 defineste o terminare normala a programului, iar o valoare diferita de 0 semnaleaza prezenta unei erori.

INSTRUCTIUNEA while
Are formatul: while (expresie) instructiune Este o instructiune ciclica conditionata anterior. Corpul instructiunii while este o singura instructiune, care poate fi compusa. Atunci cind sunt compuse spunem ca instructiunile while sunt imbricate.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia05.html (3 of 6)10/2/2005 8:13:57

Lectia 5

INSTRUCTIUNEA for
Este asemanatoare instructiunii while si se utilizeaza pentru a realiza o structura repetitiva conditionata anterior. Formatul ei este: for(exp1;exp2;exp3) instructiune

INSTRUCTIUNEA do-while
Realizeaza structura ciclica conditionata posterior. Aceasta instructiune poate fi realizata cu ajutorul instructiunilor definite pana in prezent. Prezenta ei in programe mareste flexibilitatea in programare. Are formatul: do instructiune while(expresie);

INSTRUCTIUNEA continue
Se poate utiliza numai in cazul unui ciclu. Ea permite abandonarea iteratiei curente. Formatul ei este: continue; Efectul este urmatorul:
G

in corpul instructiunii do-while se abandoneaza iteratia curenta si se trece la evaluarea expresiei care stabileste continuarea sau terminarea ciclului respectiv; in corpul instructiunii for se abandoneaza iteratia curenta si se trece la executia pasului de reinitializare.

Observatie: instructiunea continue conduce adesea la diminuarea nivelurilor de imbricare ale instructiunilor if utilizate in corpul ciclurilor.

INSTRUCTIUNEA break

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia05.html (4 of 6)10/2/2005 8:13:57

Lectia 5

Este inrudita cu instructiunea continue si are formatul: break; Mareste flexibilitatea la scrierea programelor in limbajele C.

INSTRUCTIUNEA switch
Permite realizarea structurii selective. Aceasta este o generalizare a structurii alternative. Ea poate fi realizata prin instructiuni if imbricate. Structura selectiva , in forma in care a fost acceptata, se realizeaza in C cu ajutorul urmatorului format: switch(expresie) { case c1: sir1 break; ......... case cn: sirn break; default: sir } Instructiunea break de la sfirsitul fiecarei alternative, permite ca la intilnirea ei sa treaca la executia urmatoarei instructiuni.

INSTRUCTIUNEA goto
Nu este o instructiune absolut necesara la scrierea programelor in C. Cu toate acestea ea se dovedeste utila in diferite cazuri.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia05.html (5 of 6)10/2/2005 8:13:57

Lectia 5

Formatul instructiunii: goto nume; -nume- eticheta definita in corpul aceleiasi functii in care se afla instructiunea goto. Prin eticheta intelegem un nume urmat de " : " ,dupa eticheta urmeaza o instructiune.

INSTRUCTIUNEA return
Admite doua forme: return; return(exp); Efectul consta in trecerea controlului la functia care a apelat functia respectiva fara transmiterea unei valori in prima varianta sau cu transmiterea unei valori in a doua varianta.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia05.html (6 of 6)10/2/2005 8:13:57

Lectia 6

LECTIA 6 FUNDAMENTE LIMBAJULUI C++ (v)


Obiective Prezentare generala

OBIECTIVE <home>
G G G

Scopul, vizibilitatea si tipul identificatorilor, Includerea enumerarilor, Declaratii

PREZENTARE GENERALA <home>


Asa cum am vazut, prin utilizarea instructiunilor compuse, putem obtine sectiuni de program in care identificatorii au asociate diferite atribute, accesibilitatea acestora fiind supusa acestor modificari. Acesti factori ce intervin in aceste procese sunt grupati in trei categorii : scop, vizibilitate si tipul numelui.

SCOPUL
Prin scopul unui identificator, intelegem acea portiune din program in care este valabila o legare a identificatorului de o entitate (obiect, variabila, constanta sau functie). In C exista cinci categorii de scop ale unui identificator :
G G G G G

bloc, functie, prototipul functiei, fisier, structura.

Scopul identificatorilor declarati in interiorul unui bloc se afla in acel bloc. Acest domeniu are drept punct de plecare momentul declaratiei identificatorului si se incheie odata cu inchiderea blocului. Atunci cand blocul contine subblocuri, scopul identificatorului nu contine si acele subblocuri. Prin bloc intelegem o instructiune compusa. In limbajul C o declaratie poate fi in interiorul unui bloc sau in afara blocurilor. Domeniu scopului de tip bloc este aria cuprinsa intr-o pereche de acolade.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia06.html (1 of 5)10/2/2005 8:13:58

Lectia 6

Majoritatea identificatorilor din cadrul unei functii au scopul de tip bloc. Lista parametrilor formali ai functiei intra in aceasta categorie. Domeniul scopului de tip functie se aplica numai etichetelor interioare unei functii. Prototipul functiei reprezinta declararea functiei in cauza. Prin prototip al unei functii intelegem o declaratie a acesteia, in care se fac cunoscute numele, tipul returnat si lista parametrilor sai ( ca numar, tip si ca identificatori ). Domeniul scopului de tip prototip al functiei se refera la lista parametrilor formali ai acesteia. Un nume declarat in afara oricarui bloc sau declaratie de clasa are un domeniu de tip fisier. Acest domeniu incepe in punctul in care numele este definit si tine pana la sfarsitul fisierului, care contine definitia respectiva. El poate fi utilizat in domeniul respectiv fara nici o restrictie daca nu este redefinit in blocurile incluse in domeniul sau. Daca un nume care are un domeniu de tip fisier este redefinit intrun bloc inclus in domeniul sau, atunci el poate fi folosit, in acel bloc, daca este precedat de operatorul de rezolutie. Deci, domeniu al scopului de tip fisier este domeniul exterior functiilor si declaratiilor de clasa. Ultima categorie a scopului este cea in care scopul cuprinde declaratia unei clase. Membrii unei clase au drept scop acea clasa, iar numele lor sunt ascunse restului programului. In cazul structurilor si uniunilor, care sunt forme speciale ale claselor, scopul membrilor acestor tipuri de date se inscrie in categoria clasei. Numele clasei nu are drept scop acea clasa, ci se stabileste in functie de locul declaratiei clasei respective. Identificatorii care nu se afla in blocuri, functii sau clase, au ca domeniu al scopului intregul fisier. Acesta este delimitat de declaratia identificatorului, pe de o parte, iar pe de cealalta parte, de sfarsitul fisierului. Daca identificatorul se afla intr-un fisier header, scopul acestuia va fi de tip fisier si va cuprinde orice fisier ce include headerul respectiv.

VIZIBILITATEA
Vizibilitatea unei variabile este o caracteristica ce defineste partile unui program, care vor putea recunoaste variabila respectiva. Astfel, o variabila poate fi recunoscuta in interiorul unui bloc, al unui fisier, al unui grup de fisiere sau in tot programul. Un identificator este recunoscut in domeniul sau, daca nu este redefinit in blocuri incluse in domeniul respectiv. Un identificator redefinit in blocuri din domeniul sau, devine temporar ascuns. Un identificator cu domeniul de tip fisier poate fi facut vizibil in domeniul in care este redefinit, folosind operatorul de scop : " :: " , iar daca identificatorul respectiv este numele unei clase, atunci el va fi precedat de cuvantul cheie corespunzator : class, struct sau union. Prin urmare, domeniul de vizibilitate al unui identificator este acea parte a domeniului sau in care el poate fi utilizat.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia06.html (2 of 5)10/2/2005 8:13:58

Lectia 6

Numele utilizate in C se impart in patru mari categorii:


G G G G

etichete de instructiuni, etichete de structuri, uniuni si enumerari, nume ale membrilor tipurilor agregate ( structuri, uniuni), functii, variabile, nume introduse prin typedef si membri ai enumerarilor.

Doi identificatori pot avea acelasi nume si apartine aceleasi categorii a numelui, in cazul in care au scopuri diferite. In exemplul urmator, sunt utilizate doua declaratii ale structurii punct in functii diferite, deci, cu scopuri distincte:
void func1 ( ) { struct punct { int x, y ; }; ........ } void func2 ( ) { enum punct { simplu, dublu }; ........ }

Doi identificatori nu pot avea aceeasi denumire daca se afla in acelasi domeniu al scopului si apartin aceleiasi categorii a numelui. In exemplul de mai jos, sunt utilizate doua declaratii ale structurii punct in aceeasi functie, ceea ce este ilegal, avand un duplicat al numelui.
void func ( ) { struct punct { int x, y ;}; enum punct { simplu, dublu }; }

In cazul in care numele a doi identificatori fac parte din categorii diferite ale numelui, nu conteaza ce domeniu al scopului au. Deasemenea, acestia pot avea aceeasi denumire, fara a exista riscul aparitiei de erori sau confuzii. Spre exemplu, in cadrul unei functii putem avea o variabila x si o eticheta cu acelasi nume, deci tot x.
void func (int x)

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia06.html (3 of 5)10/2/2005 8:13:58

Lectia 6

{ if (x==5) goto x; cout << "NOT "; x: cout << " EQUAL \n"; }

INCLUDEREA ENUMERARILOR
In C este posibila declararea unei enumerari si a unei variabile, avand acest tip in cadrul unei structuri.
struct luna { enum sapt {luni,marti,miercuri,joi,vineri,sambata,duminica} zile[7]; int numar_zile };

Astfel, am declarat sapt ca fiind o enumerare si zile un vector de elemente de tip sapt. Deorece in C, scopul numelui unei enumerari declarate in interiorul unei structuri depaseste granitele acelei structuri, sapt nu este ascuns exteriorului structurii, pe cand zile este. Altfel scris, exemplul de mai sus va arata:
enum sapt { luni, marti, miercuri, joi, vineri, sambata, duminica }; struct luna { enum sapt zile[7]; int numar_zile; };

Pentru a accesa un tip enumerat in interiorul unei structuri, va trebui sa utilizam operatorul de scop si sa completam numele tipului cu numele structurii:
enum luna::sapt x; x=luna::marti;

In acest caz, operandul drept al operatorului de scop indica identificatorul sau numele tipului, iar operatorul stang desemneaza scopul, acesta putand fi numele oricarei clase, structuri sau uniuni. Aceasta metoda de accesare este disponibila numai in cazul in care tipul enumerat este declarat public si nu se afla in sectiunea privata a clasei. Asa cum se aplica asupra structurilor, si asupra claselor si uniunilor se poate aplica regula ascunderii enumeratelor.

DECLARATII IN C++
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia06.html (4 of 5)10/2/2005 8:13:58

Lectia 6

O declaratie specifica un tip si este urmata de o lista de una sau mai multe variabile de acel tip. Declaratiile pot aparea in unul din urmatoarele contexte:
G G G

declaratii de variabile, declaratii de tipuri de date, sau prototipuri de functii.

Regulile de utilizare a variabilelor sunt:


G G G G G

Putem declara variabilele acolo unde avem nevoie de ele, la inceputul buclei . Putem declara variabilele in interiorul unor blocuri. Nu avem voie sa folosim duble declaratii. O declarare o putem completa cu o initializare (int i=0;). Declararea se face in interiorul blocului ciclului.

int i; // Declaratie de variabila nt i=5; // Declaratie de variabila si initializare struct ceas { // Declaratie de tip data int sec ; ceas (int s); void oms( int &ore, int &minute, int &secunde ); }; int aduna(int a,int b ); // Prototip de functie

In cadrul celei de-a doua declaratie este permis ca pe langa specificarea tipului variabilei, sa se efectueze chiar si initializarea acesteia. Aceste declaratii seamana cu instructiunile de atribuire, dar nu sunt atribuiri. Diferenta intre atribuiri si initializari consta in aceea ca, in timp ce atribuirile efectueaza o simpla incarcare de memorie a unei valori, in cadrul initializarilor de acest tip este specificat si tipul variabilei. Declaratiile pot fi plasate atat in interiorul blocurilor, cat si in exteriorul acestora, si au ca scop intreg fisierul. Acestea pot fi plasate oriunde in cadrul acestuia, chiar daca, de obicei, aceste declaratii se afla chiar la inceputul fisierului. Nu este permisa dublarea declaratiei unei variabile in cadrul aceluiasi domeniu al scopului. Prin plasarea declaratiilor in interiorul ciclului, scopul va fi local, deci in interiorul blocului ciclului.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia06.html (5 of 5)10/2/2005 8:13:58

Lectia 7

LECTIA 7 FUNCTII (I)


Obiective Prezentare generala

OBIECTIVE <home>
G G G G

Fundamente, Functii care returneaza non-intregi. Argumentele functiilor. Argumentele liniei de comanda.

PREZENTARE GENERALA <home>


In acest laborator se vor studia avantajele utilizarii functiilor in limbajul programare C++ si principalele caracteristici ale acestora. Scopul laboratorului este de a utiliza functiile C si de a oferi un suport programatorilor in programarea orientata pe obiecte. Limbajul C a fost proiectat pentru a face functiile eficiente siusor de folosit, programele C constau,in general,.mai degraba,din numeroase functii mici decit din functii mari. Un program poate fi compus din unul sau mai multe fisiere sursa,acestea putind fi compilate separat si incarcate impreuna,impreuna cu alte functii compilate anterior,care se gasesc in biblioteci. Aceste functii trunchiaza programele mari in mai multe programe mici si permit programatorului sa construiasca incepind de la ceea ce au facut altii deja,in loc de a porni totul de la inceput.

FUNDAMENTE
Fiecare functie C este de forma:
tip_returnat nume (declaratii_argumente, daca exista) { declaratii si instructiuni, daca exista }

Asa cum am sugerat, anumite parti pot sa lipseasca, functia minima fiind
nimic() { }

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (1 of 7)10/2/2005 8:13:59

Lectia 7

care nu face nimic. (O functie care nu face nimic este utila uneori ca loc pastrat pentru dezvoltari ulterioare in program). Numele functiei poate fi, de asemenea, precedat de un tip, daca functia returneaza altceva decat o valoare intreaga. (Acesta este subiectul urmatoarei sectiuni). Obs.:Un program este tocmai un set de definitii de functii individuale. Comunicarea intre functii este (in acest caz) facuta prin argumente si valori returnate de functii. Ea poate fi facuta, de asemenea, prin variabile externe. Functiile pot aparea in orice ordine in fisierul sursa, iar programul sursa poate fi spart in mai multe fisiere. In schimb o functie nu poate fi sparta in mai multe fisiere. Instrunctiunea return este mecanismul de returnare in apelant a unei valori din functia apelata. Orice expresie poate urma dupa instructiunea return:
return (expresie)

sau
return expresie

Functia apelanta este libera sa ignore valoarea returnata,daca doreste.Mai mult, nu e necesar sa existe o expresie dupa return,caz in care nu va fi returnata nici o valoare apelantului.Totusi, compilatorul va avertiza asupra acestui fapt. Controlul este, de asemenea, returnat apelantului, fara nici o valoare,atunci cand executia functiei apelate atinge cea mai din dreapta acolada. Nu este ilegal ca o functie sa returneze o valoare intr-un loc si nici o valoare din altul. In orice caz , valoarea unei functii care nu returneaza nici una este sigur un non-sens.Mecanismul prin care se compileaza si se incarca un program al carui cod este format prin compunerea mai multor fisiere sursa variaza de la un sistem la altul.

Functii care returneaza non-intregi


Daca un nume care nu a fost declarat apare intr-o expresie si este urmat de o paranteza stanga, el este declarat prin context ca fiind nume de functie. Mai mult, implicit se presupune ca o functie returneaza un int. Deoarece char se transforma in int in expresii,nu e nevoie sa declaram functiile care returneaza char. Aceste prezumptii acopera majoritatea cazurilor, inclusiv o mare parte din elementele de acum. Dar ce se intampla daca o functie trebuie sa returneze o valoare de alt tip? Multe functii numerice, ca sqrt(), sin(), cos(), returneaza double; alte functii specializate returneaza alte tipuri. Pentru a ilustra modul lor de folosire vom scie si vom folosi o functie atof(s) care converteste sirul s in echivalentul lui in dubla precizie; atof() este o prezenta sau o absenta atat a partii intregi, cat si a partii fractionare. In primul rand, atof() insasi trebuie sa declare tipul valorii pe care o va returna, deoarece acesta nu este

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (2 of 7)10/2/2005 8:13:59

Lectia 7

int. Deoarece float este convertit in double in expresii, nu are nici un rost sa spunem ca atof() returneaza un float; putem, la fel de bine, sa facem uz de precizie suplimentara si sa declaram ca ea returneaza double. Numele tipului precede numele functiei, ca in :
double atof(char *s) { double val, putere; int i, semn ; for(i=0;s[i]==' ' ||s[i]=='\n' ||s[i]=='\t ' ;i++); semn=1; if(s[i]=='+' || s[i]== '-') semn=(s[i++]=='+')?1: -1; for(val=0 ;s[i]>='0' &&s[i]<='9' ; i++) val=10*val+s[i]-'0' ; if (s[i]=='.') I++; for (putere =1;s[i]>='0' && s[i]<='9' ; i++) { val=10*val+s[i]-'0' ; putere*=10; } return semn*val/putere; }

Declaratia
double atof (char *s);

spune ca atof() este o functie care returneaza o valoare double. Daca atof() insasi si apelul ei din main() au tipuri inconsistente in acelasi fisier sursa, acest lucru va fi depistat de catre compilator.Dar, daca atof() se compileaza separat, nepotrivirea nu va fi declarata si atof () va returna un double, pe care main() il va trata ca un intreg, rezultand raspunsuri imprevizibile.Fiind dat atof(), putem scrie, in principiu, functia atoi() (conversie de sir in intreg) astfel:
atoi( char s[]) { double atof() ; return atof (s); }

Sa remarcam structura declaratiilor si a instructiunii return.Valoarea expresiei din:

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (3 of 7)10/2/2005 8:13:59

Lectia 7

return expresie

este intodeauna convertita in tipul functiei inainte ca returnarea rezultatului sa aiba loc.Deci valoarea lui atof(), un double, este convertita automat in int, cand apare in instructiunea return, deoarece functia atoi() returneaza un int. (Conversia unei valori flotante intr-un intreg trunchiaza orice parte fractionara.).

Mai multe despre argumentele functiilor


Argumentele functiilor Ctrimise prin valoare ,adica functia apelata primeste o copie temporara si privata a fiecarui argument. Aceasta inseamna ca functia nu poate afecta argumentul original din functia apelanta. Intr-o functie, argumentul este , de fapt , o variabila locala,initializata cu valoarea cu care functia este apelata. Cand un nume de tablou apare ca argument al unei functii, locatia de inceput a tabloului este cea trimisa efectiv; elementele nu sunt copiate. Functia poate altera elementele tabloului, indexand aceasta valoare. Efectul este ca tablourile sunt trimise prin referinta. Deocamdata sa ilustram aceasta proprietate printr-o versiune a functiei strlen(),care calculeaza lungimea unui sir.
int strlen(char *s) { for (int n=0;*s!='\0' ;n++); return n; }

Incrementarea lui s este perfect legala deoarece el este o variabila pointer; s++ nu are efect pe sirul de caractere in functia carea apelat-o pe strlen(), ci incrementeaza doar copia adresei. Ca parametrii formali in definirea unei functii,
char s[] si char *s;

sunt echivalenti; alegerea formei efective este determinata in mare parte de expresiile ce vor fi scrise in cadrul functiei.Atunci cand un nume de tablou este transmis unei functii, aceasta poate, dupa necesitati, s-o interpreteze ca tablou sau ca pointer si sa-l trateze in consecinta. Functia poate efectua chiar ambele tipuri de operatii, daca i se pare potrivit si corect. Este posibila si transmiterea de catre o functie doar a unei parti dintr-un tablou,prin transmiterea unui pointer la inceputul subtabloului. De exemplu, daca a este un tablou,
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (4 of 7)10/2/2005 8:13:59

Lectia 7

f(&a[2]) si f(a+2)

transmit functiei f adresa elementului a[2], deoarece &a[2] si a+2 sunt expresii pointer care refera al treilea element al lui a. In cadrul functiei f, declaratia parametrului poate fi:
f(int arr[ ]) { . . . }

sau
f(int *arr) { . . . }

Astfel, dupa cum a fost conceputa functia f, faptul ca argumentul refera,de fapt, o parte a unui tablou mai mare nu are importanta. In cazul unui tablou bidimensional trebuie transmis unei functii, declararea argumentelor in functie trebuie sa includa dimensiunea liniei, dimensiunea coloanei fiind irelevanta si aceasta deoarece unei functii i se transmite, ca si in cazurile anterioare un pointer. De exemplu, daca trebuie transmisa o matrice cu 2 linii si 7 coloane ale carei elemente sunt intregi, vom utiliza un pointer care parcurge tablouri de cate 7 int. Astfel , declaratia functiei f va fi:
f(int matrice[2][7]) { . . . . . }

Declararea argumentului f poate fi , de asemenea:


int matrice[][7]

din moment ce numarul liniilor este irelevant, sau ar putea fi


int (*matrice)[7]

care spune ca argumentul este un pointer pe un tablou de 7 intregi. Dupa cum am mai semnalat intr-o discutie anterioara, parantezele curbe sunt necesare datorita faptului ca parantezele drepte au prioritate mai mare decat * fara paranteze,iar:
int *matrice[7];

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (5 of 7)10/2/2005 8:13:59

Lectia 7

este un tablou de 7 pointeri la intregi,ceea ce ar echivala cu transmiterea matricei pe coloane ,si nu pe linii.

Argumentele liniei de comanda


Si, cum main() este o functie ca oricare alta functie, ea poate avea parametrii. Acestia, insa nu pot fi transmisi prin metode clasice, ci numai in cadrul liniei de comanda , deci in momentul lansarii programului in executie. Pentru aceasta, la inceperea executiei, main() primeste doua argumente. Primul (numit conventional argc) contine numarul parametrilor din linia de comanda prin care a fost apelat programul, iar al doilea (argv) este un pointer la un tablou de siruri de caractere care contine argumentele, cate unul in fiecare sir. Manipularea acestor siruri de caractere este o utilizare comuna a nivelelor multiple de pointeri. Cea mai simpla ilustrare a declaratiilor necesare si a celor de mai sus amintite este programul echo, care pune, pur si simplu, pe o singura linie argumentele liniei de comanda, separate prin blancuri. Astfel,daca este data comanda:
echo Bine ati venit in lumea C

iesirea este: Bine ati venit in lumea C Prin conventie, argv[0] este numarul prin care se recunoaste programul, asa ca argc este 1. In exemplul de mai sus, argc este 7 si argv[0], argv[1],argv[3],argv[4],argv[5] si argv[6] sunt , respectiv, echo, Bine, ati,venit,in,lumea si C. Aceasta este ilustrata in echo: //echo- prima versiune
#include <stdio.h> void main( int argc, char *argv[ ]) { int i; for (i=1; i<argc; i++) printf("%s%c", argv[i],(i<argc-1)?' ':'\n'); }

argv fiind un pointer la un tablou de pointeri, exista cateva modalitati de a scrie acest program care implica manipularea pointerului mai curand decat indexarea tabloului. Nu este lipsit de interes sa prezentam inca doua variante:

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (6 of 7)10/2/2005 8:13:59

Lectia 7

// echo- a-II-a versiune


void main ( int argc, char *argv[ ]) { while (--argc>0) printf("%s%c",*++argv,(argc>1)?' ' : '\n'); }

Daca argv este un pointer la inceputul tabloului care contine siruri de argumente cu 1 (prin ++argv face ca el sa indice pe argv[1] in loc de argv[0]. Fiecare incrementare succesiva muta pe argv pe urmatorul argument; argv este, deci, pointerul la acel argument. Simultan, argc este decrementat; atunci cand el devine zero, nu mai exista argumente de imprimat. // echo- a III a versiune
void main( int argc,char *argv[ ]) { while (--argc>0) printf((argc>1)? "%s" : "%s\n" ,*++argv); }

Aceasta versiune arata ca formatul argumentului lui printf poate fi o expresie ca oricare alta .Aceasta utilizare nu este foarte frecventa, dar este bine sa fie retinuta.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia07.html (7 of 7)10/2/2005 8:13:59

Lectia 8

LECTIA 8 FUNCTII (II)


Obiective Prezentare generala

OBIECTIVE <home>
G

exemplificam folosirea pointerilor la functii, a vectorilor de pointeri la functii si a pointerilor la functii ce returneaza pointeri. exemplificam utilizarea functiilor recursive.

PREZENTARE GENERALA <home>


In procesul compilarii programului, numele variabilelor sunt transformate in adrese de memorie unde sunt stocate si unde pot fi recuperate datele. Si pointerii la adrese pot accesa aceste adrese. Aceasta etapa de prelucrare se aplica atat variabilelor, cat si functiilor. Compilatorul transforma numele unei functii intr-o adresa de cod executabil. Limbajul C extinde strategia manipularii variabilelor prin pointeri la functii. La fel ca oricare alt pointer si pointerul la o functie trebuie initializat inainte de a fi folosit, aceasta realizandu-se prin atribuirea numelui functiei, pointerului. Variabilele pointer care contin adresa unei functii permit: -transferul functiei asociate, ca parametru; -apelul functiei prin intermediul pointerului. Declararea unui pointer la o functie se face astfel: tipRezultat (*pointerFunctie) (listaParametri); Aceasta forma precizeaza compilatorului ca pointerFunctie este un pointer la o functie care intoarce un rezultat de tipul tipRezultat si care are o lista de parametri. Exemplu:
double (*fx)(double x ); void (*sortare )(int* tablInt,unsigned n);
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia08.html (1 of 3)10/2/2005 8:13:57

Lectia 8

unsigned (*cautare ) (int cheieCautare , int *tablInt , unsigned *n);

Initializarea unui pointer la o functie se face astfel:


pointerFunctie = numeFunctie ;

Functia atribuita trebuie sa intoarca un rezultat de acelasi tip cu cel intors de pointerul la functie si sa aiba aceeasi lista de parametrii cu acesta. In caz contrar compilatorul semnalizeaza eroare. Exemplu :
void (* sortare )(int* tablInt,unsigned n); sortare=qsort;

Apelul pointerilor la o functie se face astfel:


(*pointerFunctie) (<de argumente>); (*pointerFunctie[indice])(<de argumente>);

Exemplu:
(*sortare)(&tablInt,n); (*sortare[0])(tablInt,n);

Prin recursivitate se intelege, in programare, proprietatea unui functii de a se putea apela pe ea insasi. Apelul unei functii poate sa apara si in definitia sa. In acest caz, functia se numeste recursiva. Nu toate limbajele de programare suporta functii recursive. Un algoritm in a carui descriere este necesara referirea la el insusi se numeste algoritm recursiv.Aceasta clasa de algoritmi este frecvent intalnita si ofera descrieri simple si elegante ale operatiilor de efectuat. Pentru programarea lor este necesara folosirea functiilor recursive. In C nu exista restrictii speciale pentru functii recursive. Trebuie mentionata insa problema generala a iesirii din recursivitate. Practic este necesar ca apelul recursiv sa apara in blocul unei instructiuni de decizie sau ciclare a carei conditie este modificata de functie astfel incat sa opreasca secventa de apeluri. Exemplul clasic il constituie calculul factorialului, pe baza relatiei :
n!=n*(n-1)!

Exemplu:

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia08.html (2 of 3)10/2/2005 8:13:57

Lectia 8

/* factorial*/ int fact(int n) { if (n==0) return 1 ; else return n*fact(n-1); } void main() { printf("%d",fact(10)); }

Se observa ca incheierea apelurilor recursive are loc cand se ajunge la apelul fact(0). Cand este apelata o functie, parametrii si datele locale sunt salvate in stiva. Astfel, cand o functie este apelata recursiv functia incepe executia cu un nou set de parametri si variabile locale, dar codurile care constituie functia raman aceleasi. La fiecare apel, se consuma timp pentru transferul parametrilor si rezultatului si se incarca stiva suplimentar cu obiectele asociate parametrilor si rezultatului. Stiva este eliberata treptat abia in secventa de reveniri. Din aceste motive, functiile recursive pot deveni neconvenabile. Desi in principiu este posibila trecerea de la orice algoritm recursiv la algoritmi nerecursivi, rezultatul este greoi de urmarit si de programat. De multe ori, datorita simplitatii, este preferata folosirea functiilor recursive, daca viteza de executie este acceptabila.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia08.html (3 of 3)10/2/2005 8:13:57

Lectia 9

LECTIA 9 FUNCTII (III)


Obiective Prezentare generala

OBIECTIVE <home>
G G

prototipul functiilor. functii fara argumente sau cu numar variabil de argumente.

PREZENTARE GENERALA <home>

Prototipul functiilor
Inainte de a folosi o functie trebuie sa o declaram. Exista doua metode de a face acest lucru:
G

declaram pur si simplu functia inainte de a fi folosita (definitia functiei); Definitia unei functii apare in cadrul fisierului sursa inaintea oricarui apel numai in cazuri particulare. Acest lucru nu este posibil in general, fie datorita modului in care functiile se apeleaza unele pe altele, fie pentru ca definitia nu se afla in fisierul sursa. Definitia lipseste in cazul functiilor din biblioteci (standard sau definite de utilizator, disponibile sub forma de fisiere obiect) sau atunci cand se afla in alt fisier sursa din proiect. Sintaxa definitiei unei functii este urmatoarea :

<tip_r> identif_functie(<lista_declar_parametri>) { <lista_declaratii_locale> lista_instructiuni }


G

utilizam prototipul functiei. Prin prototip al unei functii intelegem o declaratie fara definire a functiei, in care se fac cunoscute numele, tipul returnat si lista parametrilor sai (ca numar, tip si, eventual, ca identificatori). Sintaxa prototipului unei functii este urmatoarea :

<tip> identif_functie (<lista_declar_parametri>);

Specificarea numelor parametrilor este optionala, dar dupa inchiderea parantezelor rotunde trebuie sa se
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (1 of 7)10/2/2005 8:14:00

Lectia 9

puna punct si virgula.


void f(void);

Prototipul de fata indica faptul ca f este o functie fara parametri si care nu returneaza nici o valoare.
double a(void);

Functia a nu are parametri. Ea returneaza o valoare flotanta in dubla precizie.


void c(int x, long y[], double z);

Functia c nu returneaza nici o valoare. Are trei parametri: - primul este de tip int; - al doilea este un tablou unidimensional de tip long; - al treilea este de tip double.
void c(int, long [], double);

Acest prototip exprima acelasi lucru cu cel precedent. Aceeasi sintaxa utilizata in cadrul prototipului va trebui sa fie utilizata si in momentul definirii functiei.
// prototipul functiei patrat (declararea functiei) double patrat(double); // definitia functiei patrat double patrat(double x) { return x * x ;}

Se observa ca declaratia functiei patrat() nu include numele parametrului sau. De asemenea observam ca nu este necesar sa declaram prototipul unei functii inaintea definirii functiei, definitia insasi putand servi drept prototip. In mod obisnuit, prototipul functiei va aparea intr-un fisier de tip header. De obicei, declaratia unei functii este globala. Prototipul unei functii poate fi insa specificat in interiorul functiei care o apeleaza. In acest fel se "ascunde" acest prototip de alte functii. In consecinta, alte functii nu pot apela functia decat daca sunt declarate dupa declaratia acesteia din urma. Prototipurile functiilor din biblioteci sunt oferite impreuna cu declaratiile de date si macrodefinitiile necesare in fisiere antet (header) identificate prin extensia ".h" si plasate in directorul INCLUDE. Serviciul help din mediul integrat precizeaza pentru fiecare functie fisierul antet in care este declarata.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (2 of 7)10/2/2005 8:14:00

Lectia 9

Utilizarea unei functii din biblioteca impune includerea in program a fisierului asociat cu ajutorul directivei #include.Programatorul isi poate crea propriile fisiere antet continand declaratiile functiilor, tipurilor globale, macrodefinitiilor utilizate in program. Drept exemplu avem prezentarea unei situatii tipice de declarare, definire, si utilizare a functiior intr-un fisier sursa.
/* declaratii ptr. functii din biblioteci */ #include <stdio.h> /* prototipuri ale functiilor definite in program */ void af_max(float, float); /* alte prototipuri si declaratii globale pentru date */ void main() { float r1,r2; ... af_max(r1,r2); /*

apelul functiei af_max care primeste ca parametrii doua valori float, afiseaza valoarea maxima si media si nu intoarce nici un rezultat */

} /* definitia functiei af_max */ void af_max(float n1, float n2); { float max; max=(n1>n2)? n1:n2; printf("Max=%f; Media=%f\n",max,(n1+n2)/2 ); }

Limbajul C impune ca o functie sa fie intai declarata, in cazul in care ea este apelata inaintea definirii ei. In cazul absentei prototipului unei functii in C obtinem, cel mult, un avertisment din partea compilatorului. Mai mult, compilatorul considera, in mod implicit, ca tipul returnat de catre functii este int. Acest lucru poate conduce la aparitia situatiilor conflictuale, in special in cazul programelor multifisier.
// myfile1.c double modul(double x)

{
if (x<0) return -x;

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (3 of 7)10/2/2005 8:14:00

Lectia 9

else return x; } // myprog1.c #include <stdio.h> void main() { int am, m=-3; am=modul(m); printf(" am= %d\n",am); }

Deoarece modul( ) nu are prototip in myprog1.cpp, compilatorul C trateaza argumentul si tipul returnat de aceasta functie ca fiind int. Totusi programul poate fi rulat,dar rezultatul este total eronat. Chiar daca vom utiliza prototipul functiei, nu suntem siguri ca am inlaturat sursa de erori. De exemplu, ce se intampla daca specificam prototipuri incorecte:
// myprog2.c # include <stdio.h> int modul(int x);//argument si tip returnat incorect void main() { int am,m=-3; am=modul(m); printf(" am= %d\n",am); }

Un compilator C va accepta aceasta fara sa furnizeze vreun avertisment macar, el presupunand ca parametrii sunt furnizati corect. Putem ajuta compilatorul sa depisteze erorile, procedand dupa cum urmeaza: mai intai prototipurile de functii la vom scrie in fisiere header, dupa care includem aceste fisiere atat in fisierele in care sunt implementate functiile, cat si in cele in care acestea sunt apelate. In acest mod, vom avea aceleasi prototipuri in ambele categorii de fisiere. Mai jos se afla scris programul conform celor spuse:
// myfile3.h double modul(double x);//Prototipul din header // myfile3.c #include "myfile3.h"

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (4 of 7)10/2/2005 8:14:00

Lectia 9

double modul(double x) { if (x<0) return -x; else return x; } // myprog3.c #include <stdio.h> #include "myfile3.h" void main() { int am, m=-3; am=modul(m); printf(" am= %d\n",am); }

In acest fel eroarea este depistata. Probabil veti crede ca, procedand astfel, erorile nu mai pot patrunde in programele noastre. Din nefericire nu este asa. De exemplu, putem gresi chiar prototipul functiei in cadrul headerului, si deci, vom folosi un prototip eronat in ambele fisiere sursa.
// myfile.h double modul(int x);//Argument incorect

Din nefericire, nu se garanteaza functionarea corecta a unor functii pentru care prototipul nu este corect specificat. Acest lucru se datoreaza faptului ca tipul returnat nu este verificat, nici de compilator si nici de catre link-editor. Ca atare, urmatoarea eroare nu va fi depistata:
// myfile4.h int modul(double x);//tipul valorii returnate eronat // myfile4.c #include "myfile4.h" double modul(double x) { if (x<0) return -x; else return x; } // myprog4.c
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (5 of 7)10/2/2005 8:14:00

Lectia 9

#include <stdio.h> #include "myfile4.h" void main() { int am, m=-3; am=modul(m); printf(" am= %d\n",am); }

Mentionam ca, in cazul absentei tipului valorii returnate in cadrul prototipului unei functii, acesta va fi considerat cel implicit, deci int.

Functii fara argumente sau cu numar variabil de argumente


In C, cel mai bun mod de a obtine prototipurile unor astfel de functii este urmatorul:
int f(void); //f nu are nici un argument int f(...); //f are numar variabil de argumente

Pentru siguranta, este bine ca intotdeauna sa se specifice numarul argumentelor, fie prin mentionarea parametrilor formali, fie utilizand ellipsis "(...)", fie prin (void). Ellipsis este un grup de trei puncte fara spatii intre ele si se utilizeaza in lista de parametri formali ai prototipului unei functii pentru a indica prezenta unui numar variabil de argumente in linia de apel a functiei sau a argumentelor cu tipuri variabile. De exemplu,
void funct(int n,char c,...);

declara funct( ) ca fiind o functie in al carui apel va aparea cel putin doi parametri efectivi, un int si un char, dar fiind permisa si prezenta altor parametri. In C, prototipul trebuie sa specifice explicit faptul ca functia nu are parametri prin utilizarea cuvantului void. Pentru compatibilitate cu declaratia clasica, daca lipseste lista de parametri din declaratie si nu apare cuvantul void, compilatorul C nu decide ca functia nu are parametri si nu verifica parametrii efectivi la apelare. Este suficient ca lista de parametri din prototip sa specifice tipurile. Identificatorii nu sunt semnificativi, dar pot fi utili pentru documentarea programului si sunt utilizati de compilator in cadrul mesajelor de eroare pentru identificarea mai usoara a parametrului eronat. Definirea unei functii cu un numar variabil de argumente de catre utilizator este o problema delicata, deoarece necesita cunoasterea modului in care sunt memorate valorile parametrilor efectivi. O alta problema este referirea acestor valori, in lipsa unor identificatori asociati in lista de parametri formali. O
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (6 of 7)10/2/2005 8:14:00

Lectia 9

solutie simpla si portabila o ofera un set de functii (de fapt macrodefinitii) declarate in stdarg.h. Acestea permit accesul la lista de parametri in cazul in care functia nu cunoaste numarul si tipurile parametrilor. Fisierul antet stdarg.h declara tipul va_list si functiile va_start( ), va_arg( ) si va_end( ),unde:
G

va_list este un pointer catre lista de parametri. In functia definita de programator trebuie declarata o variabila de acest tip care va permite adresarea parametrilor (fie ap numele variabilei). va_start( ) initializeaza variabila ap de tipul va_list cu adresa primului parametru din sublista variabila. Prototipul este:

void va_start(va_list ap, ult_fix);

unde ult_fix este numele ultimului parametru din sublista fixa.


G

va_arg( ) intoarce valoarea parametrului urmator din sublista variabila. Prototipul este:

tip_p va_arg(va_list ap, tip_p);

unde tip_p este tipul parametrului urmator. La fiecare apelare va_arg( ) intoarce valoarea parametrului indicat de ap si modifica variabila ap astfel incat sa indice parametrul urmator. In acest scop folosim tipul specificat al parametrului (tip_p)pentru a stabili dimensiunea zonei de memorie alocata. Datorita conversiilor implicite la transferul valori din sublista variabila, tipurile char, unsigned charsi floatnu se folosesc cu var_arg( ).Valorile transferate sunt intotdeauna extinse la tipul int, respectiv double.
G

va_end( ) incheie operatia de extragere a valorii parametrilor si trebuie apelata neaparat inainte de revenirea in functie

void va_end(va_list ap);

Dupa ce se executa va_end( ) pentru a relua extragerea parametrilor este necesar sa se apeleze din nou va_start( ).

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia09.html (7 of 7)10/2/2005 8:14:00

Lectia 10

LECTIA 10 FUNCTII (IV)


Obiective Prezentare generala

OBIECTIVE <home>
G G G

Transmiterea parametrilor prin referinte Functii inline Rescrierea functiilor

PREZENTARE GENERALA <home> Transmiterea parametrilor prin referinta


In limbajul C, toti parametri sunt transmisi prin valoare (fiecarei functii ii sunt transmise valorile efective ale parametrilor ). De aceea, este de preferat sa utilizam pointeri ca parametri.
void actual(int *t,int s) { *t=s; } /* t este transmis prin referinta, prin intermediul unui pointer iar s prin valoare */

Exista diferente intre apelul cu pointeri ("->") si apelul cu referinte ("."). Bineinteles ca putem utiliza oricare dintre cele doua metode, dar se pare ca functiile utilizand referintele sunt mai clare la apelare.

Functii inline
/* cazurile in care ati utilizat expresii macro in vederea simulari apelurilor functiilor. */ #define INC(i) i++ ... k=INC(j);

Problemele vin tocmai din faptul ca aceste apeluri seamana cu apelul functiilor, dar nu sunt functii. Parametrii expresiilor macro sunt inlocuiti inline atunci cand o astfel de expresie este intalnita de catre compilator. In schimb, parametrii functiilor sunt verificati din punct de vedere al tipului si pasati utilizand scopul fiecaruia.
k=INC(3+5); // va produce k=3+5++; // o sintaxa incompilabila.

In vederea rezolvarii unor astfel de situatii, C a fost inzestrat cu functii inline = combinatie intre expresii macro (apelul unei functii inline este expandat prin inlocuirea apelului sau cu corpul corespunzator implementarii functiei) si functii(se executa verificarea tipurilor parametrilor, acestia din urma fiind transmisi ca unei functii normale). Declararea functiilor inline se face prin utilizarea cuvantului cheie inline, exact inaintea definitiei functiei (inaintea tipului returnatde functie).

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia10.html (1 of 5)10/2/2005 8:14:01

Lectia 10

inline int inc(int n) { return n++; } ... int i; i=inc(3+5);

In momentul apelarii functiei inc(), compilatorul expandeaza functia inline, dar nu inainte de a aduna 3 cu 5 si de a depune rezultatul intr-o variabila temporara. Rezultatul acestei adunari este apoi incrementat si atribuit lui i. Un cod echivalent cu apelul anterior ar putea fi:
int temp=3+5; i=temp++;

Utilizand cuvantul inline, nu putem fi siguri ca functia careia i-am atasat acest cuvant va fi considerata de catre compilator astfel. Asemeni cuvantului register, inline constitue mai degraba o recomandare facuta compilatorului, noi considerand ca functia este suficent de mica pentru a fi expandata inline. Compilatorul poate sa ia in considerare sau nu aceasta recomandare. In cazul in care utilizam optiunea de compilare -vi, ii semnalam compilatorului sa ignore cuvantul inline. O situatie in care am putea dori aceasta este atunci cand depanam un program, functiile expandate inline fiind greu de urmarit de catre depanator.

Functii inline si fisierele header


Functiile inline sunt omoloage constantelor (identificatorii declarati cu ajutorul constantelor (in mod uzual in cadrul fisierelor header) sunt initializati in momentul declararii lor):
G G G

corpul unei functii inline va fi definit in momentul declararii acesteia ca fiind inline; functiilor inline li se vor lega atribute la link-editare; declararea functiilor inline se va face in cadrul fisierelor header.

// header1.h void arata_valoarea(int v); // file1.c #include <stdio.h> #include "header1.h" inline void arata_valoarea(int v) { printf("Valoarea este %d\n",v); } // progr1.c #include "header1.h" void actiune(int &v) { v^=0*1010; arata_valoarea(v); } void main()
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia10.html (2 of 5)10/2/2005 8:14:01

Lectia 10

int biti=42; actiune(biti);

Functia arata_valoarea() a fost declarata ca fiind inline in cadrul fisierului file1.c, acolo unde a fost declarata aceasta. In schimb, in cadrul headerului header1.h a fost omis cuvantul inline. Problema care apare este aceea ca odata declarand arata_valoarea() ca fiind inline, s-a realizat si legarea interna a acesteia. Deci ea va apartine modulului file1.c fiind astfel inaccesibila din exteriorul acestuia. In acest context, compilatorul va semnala eroarea legala de imposibilitatea de a localiza functia arata_valoarea() in progr1.c. Daca am fi renuntat la cuvantul inline, atunci arata_valoarea() ar fi avut legare externa la link-editare, asa cum o au toate functiile normale, programul s-ar fi compilat si link-editat cu succes, dar arata_valoarea() nu ar fi fost inline. Solutia este de a defini aceasta functie ca fiind inline in cadrul fisierului header, caruia, de fapt, ii si apartine. Procedand astfel, prezenta fisierului file1.c este nejustificata.
// header2.h inline void arata_valoarea(int v) { printf("Valoarea este %d\n",v); } // progr2.c #include "header2.h" void actiune(int &v) { v^=0*1010; arata_valoarea(v); } void main() { int biti=42; actiune(biti); }

Ascunderea functiilor sub diferite nume


// functie de deschidere a fisierelor FILE *fopen(const char *fisier, const char *mod); /* indicatorul mod va indica situatia in care fisierul este deschis pentru citire si/sau scriere. */

Problema care apare in astfel de situatii este ca se poate gresi foarte usor. In plus, un astfel de flag (fanion) are rolul de a indica deschiderea unui fisier existent sau a unuia nou, simpla inversiune a rolurilor acestui indicator putand fi fatala unui fisier deja existent, in cazul utilizarii indicatorului de creare, in locul celui de deschidere normala. Pentru a evita astfel de situatii, putem sa ne scriem functiile noastre inline, de deschidere si de creare de fisiere:
inline FILE *initializare(char *fnume) { return fopen(fnume,"w"); }

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia10.html (3 of 5)10/2/2005 8:14:01

Lectia 10

inline FILE *deschidere(char *fnume) { return fopen(fnume,"r"); }

Aceste doua functii sunt mult mai usor de utilizat, si mai sigure in acelasi timp, decat fopen(). Pe de alta parte, fiind functii inline, nu afecteaza, in nici un fel, timpul de executie sau dimensiunea codului.

Rescrierea functiilor
Este permisa utilizarea mai multor functii avand acelasi nume, asemenea functii purtand numele de functii redefinite (rescrise, overloaded sau suprapuse).
// progr3.c /* trei functii aduna(), fiecare pentru cate unul dintre tipurile int, double si char*(siruri de caractere). */ #include <stdio.h> #include <string.h> int aduna(int a, int b) { return a+b; } double aduna(double a, double b) { return a+b; } char *aduna(char *a, char *b) { strcat(a,b); return a; } void main() { int i=aduna(42,17); double d=aduna(42.0,17.0); char s1[80]="C++"; char s2[80]="is the best!"; printf("\n i=%d \n d=%f \n %s \n",i,d,aduna(s1,s2)); }

Nu este neaparat nevoie sa specificam acelasi numar de parametri intr-un set de functii redefinite.
// putem scrie inca o functie aduna(), care sa accepte un // singur parametru, fara a fi considerata ca fiind o functie eronata: int aduna(int i) { return i+42; }

Rezolvarea ambiguitatilor dintre functiile redefinite


(sau cum decide compilatorul asupra variantei functiei aduna() ce urmeaza a fi utilizata ) Atunci cand compilatorul depisteaza apelul unei functii redefinite, cauta in lista redefinirilor acelei functii, una a carei lista de parametri formali sa coincida, ca numar, tip si pozitie, cu lista parametrilor efectivi, utilizati in acel apel. Aceasta identificare este facuta cu o oarecare usurinta in cazul in care numarul parametrilor difera de la o implementare la alta, acest numar intervenind in

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia10.html (4 of 5)10/2/2005 8:14:01

Lectia 10

mod direct in procesul de identificare. In general, regulile care intervin in localizarea functiei dorite sunt destul de complexe. Pentru fiecare argument efectiv, compilatorul va utiliza un set de reguli prestabilite, in vederea gasirii celei mai bune potriviri de tip. Regulile sunt apelate in ordinea in care apar enumerate in continuare, cele mentionate mai intai fiind considerate mai bune decat cele lasate spre sfarsitul listei. Strategia de baza este de a cauta potrivirea exacta, iar, in cazul in care aceasta este imposibil de gasit, sa se incerce simple conversii de tip, in vederea obtinerii unei potriviri cat mai bune. Iata deci, regulile, urmate de conversiile triviale disponibile:

G G G

G G

Cauta potrivirea exacta si o utilizeaza in cazul gasirii ei. De asemenea, cauta potrivirea ce utilizeaza conversii triviale. Cauta conversii de la float la double sau de la char, short, enum si campuri de biti la int. Cauta potriviri in care intervin conversii aritmetice standard, cum ar fi int la double, unsigned la signed, etc. De asemenea, se vor cauta conversiile de la orice tip de pointer la void*, si se va converti constanta 0 la pointerul NULL. In plus, se va incerca conversia pointerilor la clase derivate, in pointeri la clase de baza si referinte la clase derivate, in referinte la clase de baza. Se vor cauta conversii care necesita crearea unui obiect temporar, asemeni transmiterii unui obiect constant unei functii ce are drept parametru un obiect neconstant. Se vor cauta potrivirile de tip utilizand conversiile de tip definite de utilizator. Se va incerca potrivirea de tip prin ellipses,f(...). Tip formal T& T *T const T volatile T (*F)(args) Descrierea conversiei De la un obiect de tip T, la o referinta catre un obiect de tip T De la o referinta catre un obiect de tip T, la un obiect de tip T De la un tablou de obiecte de tip T, la un pointer catre un obiect de tip T De la un obiect de tip T, la un obiect constant de tip T De la un obiect de tip T, la un obiect volatil de tip T De la o functie cu tipurile argumentelor specificate la un pointer catre o functie cu aceeasi lista de argumente

Tip actual T T& T[ ] T T F(args)

Prin variabila volatila, indicata cu ajutorul cuvantului cheie volatile, intelegem o variabila ce poate fi modificata prin intermediul unei rutine. Indicatorul este utilizat asemeni lui register sau auto, variabila fiind insa incarcata in memorie si nu intr-un registru al calculatorului. Putem avea chiar si clase volatile. Compilatorul cauta numai tipul argumentelor si nu verifica tipul valorii returnate de catre functie. Astfel, doua functii nu pot sa difere numai prin tipul acestei valori. De asemenea, este un bun stil de scriere a programelor acela de a utiliza, ori de cate ori este posibil, conversia explicita de tip, pe langa claritatea parcurgerii programului castigand si claritatea preluarii de catre compilator a acestuia. Multe din regulile de prelucrare implica efectuarea diferitelor tipuri de conversii. In unele cazuri, compilatorul ar putea executa multiple astfel de conversii in vederea stabilirii listei exacte de parametri. Este bine ca, atunci cand este posibil, lista parametrilor efectivi sa contina conversiile explicite in vederea obtinerii unei claritati a programului.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia10.html (5 of 5)10/2/2005 8:14:01

Lectia 11

LECTIA 11 STRUCTURI (I)


Obiective Prezentare generala

OBIECTIVE <home>
G G

Notiuni de baza Structuri si functii

PREZENTARE GENERALA <home>


O structura este o colectie de una sau mai multe variabile care pot fi de tipuri diferite, grupate impreuna, sub un singur nume, pentru o manipulare convenabila. (Structurile sunt numite inregistrari in unele limbaje, de exemplu, in Pascal). Exemplul traditional de structura este inregistrarea personala: o persoana este descrisa prin cateva atribute ca nume, telefon, varsta, adresa, data nasterii, etc. Fiecare dintre atribute, la randul lor, pot fi structuri. Astfel, numele are mai multe componente, adresa de asemenea, data nasterii si ea, etc. Structurile ajuta la organizarea datelor complicate, mai ales in programele de mari dimensiuni, deoarece, in multe situatii, ele permit ca un grup de variabile inrudite sa fie tratate unitar si nu ca entitati separate.

NOTIUNI DE BAZA
O "data" consta din mai multe parti, precum "ziua", "luna", "anul" si probabil, "numele lunii". Aceste patru variabile pot fi toate plasate intr-o singura structura ca aceasta:
struct data { int zi,luna,an; char nume_luna[4]; };

Cuvantul cheie struct introduce o structura de date, care este o lista de declaratii cuprinsa intre acolade. Un nume, "eticheta" sau "tag", urmeaza cuvantului cheie "struct", precum "data" in exemplul anterior. Aceasta eticheta da un nume acestui gen de structura si poate fi referita ca prescurtare de declaratie detaliata. Elementele sau variabilele mentionate intr-o structura sunt numite "membri". Un membru al structurii, o eticheta a unei structuri sau o variabila simpla, pot avea acelasi nume fara a crea ambiguitate, deoarece se disting prin context, mai exact prin domeniul scopului. Desigur, se va utiliza acelasi nume doar pentru
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia11.html (1 of 3)10/2/2005 8:14:03

Lectia 11

a defini obiecte in stransa relatie.

STRUCTURI SI FUNCTII
Este permisa transmiterea unei structuri unei functii atat prin valoare cat si prin adresa (pointer). In plus, se pot utiliza parametrii de tip referinta la structuri. Pentru a economisi spatiul ocupat de numele structurii, e permisa declararea de structuri anonime. Folosirea acestor structuri implica declararea variabilelor de tip structura fara a defini un nume pentru structura. De exemplu, urmatoarea definitie de structura declara variabilele v1, v2, v3, dar omite specificarea numelui structurii:
struct { double real; double imag; } c1,c2,c3;

De asemenea se pot initializa variabile de tip structura in momentul declararii ei, ca in exemplele urmatoare:
complex c={1.0.-8.3}; persoana el={"Numele_tau", "Salariat", "48"};

Pentru accesarea membrilor unei structuri se foloseste operatorul punct ".".


c1.real=12.45; c1.imag=34.56; c2.imag=0.98 * c1.imag el.varsta=48; el.varsta+=2; // Se adauga varstei inca 2 ani.

Unde s-au folosit structurile:


struct complex { double real; double imag; }; struct persoana {

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia11.html (2 of 3)10/2/2005 8:14:03

Lectia 11

char nume[31]; char titlu[21]; unsigned varsta; };

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia11.html (3 of 3)10/2/2005 8:14:03

Lectia 12

LECTIA 12 STRUCTURI (II)


Obiective Prezentare generala

OBIECTIVE <home>
G

structuri cu autoreferire, campuri de biti si uniuni

PREZENTARE GENERALA <home> Structuri cu autoreferire


Structurile cu autoreferire prezinta avantajul ca se poate memora o cantitate variabila de valori, lucru care nu se poate realiza prin folosirea masivelor care fie sunt prea mari si ocupa mai multa memorie decat este necesar, fie sunt prea mici si nu pot memora toate valorile necesare. O structura cu autoreferire arata astfel :
struct nod { Persoana pers; nod *next; };

In general, este ilegal ca o structura sa contina o parte a ei insasi, dar nod *next; declara next ca fiind un pointer catre un nod si nu nodul insusi.
struct descendent; struct nod { int eticheta; struct nod *rest; struct descendent *desc; }; struct descendent { struct nod *id; struct descendent *urm; };

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia12.html (1 of 5)10/2/2005 8:14:06

Lectia 12

Prima declaratie din exemplu este o declaratie "incompleta", care anunta ca ulterior se va defini o structura numita descendent. Cea de-a doua declaratie precizeaza ca structura cu numele nod are trei campuri: campul eticheta, de tip int, campul rest, de tip pointer catre nod si campul desc, de tip pointer catre o structura de tip descendent, cu doua campuri de tip pointer unul catre un nod si celalalt catre un descendent. Campurile unei structuri se declara dupa sintaxa obisnuita a declaratiilor de variabile, dar nu pot avea valori initiale. In plus, sintaxa este extinsa, permitand specificarea, prin intermediul unei expresii constante, a numarului de biti alocat pentru un anumit camp, sub forma: tip_camp selector:numar_biti; O astfel de componenta, pentru care se specifica numarul de biti alocat, se numeste camp de biti.

Campuri de biti
Se pot aloca unor campuri de structuri sau uniuni biti dintr-un octet.In felul acesta se definesc campuri de biti (bit-field) care pot fi accesate fiecare, separat de restul octetului, pentru evaluare si/sau modificare. Pentru aplicatii de control al unor dispozitive fizice (interfete), criptare, etc, care solicita structura informatiei dintr-o locatie de memorie, utilizarea campurilor de biti simplifica substantial redactarea programelor. Campurile de biti se pot declara ca membri ai unei structuri cu sintaxa : struct identificator_tip_structura { tip_element1 <identificator_element1>:lungime .............................. tip_elementN <identificator_elementN>:lungime } lista_identificatori_variabile_structura ; Exista urmatoarele restrictii pentru campurile de biti :
G G G

tipul poate fi int, signed sau unsigned; lungimea este o constanta intreaga cu valoarea in domeniul 0-15; nu se poate evalua adresa unui camp (deci operatorul & nu poate avea ca operand un camp de biti); nu se pot organiza tablouri de campuri de biti.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia12.html (2 of 5)10/2/2005 8:14:06

Lectia 12

Referirea unui element camp de biti dintr-o structura se face ca pentru orice alt tip de element, folosind operatorii de selectare directa sau indirecta (punct sau sageata). Numele campului poate sa lipseasca. In acest caz, se face alocarea bitilor specificati de valoarea "lungime", dar campul nu poate fi accesat. Pot fi alocati astfel biti care nu sunt utilizati dintr-un octet. Vom considera, ca exemplu, structura informatiei transferate intr-o comunicatie seriala sincrona dintre calculatoare, pe baza protocolului HDLC. In acest caz, blocurile de date transmise sunt completate cu anumite informatii de control, rezultand in final un "cadru" de date organizat ca o secventa de biti. Structura din exemplul urmator descrie un cadru de date HDLC in reprezentarea interna, utilizata de un program de comunicatie. Ea contine adresa si campul de control necesare protocolului si dimensiunea si adresa blocului de date :
struc cadru_i { unsigned char adresa;// adresa pe 8 biti /* camp de control pe 8 biti */ /* bit identificare cadru I*/ unsigned c_i:1; /*contor transmisie N (S) */ unsigned ns:3; /* bit PIF */ unsigned pf:1; /*contor receptie N (R) */ unsigned nr:3; /* dimansiunea si adresa blocului de date */ unsigned lng; char *data; };

Alocarea bitilor se face de la bitul 0 al octetului, in ordinea declararii. Astfel, daca se declara mai multe campuri care insumeaza cel mult 8 biti se aloca spatiul in cadrul aceluiasi octet. Pentru campurile de tip int (signed int) valorile sunt memorate in reprezentarea in complement fata de doi, pentru lungimea specificata. Campurile unsigned int contin valoarea binara inscrisa.La inscrierea unui camp de biti, programatorul trebuie sa urmareasca respectarea domeniului de valori corespunzator lungimii, altfel alocarea este alterata prin trunchiere. Campurile de biti se pot initializa la fel ca orice alt membru al structurii.

Uniuni

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia12.html (3 of 5)10/2/2005 8:14:06

Lectia 12

In unele situatii, apare necesitatea ca o aceeasi zona de memorie sa fie accesata la momente diferite de timp, in contexte diferite. De exemplu, consideram ca la inceputul unui program dorim ca o anumita zona de memorie sa fie accesata prin intermediul unei variabilede tip interg, urmand ca ulterior aceeasi zona de memorie sa fie accesata prin intermediul unei variabile de tip real. O zona de memorie poate fi alocata mai multor obiecte de tipuri diferite prin declarea unei uniuni. Sintaxa declaratiei este similara cu cea a structurii, dar identificatorii declarati ca membri reprezinta numele cu care sunt referite diferitele tipuri de obiectecare utilizeaza in comun zona de memorie. Declarea unei uniuni se face astfel : union identificator_tip_uniune { tip_element1 identificator_element1; ............................. tip_elementN identificator_elementN; } lista_identificatori_variabile_uniune; Spatiul alocat in memorie corespunde tipului cu dimensiune maxima. O variabila uniune poate fi initializata numai cu valoarea corespunzatoare primului membru. Pentru refolosirea unui membru al unui uniuni se folosesc tot operatorii de selectie "punct" si "sageata".
int k=5; float r=12.3; union tipifl nr,*pu=&nr; /* variabila initializata */ union tipifl alt_nr={10}; nr.i=k; /* nr contine valoarea intreaga 5 */ nr.f=r; /* nr contine valoarea float 12.3 */ pu->f=k; /* nr contine valoarea float 5.00 */

Pentru exemplificare putem relua structura unui cadru HDLC. In afara cadrelor de date de care ne-am ocupat in paragraful precedent, protocolul HDLC mai foloseste doua categorii de cadre de control al comunicatiei, cu format diferit : cadre de supervizare (S) si cadre nenumerotate(U). Aceste cadre se pot declara ca structuri cu campuri de biti in mod similar cu cadrele de date din exemplul 1 de la campuri de biti. In exemplul urmator se declara o uniune care poate fi utilizata pentru memorarea oricarui cadru HDLC:
union cadru_hdlc {
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia12.html (4 of 5)10/2/2005 8:14:06

Lectia 12

struc { /* cadru unsigned unsigned unsigned unsigned unsigned unsigned } cadru_i;

informatic */ char adresa; c_i:1; ns:3; pf:1; nr:3; lng;char *data

struct { /* cadru supervizare */ ....................... } cadru_s; struct { /* cadru nenumerotat */ ....................... } cadru_u; };

In aceasta prima varianta, declaratiile tipurilor membrilor uniunii sunt interne. Daca obtinerea acestui rezultat nu este dorita, declaratiile tipurilor de cadre se fac separat. De exemplu, prin utilizarea unor declaratii typedef, tipul uniune se poate declara mai simplu:
typedef struc {...} tip_c_i; typedef struc {...} tip_c_s; typedef struc {...} tip_c_u; typedef union { tip_c_i cadru_i; tip_c_s cadru_s; tip_c_u cadu_i; } cadru_hdlc;

Folosirea tipului uniune de cadre permite simplificarea programului de comunicatie, de exemplu in privinta manevrarii diferitelor cadre (transferuri de parametrii, liste, etc.) si a efectuarii prelucrarilor, care sunt similare pentru toate tipurile.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia12.html (5 of 5)10/2/2005 8:14:06

Lectia 13

LECTIA 13 INTRARI SI IESIRI


Obiective Prezentare generala

OBIECTIVE <home>
G

"intrari/iesiri standard "si functiile care permit utilizatorului sa schimbe date prin intermediul componentelor periferice cu diferite programe.

PREZENTARE GENERALA <home>


Prin intrari/iesiri intelegem un set de operatii care permit schimbul de date intre un program si un periferic. In general operatia de introducere a datelor de la un periferic se numeste citire, iar cea de iesire pe un periferic scriere. Numim terminal standard terminalul de la care sa lansat programul .De obicei terminalele standard sunt de tip display. In acest caz operatia se numeste si afisare. Limbajul C nu dispune de instructiuni specifice pentru operatiile de intrare/iesire. Ele pot fi apelate folosind functii special construite pentru acest scop. Utilizatorul poate el insusi sa construiasca astfel de functii, in cazul in care nu sunt utilizabile cele existente. Functiile de biblioteca, utilizate mai frecvent pentru realizarea operatiilor de intrare/iesire folosind terminalul standard sunt :
G G

pentru intrari: getch(),getche(),gets() si scanf(); pentru iesiri: putch,puts si printf().

FUNCTII gets() si puts()


Functia gets() poate fi folosita pentru a introduce de la terminalul standard o succesiune de caractere terminata prin actionarea tastei Enter. Citierea se face fara ecou. Se pot citi numai caractere ale codului ASCII. Functia are ca parametru adresa de inceput a zonei de memorie in care se pastreaza caracterele citite. De obicei ,in aceasta zona de memorie este alocata unui tablou unidimensional de tip char. Functia gets() returneaza adresa de inceput a zonei de memorie in care s-au pastrat caracterele. Functia puts() afisaza la terminalul standard un sir de caractere ale codului ASCII. Ea returneaza codulultimului caracter al sirului de caractere afisat . Ele au urmatoarele prototipuri :

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (1 of 13)10/2/2005 8:14:10

Lectia 13

char *gets(char *str); int puts(char *str); Functiile gets() si puts() au prototipurile in fisierul stdio.h .

FUNCTIA printf()
Functia printf() poate fi folosita pentru a afisa date pe ecranul terminalului standard sub controlul unor formate. printf(control , param 1 ,param 2,...,param n) unde:
G G

control: este un sir de caractere parametru 1, .., parametru n - sunt expresii.

Fiecare specificatie de conversie e introdusa prin caracterul % si incheiata printr-un caracter de conversie. Intre % si caracterul de conversie pot fi:
G G

G G

un semn minus care specifica alinierea la stanga in camp a argumentului convertit; un sir de digiti ce specifica o lungime minima a campului. Numarul convertit va fi introdus in camp la cel putin aceasta lungime sau mai mare , daca este necesar. Daca argumentul are mai putine caractere decat dimensiunea campului , el va fi aliniat la dreapta sau la stanga si va fi completat cu zero sau spatii pana la lungimea campului. Caracterul de completare utilizat in mod implicit e blank, iar daca dimensiunea campului a fost specificata prin leading zero, este zero; o virgula care separa lungimea campului de un alt sir de digiti; un sir de digiti ce specifica numarul maxim de caractere acceptate dintr-un sir sau numarul de pozitii dupa virgula zecimala.

Caracterele de conversie si semnificatiile lor sunt:


G G G G G G G

d,i argumentul e convertit in zecimal; o argumentul e convertit in octal fara semn; x,X argumentul e convertit in hexazecimal fara semn; u argumentul e convertit in zecimal fara semn; c argumentul e preluat ca un singur caracter; s argumentul e un sir de caractere terminat cu caracterul nul; e argumentul e luat ca virgula flotanta sau dubla precizie si convertit in notatia stiintifica in care lungimea sirului de cifre de dupa virgula flotanta este specificata de precizie ; f argumentul e luat ca virgula mobila sau dubla precizie si convertit in notatia normala;

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (2 of 13)10/2/2005 8:14:10

Lectia 13
G G

g este similar lui e sau f , dar se bazeaza pe precizie. % caracterul %.

FUNCTIA scanf()
scanf() citeste caractere de la intarea standard , le interpreteaza conform formatului specificat in control si memoreaza rezultatele in celelalte argumente, care sunt pointeri ce indica unde vor fi depuse datele convertite. Ea are urmatorul prototip: int scanf(const char control,...) Sirul de control contine specificatii de conversie care sunt utilizate pentru o interpretare directa a secventelor de intrare. Sirul de control poate sa contine:
G G G

spatii, taburi, caractere de linie noua care sunt ignorate caractere ordinare specificatii de conversie continand caracterul % si caracterul de suprimare, un numar optional de specificare a lungimii maxime a campului si un caracter de conversie.

Caracterul de conversie indica interpretarea campului de la intrare, argumentul corespunzator trebuind sa fie un pointer. Urmatoarele caractere de conversie sunt legale:
G G G G G

d,i un intreg zecimal e asteptat la intrare; o un intreg e asteptat la intrare; x un intreg hexazecimal e asteptat la intrare; h un intreg short e asteptat la intrare; c un singur caracter e asteptat la intrare; argumentul corespunzator trebuie sa fie un pointer la caracter; s un sir de caracter e asteptat la intrare; argumentul trebuie sa fie un pointer al unui tablou de caractere; f un numar in virgula flotanta e asteptat; argumentul corespunzator trebuie sa fie un pointer la un camp float. Caracterul de conversie e este un sinonim al lui f. Formatul prezentat la intrare pentru un float e alcatuit dintr-un semn optional, un sir de numere care pot sa contina si un punct zecimal si un camp de exponent care e format din E sau e, urmat de un intreg cu semn.

FUNCTIILE sscanf() si sprintf()


Functiile scanf() si printf() au corespondente functiile sscanf() si sprintf(), care executa acelasi tip de conversii, dar care opereaza prin intermediul unui sir si nu prin intrarea, respectiv iesirea, standard.

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (3 of 13)10/2/2005 8:14:10

Lectia 13

Formatul general este: sprintf(char*string,const char *control,...) sscanf(char *string,const char *control,...)

MACROURILE putchar() si getchar()


Aceste macrouri sunt definite in fisierul stdio.h. Macroul getchar permite citirea cu ecou a caracterelor de la terminalul standard. Se pot caractere ASCII, nu si caractere corespunzatoare tastelor speciale. getchar(); Macroul putchar afiseaza un caracter al codului ASCII. El afiseaza codul caracterului afisat sau eroare . putchar(expresie);

FUNCTIA putch()
Functia putch() afisaza un caracter pe ecranul terminalului standard.Ea are un parametru care determina imaginea afisata la terminal. putch(expresie);

Intrari/Iesiri orientate spre fisiere


Aceste operatii se realizeaza pin intermediul unor functii din biblioteca standard a limbajului. Aceste functii pot fi aplicate in mod eficient la o gama larga de aplicatii. Ele asigura o portabilitate buna a programelor, fiind implementate intr-o forma compatibila pe diferite sisteme de operare. In continuare ne vom referi la functiile din biblioteca standard I/O care au o utilizare frecventa in diferite aplicatii. Datele introduse de la tastatura unui terminal se considera ca formeaza un fisier de intrare. Datele care se afiseaza pe terminal formeaza un fisier de iesire. Prin intrarea standard se intelege tastatura terminalului de la care s-a lansat programul. Iesirea standard este ecranul aceluiasi terminal. Prelucrarea fisierelor implica un numar de operatii specifice acestora:
G

deschiderea de fisiere

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (4 of 13)10/2/2005 8:14:10

Lectia 13
G G G G G G G

inchiderea creare citirea (consultarea) inregistrarilor unui fisier actualizarea unui fisier adaugarea de inregistrari intr-un fisier pozitionarea intr-un fisier stergerea unui fisier

Tratarea fisierelor se poate face la doua nivele. Primul nivel face apel direct la sistemul de operare. Acesta este nivelul inferior de prelucrare a fisierelor. Al doilea nivel se realizeaza prin intermediul unor proceduri specializate de prelucrare a fisierelor care utilizeaza structuri speciale de tip fisier. Acesta este nivelul superior de prelucrare a fisierelor.

Nivelul inferior de prelucrare a fisierelor Deschiderea unui fisier


Deschiderea unui fisier se realizeaza cu ajutorul functiei open(). Functia open(), in forma cea mai simpla, se apeleaza printr-o expresie de atribuire de forma: df=open(...); unde: df=variabila de tip int. Prototipul functiei open() : int open (const char* cale, int acces); unde: - cale : este un pointer spre un sir de caractere care defineste calea spre fisierul care se deschide - acces : este o variabila de tip intreg care poate avea una din valorile urmatoare:
G G G G G G

O_RDONLY - fisierul se deschide numai la citire O_WRONLY - fisierul se deschide numai la scriere O_RDWR - fisierul se deschide in citire/scriere O_APPEND - fisierul se deschide pentru adaugarea de inregistrari la sfirsit O_BINARY - fisierul se prelucreaza binar O_TEXT - fiserul este de tip text (se prelucreaza pe caractere)

Pentru a crea un fisier nou se utilizeaza functia creat() in locul functiei open.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (5 of 13)10/2/2005 8:14:10

Lectia 13

Prototip: int creat(const char* calea, int mod); unde: - calea este un pointer spre un sir de caractere care defineste calea spre fisierul care se deschide in creare. - mod este un intreg care poate fi definit folosind constantele simbolice de mai jos :
G G G

S_IREAD : proprietarul poate citi fisierul S_IWRITE : proprietarul poate scrie un fisier S_IEXE : proprietarul poate executa programul continut in fisierul respectiv.

Functia creat(), ca si functia open(), returneaza descriptorul de fisier sau -1 in caz de eroare. Fisierele de I/O standard se deschid automat la lansarea programului in executie.

Citirea dintr-un fisier


Operatia de citire a unei inregistrari dintr-un fisier deschis se ralizeaza functia read(). Aceasta returneaza numarul de octeti dintr-un fisier sau -1 la eroare. Prototip: int read(int df, void *buf, unsigned lung); unde: - df este descriptorul de fisier returnat de functia open la deschiderea fisierului respectiv - buf este pointerul spre zona de memorie in care se pastreaza inregistrarea citita dintr-un fisier - lung este lungimea in octeti a inregistrarii citite. La un apel al functiei read() se citesc cel mult lung octeti. Cand se citesc inregistrari de pe disc, o valoare utilizata frecvent pentru lung este 512. Utilizarea functiei read() implica includerea fisierului io.h

Scrierea intr-un fisier


Pentru a scrie o inregistrare intr-un fisier folosim functia write(). Fisierul trebuie sa fie in prealabil deschis cu functia open() sau creat(). Functia write() este asemanatoare cu functia read() si are acelasi
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (6 of 13)10/2/2005 8:14:10

Lectia 13

prototip. Diferenta consta in aceea ca realizeaza transferul datelor in sens invers. Functia write()poate fi folosita pentru a scrie la cele doua iesiri standard, folosind descriptorii de fisier de valoare 1 sau 2. Utilizarea functiei write() implica includerea fisierului io.h.

Pozitionarea intr-un fisier


Inregistrarile se scriu una dupa alta pe suportul fisierului. Acest mod de scriere si acces la inregistrarile fisierului se numeste acces secvential. Apar situatii in care noi dorim sa scriem si sa citim inregistrari intr-o ordine diferita de cea secventiala. In acest caz se spune ca accesul la fisier este aleator. O pozitionare oriunde in fisierul respectiv este posibila pe suporturile de disc magnetic si se realizeaza cu functia lseek(). Prototipul functiei este : long lseek(int df, long deplasament, int origine); unde: - df este descriptorul de fisier - deplasament defineste numarul de octeti peste care se va deplasa capul de citire/scriere al discului - origine are una din valorile:
G G G

0 - deplasamentul se considera de la inceputul fisierului 1 - deplasamentul se considera din pozitia curenta a capului de citire/scriere 2 - deplasamentul se considera de la sfirsitul fisierului.

Utilizarea functiei lseek() implica includerea fisierului io.h.

Inchiderea unui fisier


Inchiderea unui fisier se realizeaza automat daca programul se termina prin apelul functiuni exit(). Programatorul poate inchide un fisier folosind close(). Prototipul functiei close(): int close (int df); unde: - df : descriptorul fisierului care se inchide. Utilizarea functiei close() implica includerea fisierului io.h.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (7 of 13)10/2/2005 8:14:10

Lectia 13

NIVELUL SUPERIOR DE PRELUCRARE A FISIERELOR


La acest nivel operatiile de prelucrare a fisierelor se executa uilizindu-se functii specializate de gestiune a fisierelor. Toate functiile din aceasta clasa au prototipurile in fisierul stdio.h.

Deschiderea unui fisier


Pentru a deschide un fisier se utilizeaza functia fopen(). Ea returneaza un pointer spre tipul FILE sau pointerul in caz de eroare. Prototipul: FILE *fopen(const char *calea,const char *mod); unde: - calea are aceeasi semnificatie ca si in cazul functiei open() - mod este un pointer spre un sir de caractere care defineste modul de prelucrare al fisierului dupa deschidere. Acest sir de caractere se defineste astfel:
G G G G G G G

"r" - deschidere in citire (read) "w" - deschidere in scriere (write) "a" - deschidere pentru adaugare (append) "r+" - deschidere pentru modificare "rb" - citire binara "wb" - scriere binara "r+b" - citire/scriere binara.

Cu ajutorul functiei fopen() se poate deschide un fisier inexistent in modul "w" sau "a". Pentru a utiliza aceste fisiere se vor folosi urmatorii pointeri spre tipul FILE: - stdin : pentru a citi de la intrarea standard - stdout : pentru a afisa pe ecranul de la iesirea standard - stderr : pentru afisarea erorilor la iesirea standard - stdprn : iesirea paralela pe imprimanta - stdaux : comunicatie seriala.

Prelucrarea pe caractere a unui fisier


Fisierele pot fi scrise si citite caracter cu caracter folosind doua functii simple.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (8 of 13)10/2/2005 8:14:10

Lectia 13

Functia putc() pentru scriere, al carei prototip este: int putc(int c,FILE *pf); unde: - c este codul ASCII al caracterului care se scrie in fisier - pf este un pointer spre tipul FILE a carui valoare a fost returnata de functia fopen() la deschiderea fisierului in care se face scrierea. pf poate fi unul din pointerii :
G G G G

stdout - iesire standard stderr - iesire standard pentru eroare stdprn - iesire paralela la imprimanta stdaux - iesire seriala.

Functia putc() returneaza valoarea lui c sau -1 la eroare. Macroul putchar() se defineste cu ajutorul functiei putc() astfel: #define putchar(c) putc(c,stdout) Functia getc() pentru citire, cu prototipul: int getc(FILE *pf); unde: - pf este pointerul de tipul FILE si poate fi unul din pointerii:
G G

stdin - intrare standard stdaux - intrare seriala

Functia getc() returneaza codul ASCII al caracterului citit din fisier. Macroul getchar() se defineste in fisierul stdio.h, astfel: #define getchar() getc(stdin)

Inchiderea unui fisier

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (9 of 13)10/2/2005 8:14:10

Lectia 13

Inchiderea unui fisier se realizeaza cu ajutorul functiei fclose(). Prototip: int fclose(FILE *pf); unde: - pf este pointerul spre tipul FILE. Functia returneaza valorile: 0 - la inchiderea normala 1 - la eroare.

Intrari/iesiri de siruri de caractere


Functia fgets() permite citirea inregistrarilor care sunt siruri de caractere intr-un fisier. Prototip: char *fgets(char *s,int n, FILE *pf); unde: - s este pointerul spre zona in care se pastreaza caracterele citite din fisier - n este dimensiunea in octeti a zonei in care se citesc caracterele din fisier - pf este pointerul spre tipul FILE a carui valoare s-a definit la deschiderea fisierului. Citirea caracterelor se intrerupe la intilnirea caracterului \n. In zona spre care se pointeaza "s" se pastreaza caracterul \n daca acesta a fost citit din fisier, iar apoi se memoreaza caracterul nul (\0). La intilnirea sfirsitului de fisier functia returneaza valoarea zero. Functia fputs() permite scrierea inregistrarilor care sunt siruri de caractere intr-un fisier. Prototip: int fputs(const char *s,FILE *pf); unde: - s este pointerul spre inceputul zonei de memorie care contine sirul de caractere care se scrie in fisier - pf este pointerul spre tipul FILE a carui valoare a fost definita la deschiderea fisierului prin apelul lui fopen(). Functia fputs() returneaza codul ASCII al ultimului caracter scris in fisier sau -1 la eroare.

Intrari/iesiri cu format
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (10 of 13)10/2/2005 8:14:10

Lectia 13

Biblioteca standard a limbajului C contine functii care permit realizarea operatiilor de intrare/iesire cu format. In acest scop se pot utiliza functiile fscanf() si fprintf(). Functia fscanf() citeste date dintr-un fisier si le converteste pastrind rezultatele acestor conversii in conformitate cu parametrii existenti la apelul functiei, in timp ce scanf() realizeaza acelasi lucru dar utilizind date din memorie. Functia fprintf() converteste date din format intern in format extern si apoi le scrie intr-un fisier, spre deosebire de functia sprintf() care realizeaza aceleasi conversii, dar rezultatele se pastreaza in memorie. Prototipul functiei fscanf(): int fscanf(FILE *pf, const char *format,...); unde: - pf este un pointer spre tipul FILE a carui valoare a fost definita prin apelul functiei fopen(). Acesta defineste fisierul din care se face citirea. Ceilalti parametrii sunt identici cu cei utilizati in functia scanf (). Functia fprintf(), ca si functiile printf() si sprintf(), returneaza numarul caracterelor scrise in fisier sau 1 in caz de eroare.

Eliberarea zonei tampon a unui fisier


In acest scop se poate utiliza functia fflush(). Prototip: int fflush(FILE *pf); unde: - pf este pointerul spre tipul FILE care defineste fisierul pentru care videaza zona tampon. Daca fisierul este deschis la scriere, atunci continutul zonei tampon se scrie in fisierul respectiv. Daca fisierul este deschis la citire, caracterele necitite in zona tampon se pierd, deoarece dupa apelul functiei zona tampon devine goala.

Pozitionarea intr-un fisier


Functia fseek() permite deplasarea capului de citire/scriere al discului in vederea prelucrarii inregistrarilor fisierului intr-o ordine diferita decit cea secventiala. Prototip: int fseek(FILE *pf, long deplasament, int origine);

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (11 of 13)10/2/2005 8:14:10

Lectia 13

unde: - pf este pointerul spre tipul FILE care defineste fisierul in care se face pozitionarea capului de citire/ scriere. Ceilalti parametrii se definesc la fel ca in cazul functiei lseek(). Functia fseek() returneaza valoarea zero la o valoare diferita de zero in caz de eroare. Functia ftell() permite sa cunoasca pozitia curenta a capului de citire/scriere. Prototip: long ftell(FILE *pf); unde: - pf este pointerul spre tipul FILE care defineste tipul in cauza. Functia returneaza valoarea care defineste pozitia curenta a capului de citire/scriere. Valoarea returnata este deplasamentul in octeti a pozitiei capului de citire/scriere fata de inceputul fisierului.

Prelucrarea fisierelor binare


Fisierele organizate ca date binare pot fi prelucrate folosind functiile fread() si fwrite(). La o citire/ scriere se transfera intr-o zona tampon (buffer) un numar de articole care se presupune ca au o lungime fixa. Articolul este o data de tip oarecare. Prototipul functiei fread() este: unsigned fread(void *ptr, unsigned dim, unsigned nrart, FILE *pf); unde: - ptr este pointerul spre zona tampon care contine articolele citite (inregistrarea citita) - dim defineste dimensiunea unui articol in octeti - nrart defineste numarul de articole din compunerea iregistrarii citite - pf este pointerul spre tipul FILE care defineste fisierul din care se face citirea. Functia returneaza numarul de articole citite sau -1 in caz de eroare. Functia fwrite() are protipul: unsigned fwrite(void *ptr, unsigned dim, unsigned nrart, FILE *pf); unde:

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (12 of 13)10/2/2005 8:14:10

Lectia 13

- ptr este pointerul spre zona tampon care contine articolele care se scriu in fisier - dim defineste lungimea unui articol - nrart defineste numarul de articole din compunerea inregistrarii care se scrie in fisier - pf este pointerul spre tipul FILE care defineste fisierul in care se scrie inregistrarea. Functia returneaza numarul articolelor scrise in fisier sau -1 in caz de eroare.

STERGEREA UNUI FISIER


Un fisier poate fi sters apelind functia un link() care are prototipul: int unlink(const char *calea); unde: - calea este un pointer spre un sir de caractere identic cu cel utilizat la crearea fisierului in functia creat sau fopen. Functia returneaza valoarea zero la o stergere reusita si -1 in caz de eroare.

REDIRECTAREA FISIERELOR DE INTRARE/IESIRE STANDARD


Functiile scanf(), printf(), gets() si puts(), precum si macrourile getchar() si putchar() pot fi utilizate si cu alte periferice daca, in prealabil, se face o redirectare a fiserelor standard de intrare/iesire. Acest lucru se realizeaza folosind, in linia de comanda a apelului executiei programului, caracterele C si >. < se foloseste pentru redirectarea fisierelor de intrare (stdin). > se foloseste pentru redirectarea fisierelor de iesire (stdout). Ele se folosesc astfel: <specificator_de_fisier_de_intrare si >specificator_de_fisier_de_iesire Specificatorul de fisier depinde de sistemul de operare utilizat. Fisierul de iesire standard pentru erori (stderr) nu poate fi redirectat.
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia13.html (13 of 13)10/2/2005 8:14:10

Lectia 14

LECTIA 14 PREPROCESORUL C
Obiective Prezentare generala

OBIECTIVE <home>
G

directive de compilare

PREZENTARE GENERALA <home>


Cu toate ca existenta mediului integrat este calea cea mai sigura si mai simpla de a produce programe in limbajul C++, nu este lipsit de importanta sa purtam o discutie si asupra elementelor asociate compilatoarelor utilizate in cadrul acestui mediu. Intr-un asemenea compilator la o prima parcurgere a programelor sursa, se vor include toate fisierele specificate in acest sens, se vor evalua toate expresiile conditionale ce vizeaza direct aceasta faza, deci cea a compilarii, se vor expanda toate expresiile macro si se va produce un fisier, intermediar, care va fi preluat de urmatoarea faza a compilarii. Deoarece acest fisier intermediar nu este regasit pe suportul fizic la sfirsitul etapei de compilare, atat mediul integrat, cat si compilatorul din linia de comanda sunt inzestrate cu un preprocesor, rolul acestuia fiind exact acela de a produce un astfel de fisier. Acest preprocesor este util in depanarea programelor, in inspectarea directivelor de includere, compilare conditionata si a expresiilor macro complexe.In continuare, vom enumera directivele preprocesorului, atat din punct de vedere sintactic, cat si din punct de vedere semantic. Preprocesorul C include un macroprocesor sofisticat, care scaneaza codul sursa inainte de a fi supus efectiv actiunii lui de compilare. Acesta ne furnizeaza o mare flexibilitate in:
G

definirea de expresii macro, care reduc efortul de programare si confera mai multa claritate codului. includerea textelor provenite din alte fisiere, astfel ca fisierele header contin constante si prototipuri de functii din bibliotecile standard si definite de utilizatori. stabilirea de conditii ce trebuie sa fie indeplinite pentru ca anumite portiuni de cod sa contribuie la faza de compilare.

Astfel orice linie care incepe cu caracterul # este considerata de catre preprocesor ca o directiva ce ii este adresata.

Directiva nula #
Aceasta directiva consta dintr-o linie care contine un singur caracter #. Aceasta este intotdeauna ignorata
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (1 of 8)10/2/2005 8:14:13

Lectia 14

de preprocesor.

Directivele #define si #undef


Directivele #define definesc constante macro. Acestea reprezinta un mecanism de inlocuire globala a unor nume, insotite de o lista de parametri formali. In cazul lipsei parametrilor, sintaxa este urmatoarea:
#define id_macro secv_definitie_macro

Fiecare aparitie a identificatorului expresiei macro, id_macro, in textul sursa al programului, dupa definitia introdusa cu #define, se va inlocui cu secventa ce expliciteaza corpul expresiei respective, secv_definitie_macro. Exista cateva exceptii de la aceasta regula si anume: nu se vor inlocui aparitiile numelui expresiei macro din cadrul sirurilor de caractere, constantelor siruri de caractere sau al comentariilor,
#define SALUT " Te salut, " #define PRIETEN " Ioane " #define LOCALITATE " , de la Agigea!" puts(SALUT); puts(PRIETEN); puts(LOCALITATE);

va produce : " Te salut, Ioane ,de la Agigea! " In cazul expresiilor macro cu parametri, sintaxa ce trebuie respectata in definirea acestora este:
#define id_macro(1_param) secv_definitie_macro

Nu trebuie sa existe nici un spatiu intre identificatorul expresiei macro si paranteza ce deschide lista parametrilor acestuia. In cadrul acestei liste, argumentele se vor desparti prin virgule si nu se va specifica tipul lor, din acest punct de vedere expresiile macro urmand protocolul C de declarare a functiilor. Apelul unui astfel de macro consta in doua seturi de inlocuiri. In primul rand, identificatorul expresiei macro si parantezele ce cuprind lista de argumente sunt inlocuite de sirul de definitie al expresiei, iar, incea de a doua etapa, argumentele formale ale acesteia sunt inlocuite de parametri efectivi.
#define SUMA(a,b) ((a)+(b)) int i,j,sum; sum=SUMA(i,j);

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (2 of 8)10/2/2005 8:14:13

Lectia 14

va expanda SUMA in ((i)+(j)). In cadrul expresiilor macro, nu se efectueaza verificarea tipurilor argumentelor, acest element nefiind utilizat nici in definirea expresiei. Sa consideram urmatorul exemplu :
#define PRODUS(a,b) ((a)*(b)) int i,j,prod; prod=PRODUS(i,j+1);

produsul se expandeaza in ((i)*(j+1)). Neglijand parantezele ce inconjoara parametrii formali, produsul va fi expandat in (i*j+1), fiind astfel evident ca nu aceasta a fost intentia noastra. Cateva cazuri in care se utilizeaza expresiile macro cu parametri: parantezele imbricate - Lista de parametri efectivi poate sa contina paranteze imbricate
#define SUMA(x,y) ((x)+(y)) return SUMA((f(i,j) , g(m,n));

construirea de nume - Putem obtine noi nume prin alipirea a doua nume utilizand operatorul ##, si eventual, spatii albe. Preprocesorul elimina spatiile albe si ##, combinand cele 2 nume intr-unul nou
#define VARIABILA(i,j) (i##j)

si apeland-o prin VARIABILA(x,6), obtinem identificatorul (x6). conversia de siruri prin # - Simbolul # poate fi plasat inaintea unui argument al expresiei macro pentru a-l converti intr-un sir de caractere, dupa inlocuire. Astfel avand urmatoarea definitie de macro:
#define URMA(flag) printf(#flag "= %d\n",flag)

fragmentul de cod
int valmax=1024; URMA(valmax);

devine
int valmax=1024;

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (3 of 8)10/2/2005 8:14:13

Lectia 14

printf("valmax" "= %d\n", valmax);

si este echivalent cu
printf("valmax= %d\n", valmax);

backslash pentru continuarea liniei - Un identificator prea lung poate fi descris pe mai multe linii utilizand caracterul "\" (backslash) ca terminator de linie intermediara. Preprocesorul elimina atat caracterul linie noua, cat si caracterul "\", pentru a furniza identificatorul real:
#define AVERTISMENT "Acesta este un avertisment !" puts(AVERTISMENT);

Directiva #undef este opusa directivei anterioare #undef id_macro, anuleaza definirea anterioara a expresiei macro, astfel ca orice utilizare ulterioara a acesteia va fi considerata eronata.

Incluziunea fisierelor. Directiva #include


Exista trei metode de a include fisiere unele in altele
#include <nume_fisier> #include "nume_fisier" #include id_macro

Preprocesorul inlatura linia #include si o inlocuieste, conceptual, cu continutul fisierului indicat, printruna din cele trei variante. Este normal ca sursa codului nu se va modifica, dar compilatorul vede fisierul extins. Din acest motiv, pozitia directivei poate influenta scopul si durata identificatorilor. In cazul in care este specificata o cale explicita pentru fisierul inclus, atunci numai acel fisier, daca exista, va fi inclus. Si acum, despre despre metodele de a include fisiere. Diferenta dintre primele doua metode consta in faptul ca, in timp ce prima varianta specifica un fisier standard pentru includere, localizarea sa facandu-se in fiecare director cu acest rol, in ordinea in care acestia s-au definit, in cea de a doua varianta localizarea fisierului de inclus va incepe cu directorul curent si se va continua abia apoi, cu directoarele destinate incluziunii de fisiere. In sfarsit, cea din urma varianta de includere presupune ca nici < si nici " nu vor aparea ca prim caracter in cadrul identificatorului. Mai mult se presupune ca explicitarea expresiei macro va produce un nume de fisier valid, bineinteles cuprins intre ghilimele sau paranteze <,>, reducand deci directiva la una din primele variante.
#include <stdio.h> #include "newgraph.h"

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (4 of 8)10/2/2005 8:14:13

Lectia 14

#define myinclud "c:\users\my_heads\graph.h" #include myinclud

Compilarea conditionata
Toate directivle de compilare conditionata trebuie sa fie incluse in fisierul in care s-a inceput efinirea lor. Directivele conditionale #if, #elif , #else si #endif functioneaza asemeni operatorilor conditionali ai limbajului. Ei sunt tilizati in urmatoarele variante:
#if expr_const_1 sectiunea_1 #elif expr_const_2 sectiunea_2 . . . #elif expr_const_n #else sectiunea_finala #endif

Daca expr_const_1 este nenula, in urma expandarii, liniile de cod din sectiunea_1 se vor procesa, altfel sectiunea_1 este ignorata. In cazul in care se proceseaza sectiunea_1, directiva de compilare conditionata, dupa procesarea sectiunii se incheie cu #endif. Daca expr_const_1 este nula deci neindeplinita, se va procesa in functie de sectiunea_2, respectiv n, sau cea finala. Directiva optionala #else, in cazul existentei sale, va fi considerata ca varianta in cazul in care nici una din conditiile anterioare nu a fost verificata. Sectiunea procesata poate contine si alte clauze conditionale, singura regula care trebuie urmata este aceea ca pentru fiecare #if existent sa existe un singur #endif. Dintre expresiile constante cele mai frecvente trebuie sa mentionam acele expresii ce sunt constituite prin intermediul operatorului defined acesta putand aparea intr-una din formele defined(id_const), sau defined id_const, amble fiind echivalente. Evaluarea unei expresii ce contine acest operator va furniza 1, in cazul in care id_const a fost definit si 0 in caz contrar. Astfel, directiva
#if defined(MYCONST)

este echivalenta cu
#ifdef MYCONST

Avantajul uitilizarii operatorului defined este acela ca acesta poate fi utilizat rpetat in cadrul unei aceleasi linii de directiva pe cand #ifdef sau #ifndef nu, cum ar fi in exemplul de mai jos:
#ifdefined (O_CONST) && ! defined (ALTA_CONST)

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (5 of 8)10/2/2005 8:14:13

Lectia 14

Mai mult, aceste din urma directive trebuie sa fie incheiate cu directiva #endif. Asa dupa cum observam putem forma expresii conditionale utilizand operatorul defined si operatorii relationali uzuali(&&,!).

DIRECTIVA #line
Comanda #line poate fi utilizata pentru a numerota liniile unui program, numarul liniilor fiind util in raportarea erorilor si, in special atunci cand programul analizat este multi-fisier, numerotarea fisierelor incluse incepand cu indicele liniei din programul principal, in care s-a efectuat includerea. Astfel sintaxa
#line ct_intreaga "nume_fisier"

indica faptul ca liniile urmatoare acesteia se vor numerota cu indicele ct_intreaga in fisierul nume_fisier. Odata folosit un nume de fisier, adresarile ultrioare ale directivei #line se vor referi la acelasi fisier. Expresiile macro sunt expandate in aceasta directiva ca si in cazul directivei #include.

DIRECTIVA #error
Aceasta directiva are urmatoarea sintaxa:
#error mesaj_eroare

si genereaza mesajul:
Error: nume_fisier line # :Error directive : mesaj_eroare

Aceasta directiva furnizeaza un mesaj atasat unei erori in compilare. De exemplu, presupunand ca am definit O_COND prin #defined O_COND, putem include urmatoarea conditie intr-unul din programele noastre pentru a testa o eventuala valoare incorecta a lui O_COND
#if (O_COND!=0 && O_COND!=1) #error O_COND trebuie sa aiba valoarea 0 sau 1 #endif

DIRECTIVA #pragma
Cu ajutorul acestei directive, programatorul poate implementa alte directive de forma:
#pragma nume_directiva

Cu ajutorul ei, C isi poate defini propriile directive, fara a genera conflicte cu alte compilatoare care
file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (6 of 8)10/2/2005 8:14:13

Lectia 14

admit aceleasi directive. Cand compilatorul nu recunoaste directiva indicata prin nume_directiva, el va ignora directiva #pragma, fara sa genereze nici macar un mesaj de avertisment. Borland C admite urmatoarele directive #pragma: #pragma argsused - est valabila numai in definirea functiilor si actioneaza numai asupra functiei imediat urmatoare. #pragma exit - permite programatorului de a stabili functii ce vor fi apelate numai inainte de iesirea din program. Sintaxa este:
#pragma exit nume_functie nr_prioritate

Functia indicata trebuie sa fie declarata si sa posede un prototip de genul:


void nume_functie (void)

In ceea ce priveste numarul optional, de prioritate, acesta trebuie sa fie un intreg din [64,255]. Cea mai mare prioritate este 0. Functiile cu prioritati mari sunt apelate ultimele la iesire. In cazul in care numarul de prioritate lipseste, se va considera numarul de prioritate implicit, acesta fiind 100. #pragma hdrfile - stabileste numele fisierului in care se vor depune headeri precompilati. Implicit, acest nume este TCDEF.SYM, iar sintaxa este:
#pragma hdrfile "nume_fisier.SYM"

In cazul in care nu utilizati headeri precompilati, directiva nu are efect. #pragma hdrstop - incheie lista fisierelor header utilizate in precompilare. Puteti utiliza aceasta directiva pentru a reduce dimensiunea spatiului utilizat de headeri precompilati. #pragma inline - semnalizeaza compilatorului existenta unor linii de cod in limbaj de asamblare in cadrul programului. Sintaxa este:
#pragma inline

Cel mai potrivit loc pentru a plasa aceasta directiva este inceputul fisierului, compilatorul reluand analiza la atingerea acestei directive. Scopul acestor dirctive este de a micsora timpul acordat compilarii. #pragma intrinsic - rescrie comutatoare ale liniei de comanda sau optiuni ale mediului integrat pt a controla expandarea inline a functiei utilizate in functii proprii. De exemplu

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (7 of 8)10/2/2005 8:14:13

Lectia 14

#pragma intrinsic strcpy

anuleaza expandarea inline a functiei indicate in functii proprii. Atunci cand se doreste expandarea unei functii includeti prototipul functiei inainte de a utiliza functia respectiva. #pragma option - include optiuni ale liniei de comanda in cadrul programului. Sintaxa este:
#pragma option optiune

Optiunile pot aparea oricat de multe, dar intr-o singura directiva. #pragma saveregs - asigura ca orice functie huge nu va modifica valoarea nici unui registru in momentul apelarii sale. Aceasta directiva este uneori necesara pentru interfatarea cu codul limbajului de asamblare. In plus, pozitionarea sa se va efectua in imediata vecinatate a definitiei functiei in cauza bineinteles inaintea acesteia. Directiva actioneaza asupra primei functii intalnite dupa ea. #pragma startup - permite programatorului sa stabileasca functii ce vor fi apelate chiar inainte de funtia main(). Sintaxa este:
#pragma startup nume_functie nr_prioritate.

#pragma warn - permte redefinirea comenzilor din linia de comanda -wxxx


#pragma warn +xxx #pragma warn -yyy

file:///E|/Math/cursuri/Informatica/Cursuri%20Anul%20I/MI%201103/Lectia14.html (8 of 8)10/2/2005 8:14:13