Sunteți pe pagina 1din 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

- Examen (E)

(pondere 35%) (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: Aplicatii:
Lectia 1
Scop:
Aplicatii:

Saptamana: 01-07.10

Introducere in C++

structura unui program, intrari/iesiri, variabile, instructiunea for

exercitii diverse

 
Lectia 2 Scop: Aplicatii:
Lectia 2
Scop:
Aplicatii:

Saptamana: 07-14.10

Fundamente (I)

constante, identificatori, declaratii, tipuri fundamentale, masive, enumerari

exercitii diverse

 
Lectia 3 Scop: Aplicatii:
Lectia 3
Scop:
Aplicatii:

Saptamana: 14-21.10

Fundamente (II)

pointeri, structuri(masive), conversii, typedef, constante

exercitii diverse

 
Lectia 4
Lectia 4

Fundamente (III)

Programare procedurala

Scop: Aplicatii:
Scop:
Aplicatii:

Saptamana: 21-28.10

Atributele datelor, operatori si expresii

.

 

exercitii diverse

 
Lectia 5 Scop: Aplicatii:
Lectia 5
Scop:
Aplicatii:

Saptamana: 28-03.11

Fundamente (IV)

Instructiuni

.

exercitii diverse

 
Lectia 6 Scop: Aplicatii:
Lectia 6
Scop:
Aplicatii:

Saptamana: 03-10.11

Fundamente (V)

 

Scopul, vizibilitatea si tipul identificatorilor, includerea enumerarilor, etichete, declaratii

exercitii diverse

 
Lectia 7 Scop: Aplicatii:
Lectia 7
Scop:
Aplicatii:

Saptamana: 10-17.11

Functii (I)

Declararea si argumentele functiilor, argumentele liniei de comanda

exercitii diverse

 
Lectia 8 Scop: Aplicatii:
Lectia 8
Scop:
Aplicatii:

Saptamana: 17-21.11

Functii (II)

Pointeri la functii, recursivitate

.

exercitii diverse

 

Lectia 9

Functii (III)

Scop: Aplicatii:
Scop:
Aplicatii:

Saptamana: 21-28.11

Prototip, functii cu numar variabil de argumente, utilizarea functiilor C in C++, parametri impliciti

 

exercitii diverse

 
Lectia 10 Scop:
Lectia 10
Scop:

Functii (IV)

Transmiterea parametrilor prin referinta, functii inline, redefinirea functiilor

Aplicatii:

exercitii diverse

Programare procedurala

Saptamana: 28-04.12

 
Lectia 11 Scop: Aplicatii:
Lectia 11
Scop:
Aplicatii:

Saptamana: 04-11.12

Structuri (I)

Structuri si functii, masive de structuri

.

exercitii diverse

 
Lectia 12 Scop: Aplicatii:
Lectia 12
Scop:
Aplicatii:

Saptamana: 11-18.12

Structuri (II)

Structuri cu autoreferire, campuri,

 

uniuni

.

exercitii diverse

 
Lectia 13 Scop: Aplicatii:
Lectia 13
Scop:
Aplicatii:

Saptamana: 18-25.12

Intrari si iesiri standard

Intrari si iesiri pe consola si fisiere

.

exercitii diverse

 
Lectia 14 Scop: Aplicatii:
Lectia 14
Scop:
Aplicatii:

Preprocesorul C

Directivele

preprocesorului

.

exercitii diverse

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

Lectia 1

LECTIA 1 INTRODUCERE IN PROGRAMAREA PROCEDURALA (Limbajul C)

Intrari si iesiri Obiective Prezentare generala Variabile
Intrari si iesiri Obiective Prezentare generala Variabile

Intrari si iesiri

Obiective

Prezentare generala

Intrari si iesiri Obiective Prezentare generala Variabile
Intrari si iesiri Obiective Prezentare generala Variabile
Intrari si iesiri Obiective Prezentare generala Variabile

OBIECTIVE<home>

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

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:

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

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:

"%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:

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:

int (variabilele sunt intregi)

Lectia 1

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:

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.

Lectia 2

LECTIA 2 FUNDAMENTELE LIMBAJULUI C (I)

Obiective Prezentare generala Constante Identificatori Declaratii Tipuri fundamentale Masive Enumerari
Obiective Prezentare generala Constante Identificatori Declaratii Tipuri fundamentale Masive Enumerari

Obiective

Prezentare generala

Obiective Prezentare generala Constante Identificatori Declaratii Tipuri fundamentale Masive Enumerari
Obiective Prezentare generala Constante Identificatori Declaratii Tipuri fundamentale Masive Enumerari

Constante

Identificatori

Declaratii

Tipuri fundamentale

Masive

Enumerari

OBIECTIVE <home>

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.

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

char c,linie[80]; char c; char linie[80];

int n;

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>

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

Reprezentare (in biti)

Domeniu

char

8

-128…127

unsigned char

8

0…255

signed char

8

-128…127

int

16

-32768…32767

unsigned int

16

0…65535

signed int

16

-32768…32767

short int

16

-32768…32767

unsigned short int

16

0…65535

signed short int

16

-32768…32767

long int

32

-2147483648…2147483746

signed long int

32

-2147483648…2147483746

unsigned long int

32

0…4294967295

float

32

3.4E-38…3.4E+38

double

64

1.7E-308…1.7E+308

Lectia 2

long double

80

3.4E-4932…1.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 facindu- se 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};

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.

Lectia 3

LECTIA 3 TIPURI DE DATE DERIVATE

Pointeri Structuri OBIECTIVE <home>
Pointeri
Structuri
OBIECTIVE <home>

Obiective

Prezentare generala

Referinte

Utilizarea constructiei typedef

Definirea constantelor

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

Masive

Conversii de tip

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

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>

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:

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:

stanga (l -value), data de adresa zonei de memorie (referinta);

dreapta (r -value), valoarea mamorata in zona respectiva (conform figurii de mai jos).

mamorata in zona respectiva (conform figurii de mai jos).

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.

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];

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.

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

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];

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 "*".

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;

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

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.

Lucrurile, in acest caz,

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.

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

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.

operatiei.

.Rezultatul insusi este de tipul superior. Mai precis, pentru

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;

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

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 prin intregi, acestia pot avea semn sau nu. De exemplu:

signed char byte;

byte=-87;

CONSTANTE SIMBOLICE.

255.

Deoarece caracterele sunt reprezentate

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

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.

Lectia 4

LECTIA 4 FUNDAMENTELE LIMBAJULUI C++ (III)

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

Atributele datelor

Accesibilitatea

Obiective

Prezentare generala

Clase de memorie

Operatori

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

Durata de viata

Expresii conditionale

OBIECTIVE <home>

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:

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

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:

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:

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.

Lectia 4

Operatorii limbajului C

[ ]

 

( )

.

- >

+ +

- -

&

*

+

-

~

!

/

%

< <

> >

<

>

<=

> =

= =

! =

^

|

&&

|

|

? :

=

* = > > =

/ =

%=

+ =

- =

< < =

& =

^ =

| =

,

#

# # - > *

sizeof

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

operatori unari - cu un operand

operatori binari - cu doi operanzi

operatori ternari - cu trei operanzi

Precedenta operatorilor in C

PRIORITATE

 

OPERATORI

EVALUARE

1.

( ) [ ] -> . ! ~ + - ++ -- & * (tip) sizeof ->* * / % + - << >> < <= > >= == !=

->

2.

<-

3.

->

4.

->

5.

->

6.

->

7.

->

8.

->

9.

&

->

10.

^

->

11.

|

->

12.

 

&&

->

13.

|

|

->

14.

?:

<-

15.

= *= /= %= += -= &= ^= |= <<= >>=

<-

16.

,

->

EXPRESII CONDITIONALE <home>

Instructiunea :

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.

Lectia 5

LECTIA 5 INSTRUCTIUNILE LIMBAJULUI C

Obiective Prezentare generala

Obiective

Prezentare generala

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:

vida;

expresie;

compusa;

B) Instructiuni conditionale:

if;

switch;

while;

C) Instructiuni de ciclare:

for;

do-while;

D) Instructiunea de transfer al controlului:

exit;

return;

continue;

break;

goto;

PREZENTARE GENERALA <home>

INSTRUCTIUNI

INSTRUCTIUNEA vida

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

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:

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.

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:

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

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.

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.

Lectia 6

LECTIA 6 FUNDAMENTE LIMBAJULUI C++ (v)

Obiective Prezentare generala

Obiective

Prezentare generala

Obiective Prezentare generala

OBIECTIVE <home>

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 :

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.

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 intr- un 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.

Lectia 6

Numele utilizate in C se impart in patru mari categorii:

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)

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++

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:

declaratii de variabile,

declaratii de tipuri de date, sau

prototipuri de functii.

Regulile de utilizare a variabilelor sunt:

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.

Lectia 7

LECTIA 7 FUNCTII (I)

Obiective Prezentare generala

Obiective

Prezentare generala

Obiective Prezentare generala

OBIECTIVE <home>

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() { }

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

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:

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,

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];

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:

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.

Lectia 8

LECTIA 8 FUNCTII (II)

Obiective Prezentare generala

Obiective

Prezentare generala

Obiective Prezentare generala

OBIECTIVE <home>

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);

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:

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.

Lectia 9

LECTIA 9 FUNCTII (III)

Obiective Prezentare generala

Obiective

Prezentare generala

Obiective Prezentare generala

OBIECTIVE <home>

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:

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

}

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

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.

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 multi- fisier.

double modul(double x)

{

if (x<0) return -x;

Lectia 9

else return x;

}

#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:

# 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:

double modul(double x);//Prototipul din header

#include "myfile3.h"

Lectia 9

double modul(double x)

{

if (x<0) return -x; else return x;

}

#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:

int modul(double x);//tipul valorii returnate eronat

#include "myfile4.h" double modul(double x)

{

if (x<0) return -x; else return x;

}

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 "(

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,

)",

fie prin (void). Ellipsis este un grup de trei puncte fara

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

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:

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.

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.

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( ).

Lectia 10

LECTIA 10 FUNCTII (IV)

Obiective Prezentare generala
Obiective
Prezentare generala

OBIECTIVE <home>

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).

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):

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.

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);

}

#include "header1.h"

void actiune(int &v)

{

v^=0*1010;

arata_valoarea(v);

}

void main()

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.

inline void arata_valoarea(int v)

{ printf("Valoarea este %d\n",v); }

#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"); }

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).

/* 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

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:

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 actual

Tip formal

Descrierea conversiei

T

T&

De la un obiect de tip T, la o referinta catre un obiect de tip T

T&

T

De la o referinta catre un obiect de tip T, la un obiect de tip T

T[ ]

*T

De la un tablou de obiecte de tip T, la un pointer catre un obiect de tip T

T

const T

De la un obiect de tip T, la un obiect constant de tip T

T

volatile T

De la un obiect de tip T, la un obiect volatil de tip T

F(args)

(*F)(args)

De la o functie cu tipurile argumentelor specificate la un pointer catre o functie cu aceeasi lista de argumente

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.

Lectia 11

LECTIA 11 STRUCTURI (I)

Obiective Prezentare generala

Obiective

Prezentare generala

Obiective Prezentare generala

OBIECTIVE <home>

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,