Sunteți pe pagina 1din 27

1

1. VARIABILE POINTER

Tipul pointer (indicator) reprezint adrese ale unor zone
de memorie. Facilitaile oferite pentru lucrul cu variabile
pointer reprezinta unul dintre atuurile cele mai importante ale
limbajului C. Din punct de vedere al coninutului zonei de
memorie adresate, se disting 2 categorii de pointeri:
un pointer de date (obiecte) conine adresa unei
variabile sau constante din memorie;
un pointer de funcii conine adresa codului
executabil al unei funcii.

Cele dou categorii de pointeri au roluri si proprieti
distincte. Exista n plus pointeri generici, numii pointeri void
(o a treia categorie), care pot conine adresa unui obiect
oarecare.

1.1 Declararea variabilelor pointer

Sintaxa declaraiei unui pointer de date este:

tip *id_ptr;

Simbolul * precizeaz ca id_ptr este numele unei
variabile pointer, iar tip este tipul obiectelor a cror adres o
va conine (tipul de baz al id_ptr).
Pentru toate operaiile, compilatorul interpreteaz zona
de memorie adresat de pointer ca obiect de tipul indicat n
declaraie, cu toate atributele tipului: dimensiunea zonei de
memorie necesar i semnificaia informaiei coninute.
Pentru pointeri este legal declaraia:

void *id_ptr;

Aceasta permite declararea unui pointer generic, care nu
are asociat un tip de date precis. Din accest motiv, n cazul
unui pointer void dimensiunea zonei de memorie adresate *i
interpretarea informaiei nu sunt definite, iar proprietile
difer de ale altor pointeri de obiecte.
Iata cteva exemple de declaraii:

Ex.1:

int *nptr;
float *a, rez;
void *orice_adr;
/* tablou de pointeri catre intregi */
int * tabptr [10];
/* dubla indirectare; pointer la pointer */
float ** adptr;

Variabila nptr este un pointer de obiecte int, iar variabila
tabptr este un tablou de 10 pointeri int. O variabila pointer
constituie la rndul ei un obiect, deci se poate declara un
pointer de pointer. n particular, n exemplul precedent, adptr
va putea conine adresa unui pointer de obiecte float.
Este important de reinut c orice variabil pointer
trebuie iniializat cu o valoare valid, 0 sau adresa unui
obiect sau a unei funcii, nainte de a fi utilizat. n caz
contrar, efectele pot fi grave deoarece la compilare sau n
timpul execuiei nu se fac verificri ale validitii valorilor
pointerilor.
Adresele obiectelor sau funciilor din program sunt
diferite de 0. Constanta intreag 0 poate fi atribuit oricrei
variabile pointer *i semnific faptul ca aceasta nu conine
adresa unui obiect sau a unei funcii. De obicei se folose*te
pentru atribuire identificatorul NULL=0, declarat in fi*ierele
antet standard (stdio.h, stdlib.h, etc). Pointeri de orice tip pot
fi comparai cu NULL sau 0 pentru a verifica egalitatea sau
inegalitatea.

1.2 Operatori specifici.

Opera#ii de atribuire cu pointeri

Exist doi operatori unari care permit folosirea
varabilelor pointer. n esen, efectul lor este destul de
simplu: operatorul & se folose*te pentru aflarea adresei unei
variabile oarecare, iar operatorul * pentru accesul la
variabila adresat de un pointer. Definiiile urmtoare sunt
mai riguroase.
Pentru o variabil id_var de tipul tip_var, expresia:

&id_var
se cite*te:
adresa variabiei id_var

Tipul rezultatului este pointer de obiecte tip_var *i
expresia are valoarea adresei obiectului id_var.
Pentru o variabil pointer de obiecte tip_ptr, numit
id_ptr, expresia:

*id_ptr
se cite*te:

la adresa id_ptr

Rezultatul este de tipul tip_ptr *i reprezint obiectul
adresat de id_ptr. Trebuie remarcat ca expresia *id_ptr are
valoare stnga (lvalue), deci poate fi folosit att pentru a
obine valoarea obiectului, ct *i pentru a o modifica printr-o
atribuire.
Aciunea accestor operatori se poate studia n exemplul
urmtor. Pentru vizualizarea adreselor se folose*te funcia
printf() cu specificatorul de format %p; adresele sunt
afi*ate n hexazecimal:

ex.1:

#include <stdio.h>
void main(void)
{
int iv=10, *iptr;
printf(\n Variabila iv se afl la adresa:%p, &iv);
printf(\n *i are valoarea iv=%d,iv);
iptr=&iv;
printf(\n Variabila iptr are valoarea:%p, iptr);
printf(\n *i adreseaz obiectul: %d\n,*iptr);
*iptr=20;
printf(\nAcum, iv are valoarea %d\n,iv);
}
Programul afi*eaz:
Variabila iv se afl la adresa: FFF4
*i are valoarea iv=10
Variabila iptr are valoarea: FFF4
*i adreseaz obiectul: 10
Acum, iv are valoarea 20
2
n urma atribuirii iptr=&iv, iptr preia adresa variabilei iv,
astfel ncat *iptr *i iv reprezint acela*i obiect, un ntreg cu
valoarea 10 de la adresa FFF4. Prin urmare, dup atribuire,
expresia *iptr se poate folosi n orice situaie n locul numelui
variabilei iv, inclusive n partea stng a unei atribuiri.
n mod normal, n situaia:

tip1 * id_ptr1;
tip2 id_var;
id_ptr1=&id_var;

tipurile tip1 *i tip2 coincid sau tip1 este void. n caz
contrar se poate constata o contradicie.
n general, n situaia:

tip1 * id_ptr1;
tip2 *id_ptr2, id_var;
id_ptr1=id_ptr2;
id_ptr1=&id_var;
pot fi identificate cazurile:
tip1 este void; atunci tip2 poate fi oarecare;
tip2 este void; atunci, n Turbo C tip1 poate fi
oarecare; afirmaia nu mai este valabil n C++;
tip1 *i tip2 sunt identice, atribuirea este corect *i nu
ridic nici o problem;
tip1 *i tip2 difer; atunci compilatorul genereaz un
mesaj de avertisment (conversie supect) sau eroare
(atribuire ilegal).
Dac tipurile difer, atribuirea se poate face printr-o
conversie explicit folosind operatorul cast:

id_ptr1=(tip1*)id_ptr2;
sau:
id_ptr1=(tip1*)&id_var;
De exemplu, varianta urmtoare va fi acceptat de
compilator fr obiecii:

ex.2:
int * iptr;
float rv1=5.55,rv2, *rptr;
iptr=(int *)&rv1;
rv2=*iptr; /* eroare la execuie */

n concluzie, trebuie reinut c tipul de baz este asociat
rigid unui pointer, n momentul compilrii, conform
declaraiei. Compilatorul C/C++ admite o serie de conversii
implicite *i explicite, datorit crora pointerii npot fi folosii
*i pentru a adresa obiecte de alte tipuri dect cel de baz.
Aceste conversii sunt valabile doar pentru operaia curent, n
continuare compilatorul nu va ine seama de tipul obiectului
adresat, ci de tipul declarat al pointerului. Dac un pointer
adreseaz un obiect de alt tip dect cel de baz, programul
trebuie s preia responsabilitatea de a asigura realizarea
corect a operaiilor.

1.3 Opera#ii arimetice cu pointeri

n afar de atribuire, se pot efectua cu pointeri operaii de
comparare, adunare *i scdere (inclusive incrementare *i
decrementare). De*i adresele au valori numerice ntregi fr
semn, operaiile cu pointeri sunt supuse unor reguli *i
restricii specifice.
Dac tipurile asociate operanzilor pointer nu coincid,
compilatorul poate afi*a un mesaj de avretisment sau eroare.
Se pot utiliza, desigur, conversii de tip explicite cu operatorul
cast, de forma (tip*).
Valorile a doi pointeri pot fi comparate folosind
operatorii relaionali, ca n exemplul:

ex.1:

int *p1,*p2;
if(p1<p2)
printf(p1=%p <p2=%p,p1,p2);

O operaie uzual, este compararea unui pointer cu o
valoare nul, pentru a verifica dac adreseaz un obiect:

if(p1==NULL)/*pointer nul*/
else /*pointer nenul*/

sau, mai concis:

if(!p1) /*pointer nul*/
else /*pointer nenul*/

Sunt admise operaii de adunare sau scdere ntre un
pointer de obiecte *i un ntreg, dar conform unei reguli
specifice. Pentru variabila pointer cu declaraia generic:
tip*id_ptr;

operaiile:

id_ptr+n
id_ptr-n

corespund adugrii/scderii la adresa id_ptr a valorii
n*sizeof(tip)

De exemplu:

ex.2:

float *fp1,*fp2; /*sizeof(float)=4*/
double *dp; /*sizeof(double)=8*/
.
fp2=fp1+5; /*fp2<-- adresa_fp1+5*4*/
dp=dp-2; /*dp<-- adresa_dp-2*8*/
fp1++; /*fp1<-- adresa_fp1+1*4*/
dp--; /*dp<-- adresa_dp-1*8*/

Este legal scderea a doi pointeri de obiecte de acela*i
tip. Rezultatul este o valoare ntreag reprezentnd diferena
de adrese divizat prin dimensiunea tipului de baz:
ex.3:

int i;
float *p1,*p2; /*sizeof(float)=4*/
i=p2-p1;
/*i=(adresa_p2-adresa_p1)/sizeof(float)*/

Trebuie remarcat c, datorit rolului tipului n operaiile
de adunare *i scdere, operanzii nu pot fi pointeri void sau
pointeri de funcii.
3
Restriciile impuse de compilator n privina
concordanei tipurilor pointerilor sunt utile pentru a preveni
apariia erorilor de execuie, care pot avea efecte periculoase,
necontrolabile, prin afectarea sistemului de operare. Aceste
restricii pot fi ns dep*ite folosind (cu atenie) conversiile
de tip explicite.

1.4 Tablouri +i pointeri

n C exist o legtur strns ntre tablouri *i variabilele
pointer. Un nume de tablou fr index este un pointer
constant de tipul elementelor tabloului *i are ca valoare
adresa primului element din tablou. Operaiile aritmetice cu
pointeri sunt definite considernd c obiectele adresate
constituie un tablou. De altfel, aceasta este aplicaia uzual a
aritmeticii cu pointeri, avnd n vedere c programatorul
ignor de regul amplasarea variabilelor n memorie. De
exemplu, pentru declaraiile:

ex.1:

float ftab[0],*fptr;
int i;

atribuirea: fptr=ftab;
este valid. fptr va conineadresa primului element din ftab,
iar expresiile urmtoare sunt echivalente:

1. &ftab[0] <= => ftab
2. &ftab[i] <= => ftab+i
3. ftab[0] <= => *ftab
4. ftab[4] <= => *(ftab+4)
5. fptr+i <= => fptr[i]

Expresia:

(&ftab[7]-ftab)= =7
este adevarat.
Se observ c adunarea ntre pointeri *i ntregi ofer o
alternativ pentru adresarea elementelor unui tablou.
Utilizarea pointerilor poate fi mai rapid dect indexarea, de
exemplu la parcurgerea unui tablou. Pentru determinarea
lungimii unui *ir de caractere, este posibil soluia:

ex.2:

int i, cnt;
char str[10];

for(cnt=0;str[cnt];cnt++);

Iat *i o variant care folose*te o variabil pointer pentru
parcurgerea *irului:

ex.2:

int cnt;
char str[10],*p=str;
..
for(cnt=0;*p;p++)cnt++;

n cazul unei constante *ir de caractere, compilatorul
aloc zona de memorie necesar *i nscrie codurile ASCII ale
caracterelor *i terminatorul \0. Adresa zonei poate fi
atribuit unui pointer de caractere:

ex.3:
char*sptr;
.
sptr=un text;

n felul acesta se poate face *i iniializarea unui *ir sau
pointer de caractere:

char*sptr=un text;
sau:
char sptr[8]=un text;
sau:
char sptr[]=un text;

Trebuie remarcat faptul c tablourile multidimensionale
reprezint tablouri cu elemente tablouri, astfel nct numele
tabloului (fr indexare) este un pointer de tablouri:

ex.4:

float mat [10][10];
float *fp;
fp=mat; /*eroare sau avertisment*/

Atribuirea va produce un mesaj de eroare sau de
avertisment, deoarece mat este pointer de tablouri float cu 10
elemente *i nu un pointer float. De altfel, putem afla imediat
dimensiunea obiectului indicat de mat. Apelul:

printf(%d,sizeof(*mat));

afi*eaz valoarea 40, adic exact 10 valori float cu 4 octei
fiecare. Din acela*i motiv, sunt adevrate urmtoarele relaii;

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

Pentru o matrice:

tip mat[N][M];

adresa elementului mat [i][j] este dat de reaia:

&mat[i][j]==mat+(i*N+j)*sizeof(tip)
sau:
&mat[i][j]==mat+i*sizeof(*mat)+j*sizeof(tip)

Dac numele unui tablou, fr indexare, apare ca
operand intr-o expresie sizeof, el refer ntregul tablou. De
exemplu:

ex.5:
float tab[5],mat[10][10];
printf(tab ocup %4d octei,sizeof tab);
printf(mat ocup %4d octei,sizeof mat);
Programul afi*eaz:
tab ocup 20octei
mat ocup 400octei
4
2. VARIABILE DINAMICE

Pentru toate tipurile de date descrise, dimensiunea zonei
de memorie care este necesar este determinat prin
declaraie *i deci fixat naintea lansrii n execuie a
programului.
n cazul structurilor de date a cror dimensiune nu este
cunoscut a priori sau variaz n limite largi in timpul
execuiei programului, este necesar o alt abordare. Zona de
memorie necesar se aloc prin program, n timpul execuiei,
este folosit, iar atunci cnd nu mai este util se elibereaz
prin program pentru a putea fi realocat n alt scop.
Variabilele create astfel se numesc dinamice.
Spre deosebire de alte limbaje, C nu posed un sistem de
alocare *i eliberare pentru variabile dinamice ncorporate. Ca
*i n alte cazuri, motivul este reducerea complexitii
limbajului *i cre*terea flexibilitii.
Biblioteca C ofer ns un set bogat de funcii pentru
alocarea *i eliberarea memoriei n timpul execuiei
programului. Prototipurile se afl n fisierele alloc.h *i
stdlib.h. cel mai frecvent se folosesc funciile malloc() *i
free(), de care ne vom ocupa n continuare.
Organizarea spaiului de memorie n Turbo C++ se poate
face n mai multe variante, numite modelele de memorie .
Zona de memorie n care se face alocarea se nume*te heap.
De exemplu, n cazul modelului de memorie small, zona heap
este cuprins ntre zona ocupat de program *i variabilele
permanente (de dimensiune fix) *i cea ocupat de stiv (de
dimensiune variabil). Funcia care efectueaz alocarea are
prototipul:

void*malloc(unsigned nr_octe#i);

Parametrul indic dimensiunea n octei a zonei
solicitate. Dac operaia este efectuat cu success, funcia
ntoarce un pointer care conine adresa primului octet al zonei
allocate. Dac spaiul disponibil este insuficient, rezultatul
este NULL (=0).
Deoarece funcia ntoarce un pointer void, n Turbo C
rezultatul poate fi atribuit oricrui tip de pointer. Pentru a
asigura portabilitatea programelor, este recomandabil s se
utilizeze operatorul cast pentru conversie de tip la atribuire *i
operatorul sizeof pentru precizarea dimensiunii zonei
solicitate.
De exemplu, pentru alocarea unei zone pentru 10 valori
de tipul int, se poate proceda astfel:

ex.1:
int *ip;
ip=(int*)malloc(10*sizeof(int));

Atunci cnd variabila dinamic nu mai este util, spaiul
alocat trebuie eliberat pentru a putea fi refolosit. Evident,
eliberarea rmne n sarcina programatorului, care poate
apela funcia:

void free(void*ptr);

Parametrul indic adresa zonei care trebuie eliberat.
Transferal unei valori invalide (care nu este rezultatul unui
apel al funciei malloc()) compromite funcionarea sistemului
de alocare. Zona alocat n exemplul 1 se poate elibera prin
apelul:

ex.1:
free(ip);

Trebuie remarcat c zona de memorie alocat ca n
exemplul precedent este echivalent cu un tablou de tipul
respective. Elementele pot fi referite indexat, de exemplu
ip[5] este obiectul int de la adresa ip+5.
n programul din exemplul urmtor funcia inval()
permite introducerea de la tastatur a unui numr oarecare de
valori reale, care sunt prelucrate n main() *i apoi memoria
alocat este eliberat:
ex.2:
#include<stdio.h>
#include <stdlib.h>
float *inval(void)
{
float *ptr;
int i, nr;
printf(precizai numrul de valori (float):);
scanf(%d,&nr);
if(!(ptr=malloc(sizeof(float)*nr))){
puts(Memorie insuficient);
return NULL;}
for (i=0; i; i++){
printf(Introducei valoarea %d,i);
scanf(%f,ptr+i);}
return ptr; }
}
void main(void)
{
float *p;
p=inval();
/* utilizarea tabloului*/
free(p);
}

n programele nceptorilor apar frecvent o serie de erori
n cazul utilizrii variabilelor dinamice n interiorul unei
funcii. S considerm exemplul a dou funcii: prima, fct1(),
folose*te o variabil dinamic pentru prelucrri locale, iar a
doua, fct2(), creaz o variabil dinamic necesar functiei
apelante:

ex.3:
void fct();
{
long*p;

p=malloc(10*sizeof(long));

}
void fct2()
}
long*q;
...
q=malloc(25*sizeof(long));
}

Variabilele p *i q sunt locate functiilor *i timpul lor de
via este limitat la durata execuiei funciei respective. Pe de
alt parte, zona alocat *i adresat de ele rmne alocat pn
la eliberarea printr-un apel al funciei free().
5
n cazul funciei fct1(), eroarea const n omiterea
eliberrii variabilei dinamice adresate de p. Acest lucru este
neaprat necesar, deoarece disparitia pointerului local p nu
determin eliberarea zonei alocate dinamic pe care o
adreseaz.
n cea ce priveste funcia fct2(), la revenirea n funcia
apelant, de*i variabila dinamic exist n memorie, ea nu
mai poate fi accesat *i nici eliberat deoarece pointerul q
dispare! Soluia corect este cea din exemplul 2, adic
ntoarcerea ca rezultat a adresei variabilei dinamice (sau,
numai dac este efectiv necesar, utilizarea unui pointer
global).
Alocarea memoriei se poate face *i cu functia:

void*calloc(unsigned nr_blocuri,unsigned m3rime_bloc);

Deosebirea fa de malloc() const n modul de
specificare a dimensiunii *i n faptul c zona alocat este
iniializat cu 0. Se aloc o zon cu dimensiunea:

(nr_blocuri*mrime_bloc) octeti

Exemplu 1se poate rescrie n felul urmtor:

ex.4:
int*ip;
ip=(int*)calloc(10,sizeof(int));

Eliberarea se face tot cu funcia free(). Funcia calloc()
nu prezint avantaje semnificative fa de malloc(), n afar
de situaia n care iniializarea blocului alocat este util.
Biblioteca C dispune *i de alte functii pentru alocarea *i
eliberarea dinamic a memoriei, prezentate pe scurt n anexa
de funcii: coreleft(), realloc() *i variantele pentru zona heap
ndeprtat: farmalloc(), farcalloc(), farfree(),etc.

3. STRUCTURI, UNIUNI 6I
CMPURI DE BI8I
Informatia prelucrat n program este organizat n
general n ansambluri de date de tipuri diferite, astfel nct
tipurile predefinite (fundamentale *i derivate) prezentate n
capitolele anterioare nu sunt suficiente pentru o reprezentare
convenabil. Este necesar ca programatorul s-*i poat defini
tipuri care s descrie mai exact structurile de date cu care
opereaz programul.
Limbajul C ofer urmtoarele posibiliti:
declara#ia typedef asociaz un nume unui tip
structura este o colecie de obiecte de orice tip,
referite cu un nume comun;
cmpul de bi#i este un membru al unei structuri care
are alocat un grup de bii, n interiorul unui cuvnt
de memorie;
uniunea permite utilizarea n comun a unei zone de
memorie de ctre mai multe obiecte de tipuri
diferite;
enumerarea este o list de identificare cu valori
ntregi,constante.

3.1 Structuri
Declararea +i ini#ializarea structurilor.
Operatori de selectare a membrilor.

O declaraie de structur precizeaz identificatorii *i
tipurile elementelor componente *i constituie o definiie a
unui tip de date nou. Acestui tip I se poate asocial un nume.
Sintaxa declaraiei unui tip structur, n cazul general, este:

declaratie_structur:
struct nume_struct {
tip_1 id_elem_1;
tip_2 id_elem_2;
...
tip_N id_elem_N;
} lista_var_struct;
unde:
struct=cuvntul cheie pentru tipuri structur
nume_struct=numele tipului structur declarat;
tip_k=tipul elementului k;
id_elem_k=numele elementului k;
lista_var_struct=lista cu numele variabilelor de tipul
declarat, nume_struct;

Pot s lipseasc fie numele tipului (structur anonim ),
fie lista de variabile, dar trebuie s existe cel puin una dintre
specificaii. De regul numele tipului structur nu se omite
deoarece permite declararea ulterioar a unor variabile *i
parametric cu sintaxa:

struct nume_struct lista_identif_var_struct;

Componentele unei structuri sunt numite generic
membrii (cmpurile) structurii. Tipurile membrilor pot fi
oarecare, cu excepia tipului structur care se declar (dar se
admit pointeri de tipul structur respectiv). Identificatorii
membrilor trebuie s fie unici n cadrul structurii.
n exemplul urmtor se declar tipul adr, variabia adresa
*i tabloul lista[] de tip adr. Definiia tipului adr este folosit
n continuare pentru a declara variabila adresa_mea *i
tabloul alta_lista[]:
ex.1:
struct adr {
char nume[30], strada[20], loc[20];
int nr, bloc,ap;
long cod;
} adresa, lista[100];
main()
{
struct adr adresa_mea, alta_lista[10];

}
Iniializarea unei variabile structur se face prin
enumerarea valorilor membrilor, n ordinea n care apar n
declaraie. Pentru structura adr, se poate scrie:

ex.2:
struct adr va1={Ion,Sarari,Craiova ,3,5,56,200031};

Referirea unui membru al unei variabile structur se face
folosind operatorul de selec#ie(.) (punct) ntr-o expresie cu
valoare stnga care precizeaz numele variabilei *i al
membrului:
6
ex.3:
strcpy(adresa.loc,Bucure*ti);
adresa.cod=200065;

Operatorul de atribuire admite ca operanzi variabile
structur de acela*i tip, efectund toate atribuirile membru cu
membru. De exemplu, atribuirea urmtoare copiaz toate
valorile din variabila adresa in elementul 10 al tabloului de
adrese lista[]:
ex.4:
lista[10]=adresa;

Structurile sunt frecvent referite prin intermediul unei
variabile pointer, de exemplu:

ex.5:
struct adr *padr;
padr=&lista[5];
(*padr).nume=Popa Ion;

Referirea unui element al unei structuri indicate de un
pointer ca n exemplul anterior este posibil, dar neuzual. n
C exista un operator dedicat acestui scop, numit operatorul
de selec#ie indirect3:-> (sgeata).

ex.6:
padr->nume=Popa Ion;

n declaraia structurii din exemplul 1 se poate folosi
specificatorul typedef:

ex.7:
typedef struct {
char nume[30], strada[20], loc[20];
int nr, bloc, ap;
long cod;
} t_adr;

n acest caz, tipul structur este numit t_adr *i declararea
variabilelor se poate face mai comod, fr s mai fie necesar
adugarea cuvntului struct:
t_adr adresa, lista[100];

Transferul unui parametru de tip structur se poate face
prin valoare. Parametrul formal *i cel efectiv trebuie s fie de
acela*i tip structur. De multe ori se folose*te ns transferl
unui pointer ctre structur, chiar dac n funcie nu trebuie
modificat parametrul efectiv, deoarece se elimin operaia
consumatoare de tip de copiere a valorii n variabila local.
Un membru al unei structuri poate fi transferat dac tipul su
coincide (sau este compatibil) cu tipul parametrului formal
corespunztor.

Un alt exemplu de utilizare a structurilor este pentru un punct
care este dat de coordonatele sale x *i y. Deci putem crea o
structur care s aib dou cmpuri x *i y de tip ntreg:
struct punct {
int x;
int y;
};
Acum putem s declarm variabile de acest tip astfel:
struct punct pt;
struct punct mpt={120,200};
iar accesul la un membru sau altul se face astfel:
pt.x=100;
pt.y=pt.x+10;
Pentru a afi*a coordonatele unui punct:
printf(%d, %d ,pt.x, pt.y);
Pentru a calcula de exemplu distana de la origine la pt:

distana=sqrt((double)pt.x*pt.x + (double) pt.y*pt.y);

Structurile pot s fie ncuibate. De exemplu, o
reprezentare a unui dreptunghi este dat de o pereche de
puncte ce reprezint o diagonal:
struct dreptunghi {
struct punct pt1;
struct punct pt2;
};
struct dreptunghi d1;
d1.pt1.x=10 /*seteaz la 10 coordonata x a
membrului pt1 */

Dac problema impune crearea de *iruri iar fiecare
element al *irului este de tip structur se poate declara un *ir
de structuri astfel:

struct punct sirp[10];
iar acesul : sirp[0].x=90; /*atribuie membrului x al
elementului 0 din *ir valoarea 90*/

Spaiul alocat n acest caz este de doi intregi (4octei)
pentru fiecare element al *irului, deci 40 de octei.

3.2 Uniuni
Definitie: O variabil de tip uniune este o variabil care
poate memora (la momente diferite) obiecte de tipuri *i
dimensiuni diferite, compilatorul avnd grij de dimensiunea
*i alinierile cerute.
Uniunea este de fapt o zon de memorie alocat mai
multor obiecte de tipuri diferite. Sintaxa declaraiei este
similar cu cea a structurii dar identificatorii declarai ca
membri reprezint numele cu care sunt referite diferitele
tipuri de obiecte care utilizeaz n comun zona de memorie.
Declaraia uniunii este:
union nume_uniune {
tip_1 identif_1;
tip_2 identif_2;

tip_n identif_n;
} lista_var_uniune;
Spaiul alocat n memorie corespunde tipului cu
dimensiune maxim.
O variabil uniune poate fi iniializat numai cu valoarea
corespunztoare primului membru. Pentru referirea unui
membru al unei uniuni se folosesc operatorii punct *i
sgeat.

Ex1. Seciunea de program ce conine declararea unei uniuni
*i operaii cu variabile de acest tip:

union u1 {
int i;
float f;
} v1;
int k = 10;
7
float r=45,89;
union u1 *p1=&v1;
union u1 v2={100}; /* variabil initializat */
v1.i=k; /*v1 conine valoarea intreag 10 */
v1.f=r; /* v1 conine valoarea float 45,89 */
p1-->f=k; /* v1 conine valoarea float10,00 */

Ex2. Exemplul urmtor ne permite s accesm o zon de
memorie fie ca o pereche de caractere (unsigned char) fie ca
un ntreg (unsigned short):

struct bytes {
unsigned char low;
unsigned char high;
};
union word {
unsigned short word;
struct bytes byte;
};
void main (void)
{
union word data;
unsigned short temp;
data.word = 1000; /* Salveaz data in memorie ca word
*i l afi*az in format zecimal si hexazecimal */
printf(Word= %u (%X hexa) \n, data.word,
data.word);
/* afisez valorile celor doi bytes din ntreg individual ca
low si high */
ptintf(Low byte = %u (%X hexa) \n, data.byte.low,
data.byte.low);
printf(High byte = %u (%X hexa) \n, data.byte.high,
data.byte.high);
/* Calculeaza valoarea ntregului obtinut din octeii high
si low */
temp=256*data.byte.high+data.byte.low
printf( Intregul calculat = %u ,temp);
}
3.3. Cmpuri de bi#i
Definiie. Un cmp de bii este o colecie de bii care
asigur o memorare compact pentru obiecte cu o gam
limitat de valori.
Forma general a declaraiei cmpului de bii este bazat
pe declaraia structurilor *i are urmtoarea sintax:
struct nume {
unsigned cmp_1 : dimens_1;
unsigned cmp_2 : dimens_2;

unsigned cmp_n : dimens_n;
}
Declararea variabilelor de tip cmpuri de bii (bitfield) *i
accesul la cmpuri se face exact ca pentru orice alt structur.
Pentru a exemplifica s presupunem c dorim s realizm un
program care s memoreze 100000 date. Pentru aceasta
putem declara urmtoarea structur:
struct Data{
int luna; /* 1 pina la 12 */
int ziua; /* 1 pina la 31 */
int an; /* 0 la 99 (doar ultimile doua cifre ) */
};
Se observ ca o variabil de acest tip ocup 6 octei de*i
fiecare membru al acestei sructuri luat separat ocup la
valoarea maxim mai putin de un octet
Deci pentru o folosire optim a memoriei *i pentru a
realiza un program u*or de neles putem crea o structur
bitfield:

struct Data {
unsigned luna :4;
unsigned ziua :5;
unsigned an :7;
} date;

atribuirile se realizeaz astfel:

date.luna=12;
date.ziua=1;
date.an=97;
iar vizualizarea : printf(%d-%d-%d
,date.luna,date.ziua.date.an);

Problem rezolvat
Fie un grup de N studeni indentificai prin numele lor.
Fiecare student mai are asociate trei note la cele trei
examene din sesiune. S se afieze toi studenii a cror
medie este mai mare sau egal cu 5.

Rezolvare : Datorit faptului c fiecare student are asociat
informaie de mai multe tipuri(nume,nota1,nota2,nota3) vom
folosi o structur ca tip de date aferent studenilor. Aceast
structur va conine un cmp nume de tip *ir de caractere *i
trei cmpuri ntregi: nota1,nota2,nota3.

Deci structura este:
struct student {
char*nume;
int nota 1;
int nota 2;
int nota 3;
};

Cei N studeni vor fi memorai ntr-un *ir de elemente de tip
struct student. Deci : struct student s[20];
Se mai folose*te o variabil de tip float medie pentru a
memora media fiecrui student. Programul este urmtorul:

#include<stdio.h>
#include<process.h>
#include<alloc.h>
struct stud {
char *nume;
int nota1;
int nota2;
int nota3;
} s[20]; /*structura ce conine informaii
despre studeni */
int i,n;
float media;
void main (void)
{
printf(" Dati numrul de studenti: ");
scanf("%d",&n);
8
for(i=0;i<n;i++)
{
if((s[i].nume=(char*)calloc(10,sizeof(char)))==NULL)
{printf("Eroare");exit(0); } /* aloc. spaiului ptr nume*/
printf(" NUME=");
scanf("%s",s[i].nume);
printf(" NOTA1=");
scanf("%d",&s[i].nota1);
printf(" NOTA2=");
scanf("%d",&s[i].nota2);
printf(" NOTA3=");
scanf("%d",&s[i].nota3);
} /* sfarsitul ciclului for*/
i=0;
while(i<n)
{
media=(s[i].nota1+s[i].nota2+s[i].nota3)/3; /* calculul
mediei */
if(media>=5)
{
printf("%f\n",media);
puts(s[i].nume);
}
i++;
} /* sfrsit while */
} /* sfrsit main */

4. UTILIZAREA LISTELOR

n foarte multe situatii apare necesitatea organizrii
informaiilor prelucrate de calculator sub forma unor
liste.Exemplele pot fi nenumrate:lista studenilor dintr-un an
de studiu, lista produselor dintr-un magazin, lista persoanelor
cu drept de vot etc..O list con!ine o multime de elemente de
aceela*i tip. n general informatia dintr-un element al listei
este complex"; de exemplu n cazul listei studentilor dintr-un
an de studiu, fiecare element al listei va conine informaii
despre un anumit student. Acestea ar putea fi: numele,
prenumele, adresa, numarul de telefon, data na*terii *i situaia
*colar. Din aceast cauz", n majoritatea cazurilor un
element al unei listei este reprezentat sub forma unei
structuri.
La parcurgerea unei liste suntem de obicei interesai de
una dintre informaiile memorate n fiecare element. De
exemplu, pentru a afla care dintre studeni primesc burs va
trebui sa consultm pentru fiecare element cmpul referitor la
media general. Acesta va reprezenta cheia folosit la
cutare. Cheia poate fi simpl, atunci cnd informaia de
interes se regase*te ntr-un singur cmp al elementului, sau
compus, atunci cnd este necesar" consultarea mai multor
cmpuri. Una dintre cele mai frecvente situaii de acest gen
este cutarea unei anumite persoane, operaie care impune
consultarea cmpurilor de nume, prenume, *i eventual
adres".
Cea mai simpl modalitate de reprezentare a unei liste
este sub forma unui tablou unidimensional ale crui elemente
sunt structuri ce conin informaiile utile. Aceast soluie este
convenabil atunci cnd numrul de elemente din list este
fix *i cunoscut, sau atunci cnd se poate preciza o limit
superioar a numarului de elemente *i aceasta are o valoare
rezonabil. n multe situaii nsa, numarul de elemente ale
listei nu este fix *i nu se poate aprecia dimensiunea ei
maxim. S considerm c dorim s crem o list a
studenilor bursieri *i o list a studenilor nebursieri. Dac
notm cu N num"rul de studeni din an, atunci dimensiunea
maxim a fiecarei dintre aceste liste este N (teoretic s-ar
putea ca toi studenii s primeasc burs sau ca nici unul s
nu primeasca). Am putea deci reprezenta fiecare dintre aceste
liste ca un tablou de maxim N elemente. Aceasta ar nseamna
rezervarea unui spaiu de 2*N elemente. Dar, ntotdeauna
numrul elementelor din lista de studeni bursieri + numrul
elementelor din lista de studeni nebursieri = N, deci am
alocat de 2 ori mai mult spaiu dect era necesar. Cele dou
liste nu au dimensiune fix, deoarece de la un semestru la
altul apar variaii ale numarului de studeni bursieri.
Scoaterea unui element dintr-o astfel de list presupune
deplasarea cu o pozi!ie a tuturor elementelor din tablou aflate
dup elementul respectiv pentru ocuparea locului rmas gol.
Inserarea unui element n mijlocul unei liste implic o
deplasare n sens invers pentru crearea unui spaiu liber.

4.1. Liste simplu nlnuite
Eliminarea neajunsurilor prezentate mai sus se face prin
implementarea listelor cu ajutorul unor structuri de date
dinamice. Cnd apare necesitatea introducerii unui element n
list se va aloca dinamic spaiu pentru respectivul element, se
va crea elementul prin nscrierea informaiilor
corespunztoare *i se va lega n list. Cnd un element este
scos din list spaiul ocupat de acesta va fi eliberat. Fiecare
element al listei va trebui s con!in un cmp de legatur
reprezentat printr-un pointer care indic" spre urmtorul
element din list. n cazul listei de studenti un element va fi o
structur de forma:

struct student {
char nume[15];
char prenume[15];
float medie;
struct student *urm;
};
Pentru simplitate nu am mai introdus cmpurile de
adres, telefon *i data na*terii. Tipul de date de mai sus
declar" structuri recursive datorit cmpului urm care ne d
adresa urmtorului element din list. Acesta este un pointer la
o structur de date de tipul celei din care face parte nsu*i
cmpul urm. El va avea valoarea NULL pentru ultimul
element din list. O astfel de list poart numele de list
simplu nlanuit", deoarece, legtura ntre elemente este ntr-
un singur sens: de la primul ctre ultimul. Elementele unei
liste poart numele de noduri. Nodul este o structur
recursiv care con!ine un pointer ctre urmtorul nod al
listei.Exist un nod pentru care pointerul spre nodul urmtor
va avea valoarea NULL. Acesta este ulimul nod al listei
simplu nlnuite. De asemenea, exist" un nod spre care nu
pointeaz nici un alt nod. Acesta este primul nod al listei.
Principalele operaii care se pot efectua asupra unei liste
sunt: crearea listei, adugarea, *tergerea sau modificarea
unui element, accesul la un element *i *tergerea n totalitate a
listei. Adugarea se poate face la nceputul, la sfr*itul sau la
mijlocul listei. n acest ultim caz ea poart numele de
inserare. Inserarea este necesar" atunci cnd informaia din
list este ordonat dup o anumit cheie. De exemplu, n
cazul listei studenilor, ea poate fi ordonat dup media
general sau dup numele *i prenumele studenilor. Inserarea
presupune de obicei *i o parcurgere a listei pentru
deteminarea locului n care trebuie facut. Acela*i lucru este
valabil *i n cazul *tergerii sau modificarii unui element.
9
O list simplu nlnuit poate fi identificat n mod
unic prin primul element al ei. Determinarea ultimului
element al listei se poate face prin parcurgerea listei pn la
ntlnirea nodului al crui pointer spre nodul urmtor are
valoarea NULL. Totu$i este util" $i memorarea adresei
ultimului nod al listei, deoarece adugarea de elemente noi n
list se face de cele mai multe ori pe la sfr*iul acesteia.

Exemplu
S se creeze o list a studentilor dintr-un an n care
s se memoreze numele, prenumele i media generala a
fiecruia. S se afieze studenii care primesc burs,
considernd c bursa se acord celor cu media general
peste 9.00. Studenii cu media general sub 5.00 sunt
considerai repeteni si vor fi eliminai din list. Se va afia
apoi lista studenilor care au promovat.

#include <stdio.h>
#include <string.h>
#include <alloc.h>
#include <conio.h>
struct nod {
char nume[15];
char prenume[15];
float medie;
struct nod *urm;
};
struct nod *prim,*ultim;

void adauga(char *Nume,char *Prenume,float Medie){
struct nod *p;
p=(struct nod *)malloc(sizeof(struct nod));
if(p==NULL) {
printf("Memorie insuficient.\n");
return;
}
strcpy(p->nume,Nume); strcpy(p->prenume,Prenume);
p->medie=Medie;
p->urm=NULL;
if(prim==NULL) prim=ultim=p;
else {
ultim->urm=p;
ultim=p;
}
}
void sterge(struct nod *p) {
struct nod *q;

if(!p) return;
if(prim==p) {
prim=p->urm;
if(prim==NULL) ultim=NULL;
}
else {
for(q=prim;q->urm!=p&&q->urm!=NULL;q=q->urm)
if(q->urm==NULL) {
printf("Elementul nu aparine listei.\n");
return;
}
q->urm=p->urm;
if(p==ultim) ultim=q;
}
free(p);
}
void main(void) {
char Nume[15],Prenume[15];
float Medie;
int i,n;
struct nod *p,*q;

printf("Numrul de studenti:");scanf("%d",&n);
prim=ultim=NULL;
for(i=0;i<n;i++) {
printf("Nume:");gets(Nume);
printf("Prenume:");gets(Prenume);
printf("Media general:");scanf("%f",&Medie);
adauga(Nume,Prenume,Medie);
}
printf("Lista studenilor care primesc burs:\n");
for(p=prim;p!=NULL;p=p->urm)
if(p->medie >= 9) printf("%15s%15s - %5.2f\n",
p->nume,p->prenume,p->medie);
p=prim;
while(p!=NULL) {
if(p->medie < 5) {
q=p->urm;
sterge(p);
p=q;
}
else p=p->urm;
}
printf("Lista studentilor promovati:\n");
for(p=prim;p!=NULL;p=p->urm)
printf("%15s%15s - %5.2f\n",p->nume,p->prenume,p-
>medie);
}
n procedura de adugare a fost nevoie s tratm
separat cazul n care lista era vid (prim==NULL). n cazul
procedurii de *tergere am tratat separat cazul n care
elementul *ters era primul element al listei. Pentru c
operaiile de adugare *i *tergere s se fac la fel n toate
situaiile se poate plasa ca prim element al listei un element
fals, numit santinel. El nu va conine informaie util, de*i
are aceea$i structur ca *i celelalte elemente ale listei.
Santinela exist nainte de adugarea oricrui element n list.
Ea nu poate fi *tears *i ne asigur c lista are cel puin un
element (prim!=NULL) *i c indiferent ce element se *terge
din list, acesta nu este primul. La parcurgerea listei va trebui
s avem grij s srim peste santinel, deoarece ea nu conine
informaie util. Programul de mai sus poate fi rescris astfel,
dac se folose*te o santinel pentru primul element al listei:

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

struct nod {
char nume[15];
char prenume[15];
float medie;
struct nod *urm;
};

10
struct nod santinela,*prim,*ultim;

void adauga(char *Nume,char *Prenume,float Medie){
struct nod *p;

p=(struct nod *)malloc(sizeof(struct nod));
if(p==NULL) {
printf("Memorie insuficient.\n");
return;
}
strcpy(p->nume,Nume); strcpy(p->prenume,Prenume);
p->medie=Medie;
p->urm=NULL;
ultim->urm=p;
ultim=p;
}
void sterge(struct nod *p) {
struct nod *q;

if(!p) return;
for(q=prim;q->urm!=p && q->urm!=NULL;q=q->urm);
if(q->urm==NULL) {
printf("Elementul nu aparine listei.\n");
return;
}
q->urm=p->urm;
if(p==ultim) ultim=q;
free(p);
}
void main(void) {
char Nume[15],Prenume[15];
float Medie;
int i,n;
struct nod *p, *q;

printf("Numarul de studenti:");scanf("%d",&n);
santinela.urm=NULL;
prim=ultim=&santinela;
for(i=0;i<n;i++) {
printf("Nume:");gets(Nume);
printf("Prenume:");gets(Prenume);
printf("Media general:");scanf("%f",&Medie);
adauga(Nume,Prenume,Medie);
}
printf("Lista studenilor care primesc burs:\n");
for(p=prim->urm;p!=NULL;p=p->urm)
if(p->medie >= 9) printf("%15s%15s - %5.2f\n",
p->nume,p->prenume,p->medie);
p=prim->urm;
while(p!=NULL) {
if(p->medie < 5) {
q=p->urm;
sterge(p);
p=q;
}
else p=p->urm;
}
printf("Lista studenilor promovai:\n");
for(p=prim->urm;p!=NULL;p=p->urm)
printf("%15s%15s - %5.2f\n",p->nume,p->prenume,p-
>medie);
}
Utilizarea santinelei duce la simplificarea rutinelor de
adugare *i *tergere *i la scurtarea timpului de execuie al
acestora. Dezavantajul ar fi necesitatea alocrii spaiului
pentru acest element suplimentar care nu conine informaie
util, dar n majoritatea cazurilor acest lucru nu este
deranjant. n procedura de *tergere trebuie actualizat adresa
ultimului element al listei n cazul n care chiar acesta a fost
*ters. Acest lucru s-ar putea evita dac s-ar folosi *i o
santinel care s marcheze sfr*itul listei. n acest caz
operaia de adugare a unui element n list s-ar transforma
ntr-o operaie de inserare naintea santinelei de sfr*it de
list. Lsm ca tem rescrierea programului folosind o
santinel de sfr*it de list.
4.2.Liste dublu nl3n#uite
n procedura de *tergere este necesar" grsirea
elementului anterior celui care trebuie *ters. Acest lucru
impune parcurgerea de fiecare dat a listei pn la ntlnirea
elementului anterior. n cazul particular al programului nostru
s-ar putea evita operaia de cutare a elementului anterior prin
transmiterea lui ca parametru procedurii de *tergere. n
programul principal, n bucla de cutare a studenilor cu
media sub 5.00 va trebui s memorm pe lng adresa
elementului curent *i adresa elementului anterior (santinela
ne asigur existena acestui element anterior).
Cunoa*terea elementului anterior nu este posibil ns n
cazul tuturor problemelor, de aceea ar fi util s putem
determina rapid acest element. Acest lucru se poate realiza
prin folosirea listelor dublu nl"n!uite. Un element al unei
liste dublu nlnuite are 2 pointeri de legatur: unul ctre
elementul urmtor *i unul ctre elementul anterior din list.
Folosind o list dublu nlnuit cu santinel pentru marcarea
nceputului listei, programul nostru va arta astfel:

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

struct nod {
char nume[15];
char prenume[15];
float medie;
struct nod *urm;
struct nod *ant;
};
struct nod santinela, *prim, *ultim;

void adauga(char *Nume,char *Prenume,float Medie){
struct nod *p;
p=(struct nod *)malloc(sizeof(struct nod));
if(p==NULL) {
printf("Memorie insuficient.\n");
return;
}
strcpy(p->nume,Nume); strcpy(p->prenume,Prenume);
p->medie=Medie;
p->urm=NULL;
ultim->urm=p;
p->ant=ultim;
ultim=p;
}

11
void sterge(struct nod *p) {
if(!p) return;
p->ant->urm=p->urm;
if(p==ultim) ultim=p->ant;
else p->urm->ant=p->ant;
free(p);
}
void main(void) {
char Nume[15],Prenume[15];
float Medie;
int i,n;
struct nod *p,*q;

printf("Numarul de studenti:");scanf("%d",&n);
santinela.urm=NULL;
santinela.ant=NULL;
prim=ultim=&santinela;
for(i=0;i<n;i++) {
printf("Nume:");gets(Nume);
printf("Prenume:");gets(Prenume);
printf("Media general:");scanf("%f",&Medie);
adauga(Nume,Prenume,Medie);
}
printf("Lista studenilor care primesc burs:\n");
for(p=prim->urm;p!=NULL;p=p->urm)
if(p->medie >= 9) printf("%15s%15s - %5.2f\n",
p->nume,p->prenume,p->medie);
p=prim->urm;
while(p!=NULL) {
if(p->medie < 5) {
q=p->urm;
sterge(p);
p=q;
}
else p=p->urm;
}
printf("Lista studenilor promovai:\n");
for(p=prim->urm;p!=NULL;p=p->urm)
printf("%15s%15s - %5.2f\n",
p->nume,p->prenume,p->medie);
}
5. UTILIZAREA STIVELOR 6I A COZILOR

n practic ntlnim situaii n care informaia poate fi
reprezentat sub forma unei liste asupra creia se impun
anumite restricii referitoare la operaiile ce se pot executa
asupra ei.S considerm o cale ferat care trece printr-o staie
de ncrcare a vagoanelor. Vagoanele care urmeaz a fi
ncrcate vor fi a*ezate unul n urma celuilalt, n ordinea
sosirii. Dup ncrcare un vagon *i continu drumul,
prsind staia de ncrcare. Se observ c un vagon care vine
la ncrcat va trebui s treac la coad, neavnd posibilitatea
s intre n faa celorlalte. De asemenea, un vagon nu poate
prsi coada dect dup ce a fost ncrcat, deci numai dup ce
a ajuns n capul cozii. Considernd *irul de vagoane drept o
list liniar, se observ c operaiile de inserare se pot face
numai pe la coada listei, iar operaiile de extragere (*tergere)
a unui element numai pe la captul listei.
S considerm acum c" vagoanele pleac spre triaj
unde sunt trimise pe o linie moart (blocat la unul din
capete) de unde vor fi luate atunci cnd este nevoie de ele. n
acest caz, att sosirea ct *i plecarea vagoanelor se fac pe la
aceela*i capt al liniei. Avem deci de-a face cu o list n care
operaiile de inserare *i *tergere se efectueaz numai pe la
unul din capetele listei. O astfel de structur de date poart
numele de stiv.
Stivele *i cozile sunt colecii de elemente pentru care
la un moment dat este vizibil un singur element: elementul
din vrful stivei, respectiv elementul din capul cozii. n cazul
stivelor aceesul este de tipul LIFO ( Last In First Out), iar n
cazul cozilor accesul este de tip FIFO (First In First Out).
Principalele operaii asociate stivelor *i cozilor sunt
introducerea *i extragerea unui element. Extragerea elimin
din structura respectiv elementul vizibil *i permite obinerea
valorii acestuia. Poate fi necesar *i o operaie prin care s se
consulte elementul vizibil fr a-l elimina. Pentru stive
operaiile de introducere *i extragere a unui element au nume
consacrate: Push *i respectiv Pop.

Exemplu
S se scrie un program care s simuleze activitile
dintr-o staie de triaj pentru vagoane.
Vom considera c fiecare vagon este identificat printr-
un cod alfa numeric *i c" prezint interes cunoa*terea
greutii fiecrui vagon. Evenimentele care pot avea loc sunt
sosirea unui vagon, semnalat prin apsarea tastei S *i
plecarea unui vagon, semnalat prin apsarea tastei P. Pentru
un vagon care a sosit se vor solicita codul *i greutatea
acestuia, iar la plecarea unui vagon se vor afi*a aceste
informaii.
Stiva o vom implementa sub forma unei liste simplu
nlnuite, identificate prin variabila vrf care indic
elementul vizibil al listei, adic primul element. Deoarece
toate operaiile se fac pe la acest capat, nu este util
memorarea adresei ultimului element.
Procedura pop va oferi prin intermediul parametrilor
si informaiile referitoare la vagonul care tocmai a prsit
triajul. Procedura returneaz o valoare ntreag care poate fi 1
dac n triaj mai exist cel puin un vagon sau 0 n caz
contrar. Procedura push va returna 0 n cazul n care nu s-a
reu*it alocarea spaiului necesar crerii noului element sau 1
n caz contrar.

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

struct stiva {
int cod;
int greutate;
struct stiva * urm;
};
struct stiva *varf;

int push(int Cod, int Greutate){
struct stiva *p;
p=(struct stiva *)malloc(sizeof(struct stiva));
if(p==NULL) return 0;
p->urm=varf;
p->cod=Cod;
p->greutate=Greutate;
varf=p;
return 1;
}
12
int pop(int *pCod,int *pGreutate) {
struct stiva *p;

if(!varf) return 0;
p=varf;
varf=p->urm;
*pCod=p->cod;
*pGreutate=p->greutate;
free(p);
return 1;
}
void main (void) {
int Cod,Greutate;
int gata;
char c;

varf=NULL;
gata=0;
while(!gata) {
clrscr();
printf("Selectionati operatia dorita:\n");
printf("S- sosirea vagon\n");
printf("P- plecare vagon\n");
printf("T- terminare program\n\n");
c=getch();
switch(c) {
case 'S':printf("Codul vagonului:");scanf("%d",&Cod);
printf("Greutatea vagonului:");scanf("%d",&Greutate);
if(push(Cod,Greutate))
printf("Vagonul a fost introdus pe linia moart ");
else printf("Memorie insuficient");
break;
case 'P':if(pop(&Cod,&Greutate))
printf("A plecat vagonul cu codul %d *i greutatea de
%d tone",Cod,Greutate);
else printf("Nu mai exist nici un vagon n triaj:");
break;
case 'T':gata=1;break;
default:printf("Operatie ilegala");break;
}
printf("\n\nApasati o tasta pentru a continua.\n");
getch();
}
}
6. UTILIZAREA FI6IERELOR

Limbajul C nu posed instructiuni care opereaz asupra
fi*ierelor. Aceasta pare surprinztor, ns pstrarea detaliilor
de intrare /ie*ire(I/O) n afara limbajului prezint un real
avantaj. Deoarece diferitele sisteme folosesc metode diferite
pentru accesul fi*ierelor pe disc *i deoarece limbaju C a fost
proiectat ca un limbaj portabil, toate operaiile de I/O sunt
sintetizate n biblioteca standard. Aceasta este o colecie de
rutine (funcii *i macrouri) care realizeaz majoritatea
operaiilor asupra fi*ierelor.
Pentru a avea acces la funciile de manipulare a
fi*ierelor trebuie folosit directiva include pentru a ncorpora
coninutul headerului stdio.h n programul surs. Acest
header conine definii de date necesare, definiii de macrouri
*i prototipuri, funciile standard de I/O.

6.1 Tipuri de fi+iere

Se disting dou tipuri de fi*iere: fi*iere text *i fi*iere
binare.
Fi*ierele text conin caractere ASCII n gama 0-127.
Fi*ierele text (se mai numesc *i fi*iere ASCII), conin
informaie citibil: de exemplu toate fi*ierele surs sunt
fi*iere text. Fiecare caracter este reprezentat prin cei mai
puin semnificativi 7 bii ai unui octet. ntr-un fisier text,
seriile de bytes sunt organizate pe linii, fiecare linie avnd
zero sau mai multe caractere terminate cu \n. Exist situaii
n care s-ar putea s fie necesar o conversie la alte forme de
reprezentare (de exemplu `\n` corespunde secvenei CR LF).
Fi*ierele binare conin n*iruiri de bytes fr o
structur impus. Astfel de fi*iere sunt neinteligibile pentru
om ns au semnificaie pentru calculator; fi*ierele
executabile constituie un exemplu de fi*iere binare. Fi*ierele
binare au proprietatea c dac sunt scrise *i apoi citite pe
acela*i sistem vor fi egale.

6.2 Declararea unui pointer la fi+ier
Deschiderea unui fi*ier ntoarce un pointer de la un
obiect de tip FILE.FILE este o structur predeclarat n
stdio.h. Formatul de declarare al unui pointer la fi*ier este:
FILE*fpoint;
unde fpoint este numele variabilei pointer cu care se
va lucra n continuare.

6.3 Opera#ii cu fi+iere

Deschiderea unui fisier
FILE * fopen(const char*nume_fisier , const char *mod);

unde:
nume_fi*ier numele fi*ierului ce trebuie deschis sau
creat;
mod modul de deschidere
fopen deschide fi*ierul al crui nume este specificat prin
nume_fi*ier pentru scriere, citire, adugare sau citire_scriere,
dup cum este specificat atributul mod. n caz de succes,
returnez un pointer la FILE, pointer cu care se lucreaz n
continuare. Dac operaia de deschidere e*ueaz, fopen
ntoarce NULL.
Variabile posibile pentru atributul mod sunt :
r- deschide fi*ierul existent pentru citire;
w-creaz un fi*ier pentru scriere, eliminndu-se
eventual coninutul anterior (suprascriere);
a- adugare; deschide sau creaz un fi*ier pentru
scrierea la sfr*itul fi*ierului;
r+- deschide un fi*ier pentru actualizare (citire +
scriere);
w+- creaz un fi*ier pentru actualizare. Coninutul
anterior se elimin;
a+- actualizare; scrierea se face la sfr*it.
Simbolul + n atributul mod permite actualizarea, adic
scrierea *i citirea n/din acela*i fi*ier.
Fi*ierele sunt deschise fie n mod binar, fie text. Modul de
deschidere este specificat tot de argumentul mod al funciei
fopen astfel: t pentru text, b pentru binar. Litera se adaug la
*irul de caractere ce specific modul de acces.
Exemplu:
FILE *fp1, *fp2;
fp1=fopen(mm1.txt,r+t);
fp2=fopen(pp1.bin,wb);
Valoarea implicit pentru tipul fi*ierul este text.
13

b) FILE *freopen(const char *nume, const char
*mod, FILE *stream) asociaz un fi*ier nou cu un stream
deja deschis. Este folositor pentru a schimba fi*ierul ata*at lui
stdin, stdout sau stderr.
Exemplu: redirectarea ie*irii standart la un fi*ier
.
if(freopen(fis1.dat,w,stdout)==NULL)
{printf (Eroare de deschidere);exit (1);}
printf(Acest sir se va scrie n fi*ier);
nchiderea unui fiier
a) int fclose(FILE* fpoint)
nchide fi*ierul specificat de fpoint.
nainte de nchidere scrie datele din buffer n fi*ier.
n caz de succes returneaz zero. Dac nchiderea nu a reu*it
returneaz EOF.

Exemplu:
FILE *fp;
fp=fopen (fis.txt,wt);

fclose(fp);

b) int fcloseall(void) nchide toate fi*ierele cu excepia
stdin, stdout, stderr, stdprn, stdaux.
n caz de succes returneaz numrul total de fi*iere nchise,
altfel returneaz NULL.
c) int fflush(file *fpoint) determin scrierea datelor
nc nescrise din tampon n fi*ierul de ie*ire specificat prin
fpoint.
n caz de succes returneaz zero astfel EOF

6.4 Scrierea +i citirea n/din fi+ier

Scrierea cu format
a) int fprintf(FILE *fpoint, const char *format
[argument, . ]) funcia scrie n fi*ierul pointat de
fpoint datele specificate de parametrii argument n formatul
specificat prin parametrul format.
n caz de succes, funcia returneaz numrul de bytes scri*i,
astfel returneaz EOF.
Exemplu:
FILE *fp;
int i=10;
char c=A;
float f=1.6543;
fp=fopen(test.dat,w);
fprintf(fp,%d,%c,%f,i,c,f); // scrie un ntreg, un
caracter *i un float n fi*ierul descris de // fp

b) int printf(const char *format [, argument])-
este echivalent cu fprintf(stdout..);
c) int sprintf(char *s, const char *format)- este identic
cu printf cu deosebirea c ie*irea este scris n *irul s.

Citirea cu format
a) int fscanf(FILE *fpoint, const char *format [,
adresa]) cite*te din fi*ierul specificat de fpoint date
sub controlul formatului specificat n format date *i le
atribuie variabilelor prin adresele adresa.
n caz de succes returneaz numrul de cmpuri citite, astfel
returneaz EOF.

Exemplu:
int i;
fscanf(stdin, %d,&i); // cite*te un ntreg din fi*ierul
standard de intrare
printf(%d,i)
b) int scanf(const char *format[,adresa]) funcia
este identic cu fscanf(stdin, ....)

Funcii de citire i scriere caracter
a) int fgetc(FILE *fpoint) extrage un caracter din fi*ierul
descris de fpoint.
n caz de succes returneaz caracterul citit. Dac se ncearc
citirea peste sfr*itul de fi*ier sau s-a semnalat o eroare,
funcie returneaz EOF.

Exemplu:
FILE *fp;
char ch;
fp=fopen(test,r);
do
{
ch=fgtc(fp); // extrage un caracter din fi*ier
putch (ch);
}
while (ch!=EOF);
b) int fputc(int c, FILE *fpoint ) scrie caracterul c n
fi*ierul specificat de fpoint.
n caz de succes returneaz caracterul citit, astfel EOF.
Exemplu:
char mesaj[]=Hello!;
int i=0;
while (mesaj [i])
{ fputc(msg[i], stdout); //scrie caracterul msg[i] la
ie*irea standard
i++;
}
c) int getc(FILE *fpoint) macrou care extrage caracterul
curent din fi*ier *i incrementeaz pointerul de fi*ier la
urmtorul caracter.
n caz de succes returneaz caracterul citit, astfel EO.
d) int putc (int c, FILE *fpoint ) macrou care scrie
caracterul dat de c n fi*ierul fpoint.
Dac scrierea a reu*it, returneaz caracterul c, astfel EOF.
e)int getchar(void) este echivalent cu getc (stdin );
f)int putchar(int c) este echivalent cu putc(c, stdout);
g) char *fgets(char *s, int n, FILE *fpoint ) cite*te cel
mult urmtoarele n 1 caractere din fi*ier *i le scrie n s.
Funcia se opre*te dac a detectat NL. Acesta este *i el inclus
n *irul s . birul se termin cu \0.
h) int fputs(const char *s, FILE *fpoint) scrie *irul s
n fi*ierul fpoint. n caz de succes ntoarce o valoare pozitiv,
astfel EOF.
i) int ungetc(int c, FILE * fpoint)- pune caracterul c
napoi n fi*ierul dat de fpoint, de unde va fi preluat la
urmtoarea citire. Un singur caracter se poate pune napoi n
fi*ier la un anumit moment.
n caz de succes, funcia returneaz caracterul depus, altfel
EOF.

Funcii de citire i scriere la nivel de bloc
a) size_t fread(void *tab, size_t size, size_t nr_obj, FILE
*fpoint) cite*te din fi*ierul specificat de fpoint cel mult
nr_obj obiecte de mrimea size *i le introduce n tabloul tab.
Funcia ntoarce numrul de obiecte citite, acesta putnd s
fie mai mic dect nr_obj.
14
b) size_t fwrite(const void *tab, size_t size, size_t nr_obj,
FILE *fpoint)- scrie nr_obj obiecte de dimensiune size, din
tabloul tab n fi*ierul dat de fpoint. ntoarce numrul de
obiecte scrise. n caz de eroare acest numr este mai mic
dect nr_obj.

Funcii de poziionare n fiier
a) long ftell(FILE *fpoint) - returneaz poziia curent a
indicatorului de fi*ier. Dac fi*ierul este binar, offsetul este
msurat n bytes de la nceputul fi*ierului.
b)int fseek(FILE *fpoint, long offset, int reper)
determin poziionarea indicatorului de fi*ier. Pentru un fi*ier
binar, poziia este stabilit la deplasamentul offset fa de
reper, care poate fi SEEK_SET pentru nceput, SEEC_CUR
pentru poziia curent sau SEEK_END pentru sfr*it. n caz
de succes, funcia ntoarce zero, altfel o valoare diferit de
zero.
c)void rewind(FILE *fpoint ) poziioneaz indicatorul
de fi*ier la nceputul acestuia.
d) int fgetpos(FILE *fpoint, fops_t *ptr) - seteaz n ptr
poziia curent din fi*ier. ntoarce zero n caz de succes.

Pentru testarea sfritului de fiier exist funcia :
int feof(FILE *fpoint )- ntoarce o valoare diferit de
zero dac indicatorul de fi*ier este valid.

Exemple
1. S se scrie o procedur de creare a unui fiier text ce
conine nume de persoane i o alta de actualizare
prin adugare a acestui fiier. n final se va scrie o
procedur de listare a coninutului fiierului.
#include<stdio.h>
#include<process.h>
#include<conio.h>
#define nf "mm1.txt"
FILE *fp;
void creare(char* nume_fis) //creaz fi*ierul text mm1.txt
{
if((fp=fopen(nume_fis,"wt"))==NULL)
{
printf ("Eroare de creare"); //creare nereu*it
exit(1);
}
fclose(fp);
}
void adaug(char *nume_fis) //adaug nume n fi*ierul text
{
char nume[20],c;
clrscr();
if((fp=fopen(nume_fis,"a"))==NULL)
{
printf("Eroare de deschidere");
exit(1);
}c='d';
do
{
printf("\n DAdI NUMELE: ");
scanf ("%s",nume);
fprintf(fp,"%s\n",nume); // scrie n fisier
printf("\n MAI INTRODUCEdI NUME? d/n ");
c=getch();
} while(c=='d');
fclose(fp);
}
void listare (char* nume_fis) //listeaz coninutul fi*ierului
{
char nume[20];
if((fp=fopen(nume_fis,"rt"))==NULL)
{
printf("Eroare de deschidere");
exit(1);
}
while(!feof(fp))
{
if(fscanf(fp,"%s",nume)==EOF) break;
printf("\n%s",nume);
}
}
void main()
{
creare(nf);
adaug(nf);
listare(nf);
}
2. S se creeze un fiier binar ce conine informaii
despre o grup de studeni. S se scrie apoi o procedur de
adugare, apoi una de cutare n fiier dup nume i
modificarea notei studentului. n final s se listeze coninutul
fiierului modificat.
#include<stdio.h>
#include<string.h>
#include<conio.h>
#include<process.h>
#define nf "m1.txt"
typedef struct {
char nume[10];
int an,nota;
}stud;
FILE *fp;
void creare () // creaz fi*ierul m1.txt
{
if((fp=fopen(nf,"wb"))==NULL)
{
printf("Eroare de creare\n"); //creare nereu*it
exit(1);
}
fclose(fp);
}
void listare () // listeaz coninutul fi*ierului
{
stud s;
clrscr();
if((fp=fopen(nf,"rb"))==NULL) // deschide fi*ierul
//pentru citire n mod binar
{
printf("Eroare de deschidere \n");
exit(1);
}
do
{
fread(&s,sizeof(stud),1,fp); // cite*te un bloc
//de dimensiune sizeof(stud) din fi*ier
if(feof(fp)) break;
printf("\n%s",s.nume);
printf("\n%d",s.an);
printf("\n%d",s.nota);
}
while (!feof(fp));
fclose(fp);}
15
void adaugare () // adaug o nregistrare la sfr*itul fi*ierului
{
char c;
stud s;
clrscr();
if((fp=fopen(nf,"ab"))==NULL)
// deschide fi*ierul pentru adugare n mod binar
{
printf("Eroare de deschidere\n");
exit(1);
}
c='d';
while(c=='d')
{
printf("\n NUME :");
scanf("%s",s.nume);
printf("\nAN: ");
scanf("%d",&(s.an));
printf("\nNOTA : ");
scanf("%d",&(s.nota));
fwrite(&s,sizeof(stud),1,fp);
// scrie n fi*ier un bloc de
// dimensiune sizeof(stud)
printf("\n\n MAI DORIdI ADfUGARE? (d/n): ");
c=getch();
}
fclose(fp);
}
void caut_modif()
{ stud s;
long int poz;
int gasit=0;
char n[10];
int nnot;
printf("\n Dati NUMELE dupa care se cauta : ");
scanf("%s",n); printf("\n DATI NOUA NOTA : ");
scanf("%d",&nnot);
if((fp=fopen(nf,"r+b"))==NULL) //deschide fi*ierul
//pentru citire *i scriere n mod binar
{
printf("Eroare de deschidere\n");
exit(1);
}
while((!gasit)&&(!feof(fp)))
{
poz=ftell(fp); // memoreaz poziia testat deoarece
//dup fread indicatorul de fi*ier *i modific valoarea
fread(&s,sizeof(stud),1,fp);
if(!strcmp(n,s.nume))
gasit++;
}
if(!gasit)
{printf("\nNU s-a gasit inregistrarea ");
getch();}
else
{fseek(fp,poz,SEEK_SET); //se mut indicatorul de
//fi*ier pe poziia poz
fread(&s,sizeof(stud),1,fp);
s.nota=nnot; // se memoreaz noua not in
//cmpul citit din fisier
fseek(fp,poz,SEEK_SET);
fwrite(&s,sizeof(stud),1,fp); //se rescrie
//nregistrarea modificat n fi*ier
}
fclose(fp);}
void main()
{
clrscr();
creare();
adaugare();
listare();
caut_modif();
listare();
}

7. COMPLETARI ADUSE DE C++

7.1. Opera#ii de intrare/ie+ire cu consola
C++ permite utilizarea funciilor de intrare/ie*ire C,
ns dispune de un sistem de intrare/ie*ire conceput n
spiritul POO, mai flexibil *i mai comod. In cele ce
urmeaz se realizeaz o introducere sumar a operaiilor
cu consola.
n C++ snt predefinite dispozitive logice de intrare-
ie*ire standard similare celor din C:
cin = console input = dispozitiv de intrare consol,
tastatura (echivalent cu stdin din C);
cout = console output = dispozitiv de ie*ire consol,
monitorul (echivalent cu stdout din C).
Transferul informaiei cu formatare este efectuat de
operatorul >> pentru intrare (de la cin) *i de << pentru
ie*ire (ctre cout), deci:

cout < < var; /* scrie var la cout */
cin > > var; /* cite*te var de la cin */ .

Ace*ti doi operatori au urmtoarele proprieti:
- Sunt posibile operaii multiple, de tipul:

cout < < varl < < var2... < < varN;
cin > > varl > > var2... > > varN;

n acest caz, se efectueaz succesiv, de la stnga la
dreapta, scrierea la cout, respectiv citirea de la cin a
valorilor varl ... varN.
- Tipurile datelor transferate ctre cout pot fi:
toate tipurile aritmetice;
*iruri de caractere;
pointeri de orice tip n afar de char.
- Tipurile datelor citite de la cin pot fi:
toate tipurile aritmetice;
*iruri de caractere.
- Controlul formatului pentru ambele operaii este posibil,
dar nu este obligatoriu, deoarece exist formate standard.
Acestea snt satisfctoare pentru dialogul cu consola efectuat
n exemplele in cadrul acestui curs.
Operaiile de citire de la tastatur efectuate cu operatorul
>> sunt similare cu cele efectuate cu scanf(). Delimitatorii
cmpurilor inroduse sunt spaiu, tab, linie nou, etc. n cazul
citirii unui caracter nevalid citirea este ntrerupt *i caracterul
rmne n tamponul de intrare genernd probleme similare cu
cele descrise la scanf().
Utilizarea dispozitivelor *i operatorilor de intrare/ie*ire
C++ impune includerea fi*ierului antet iostream. h. Exemplul
urmtor este elocvent pentru elegana *i simplitatea
dialogului cu consola nC++:

16
ex.l:
#include <iostream.h>
void main()
{
int i;
char nume[21];
float r;
cout < < "Introducei un numr intreg"
"si apoi un numr real:";
cin > > i > > r;
cout << "\nAti introdus: "<< i< < " *i" < < r < < '\n';
cout < < "Introducei numele dvs:";
cin >> nume;
cout << "Salut," << nume << "!\n"; }

Programul afi*eaz:
Introducei un numr intreg si apoi un numr real: 15
3.1416
Ati introdus: 15 si 3.1416
Introducei numele dvs: Mihai
Salut, Mihai!
Trebuie reinut c simbolurile >> *i << *i pstreaz *i
semnificaia din C - operatori de deplasare bit cu bit la
dreapta, respectiv la stnga.

7.2 Comentariile de sfr+it de linie
C++ admite delimitatorii C /* */ pentru comentarii
care se pot ntinde pe mai multe linii *i introduce
delimitatorul // pentru adugarea mai comod de
comentarii de sfr*it de linie. Tot textul care urmeaz
dup // pn la sfr*itul liniei este considerat comentariu:

ex:l:
if (c= ='X') break; // ie*ire forat din ciclu

n Turbo C++ (ca *i n Turbo C) se admit comentarii
imbricate dac se solicit explicit acest lucru prin meniul
de opiuni. ntotdeauna ns, ntr-o zon ncadrat de /* */
pot apare *i comentarii de sfr*it de linie.

7.3 Plasarea declara#iilor
Spre deosebire de C, care impune gruparea
declaraiilor locale la nceputul unui bloc, C+ + permite *i
declaraii n interiorul blocului, de exemplu imediat
nainte de utilizare. Domeniul unei astfel de declaraii este
cuprins ntre poziia declaraiei *i sfr*itul blocului:

ex.l:
void main()
{
int i;
cin >> i;
int j=5*i-l;
for(int k=2*j; k; k--)
{...}
// k a fost declarat anterior
for(k=0; k<i;k++);
}
Declaraiile tardive pentru j *i k snt utile pentru c
permit *i iniializarea adecvat cu valori care nu erau
cunoscute la lansarea n execuie a funciei.

7.4 Variabile referin#3. Transferul prin referin#3 al
parametrilor +i al rezultatului unei func#ii

C++ permite declararea unor identificatori ca referine
de obiecte (fizice) de un anumit tip. n exemplul urmtor
se declar *i se iniializeaz ir ca referin de obiecte int:

ex.l:
int n=5;
int& ir=n;
/* sau: int &ir=n; sau int & ir=n; */
ir=100; /* echivalent cu n=100 */

Identificatorul ir este asociat obiectului alocat pentru n
*i reprezint deci un alt nume cu care poate fi referit acel
obiect, ir are o valoare stnga *i poate substitui
identificatorul n n orice operaie. Nu snt permise
referine de cmp de bii, referina unei variabile referin,
tablouri *i pointeri de referine.
Utilitatea declarrii unui alt identificator pentru un
obiect din memorie nu pare deloc evident, dar lucrurile
se schimb atunci cnd declaraia apare n lista de
parametri formali ai unei funcii. De fapt, variabilele
referin de sine stttoare snt rar folosite. La declarare
este obligatorie iniializarea lor cu adresa unei variabile
deja definite (sau a unei constante) cu sintaxa din
exemplul 1.
Prin folosirea parametrilor formali referin, C++
permite realizarea transferului prin referin de o manier
similar celei din Pascal. Se elimin astfel necesitatea
recurgerii la artificiul din C, adic utilizarea parametrilor
formali pointer. Exemplele care urmeaz conin o funcie
care schimb valorile a dou variabile. Este necesar ca
funcia s poat modifica valorile parametrilor efectivi,
astfel nct transferul prin valoare nu este aplicabil. Se
poate compara soluia cu parametri pointer cu soluia C++
cu parametri referin:
Ex.2

/* varianta C */
void schimba(int* , int* );
main()
{
int i,j;
scanf("%d%d", &i, &j);
schimba(&i, &j);
printf("%d%d",I,j);
}
void schimba(int* a, int* b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
Ex.2: //varianta C+ +
void schimba(int&, int&);
void main()
{
int i,j;
cin < < i < < j;
schimba(i, j);
cout>>i>>j;
17
void schimba(int& a, int& b)
{
int temp;
temp=a;
a=b;
b=temp;
}
Declaraiile int& a *i int& b din antetul funciei schimba()
precizeaz c parametrii formali a *i b snt referine de
obiecte int. La apelare, lista de argumente efective specific
obiectele care se asociaz referinelor a *i b. Operaiile
efectuate asupra parametrilor formali a *i b vor modifica
valorile parametrilor efectivi.
Avantajul metodei const n faptul c ntregul proces de
transfer prin referin este efectuat de compilator n mod
transparent, ceea ce simplific scrierea funciei *i apelul ei.
Metoda C este desigur valabil *i n C+ + , dar n multe
situaii ea devine o complicaie inutil.
7.5. Parametri cu valori implicite
C++ ofer posibilitatea declarrii funciilor cu valori
implicite ale parametrilor. La apelarea unei astfel de funcii,
se poate omite specificarea parametrilor efectivi pentru acei
parametri formali care au declarate valori implicite *i se
transfer automat valorile respective:

ex.l:
#include <iostream.h>
void fct(int, int =10);
void main()
{ cout << "apel: fct(5,99),";
fct(5,99); // apel normal
cout << "apel: fct(5) ,";
fct(5); // apel cu un singur argument
}
void fct(int i, int j)
{ cout << "parametri: i= "<< i;
cout << "j= " << j << "\n";
}
Programul afi*eaz:
apel: fct(5,99), parametri: i=5 j=99
apel: fct(5), parametri: i=5 j=10

Un apel fr parametri (fct();) este eronat deoarece
parametrul i nu are asociat o valoare implicit.
La declararea *i definirea funciilor cu parametri implicii
trebuie respectate urmtoarele reguli:
- Valorile implicite se specific o singur dat, n prototip
sau n definiie. De obicei valorile implicite se declar n
prototipul funciei, astfel nct decizia s aparin
utilizatorului, nu celui care a creat (definit) funcia. n
acest fel este posibil adaptarea la cerinele aplicaiei.
- n declaraie, argumentele cu valori implicite trebuie s
fie plasate la sfr*itul listei. La apelare, lista de parametri
efectivi va corespunde primilor parametri din lista de
parametri formali. Aceast regul permite identificarea
univoc a valorilor implicite.

ex.2:
#include <iostream.h>
int fct1(char='A, int, float=15); //eroare compilare
double fct2(int=5,double=3.5); // corect
void fct3(int, long=99, float=10.5);// corect
void main()
{
float vf=1.5;
fct3(0); // apel corect: i=0, j=99, r= 10.5
fct3(l,vf); //apel incorect: i=l,j=l, r=10.5
fct3(2,2.5);//apel incorect: i=2, j=2, r=10.5
}
double fct2(int i, double d=3.5)
{ // eroare compilare
cout << "i=" << i;
cout<< ",d="<<d <<"\n';
}
void fct3(int i, long j, float r)
{ cout<<"\n';
cout << "i=" << i;
cout << ", j="<< j <<", r=" < r;
}
Programul afi*eaz:
i=0, j=99, r=10.5
i=l j=1, r=10.5
i=2, j=2, r=10.5
Declaraia funciei fct() este sancionat cu eroare la
compilare cu mesajul "lipsa valorii implicite pentru
parametrul int". De asemenea, definiia funciei fct2() va
determina un mesaj de eroare datorit repetrii declaraiei
valorii implicite double. Ultimele 2 apeluri ale funciei fct3()
snt eronate n msura n care se mizeaz pe valoarea
implicit a parametrului long. Aceste apeluri nu snt
semnalate de compilator deoarece este legal conversia cu
trunchiere float --> long *i valoarea parametrului efectiv float
este transferat parametrului formal long.
Se pot specifica valori implicite *i n cazul parametrilor
transferai prin referin:
ex.3:
void main()
{
int i,j;
void fct(int, int&=i);
fct(l,j); // efect: j=l
fct(5); //efect: i=5
}
// b este implicit referina variabilei i
void fct(int a, int& b)
{
b=a;
}
Dac valoarea implicit a parametrului b trebuie s fie o
constant, se poate declara:

void fct(int, int&=5);

Trebuie remarcat c n acest caz parametrul b este asociat
implicit unei variabile temporare de tip int iniializat cu 5 *i
operaiile care afecteaz valoarea parametrului se efectueaz
asupra acestei variabile temporare.

7.6 Alocarea dinamic3 a memoriei folosind
operatorii new +i delete
C++ introduce o metod nou pentru gestiunea dinamic
a memoriei, similar celei utilizate n C (funciile din grupul
malloc() *i free()), dar superioar *i adaptat programrii
orientate ctre obiecte.
18
Alocarea memoriei se face cu ajutorul operatorului unar
new, cu sintaxa:
tipd_ptr=new tipd;
tipd_ptr=new tipd(val_init);
tipd_ptr=new tipd[n];

unde:
- tipd = tipul variabilei dinamice, care poate fi un tip de
date oarecare;
- tipd_ptr = o variabil pointer de tipul tipd;
- val_init = expresie cu a crei valoare se iniializeaz
variabila dinamic.
Varianta a treia se utilizeaz pentru alocarea memoriei
pentru n elemente de tipul tipd (un tablou cu n elemente) *i n
este o expresie ntreag. Se pot aloca *i tablouri
multidimensionale, specificnd toate dimensiunile.
Iniializarea tablourilor nu este posibil.
Operatorul new aloc spaiul necesar, corespunztor
tipului, *i ofer ca rezultat:
- dac alocarea a reu*it, un pointer de tipul (tipd *)
coninnd adresa zonei de memorie alocate;
- n caz contrar (memorie insuficient sau fragmentat),
un pointer cu valoarea NULL (=0).

Exemplul urmtor ilustreaz sintaxa pentru toate
variantele:

ex.1:

int n=15, *ip1, *ip2, *ipt1, *ipt2;
ip1=new int; //variabila intreaga neinitializata
ip2=new int(17) //variabila intreaga iniializat cu 17
iptl=newint[100]; // tablou unidimensional
int ipt2=new int[n][2*n]; // tablou bidimensional int

n general, este recomandabil ca rezultatul s fie testat
nainte de utilizarea variabilei dinamice. Programul din
exemplul 2 ilustreaz o secven de alocri care conduce
la epuizarea spaiului de memorie:
ex.2:
#include <iostream.h>
#include <stdlib.h>
void main()
{ int *ip;
long dim;
cout < < "Dimensiune bloc ?";
cin > > dim;
for(int i=l;;i++)
if((ip=new int[dim]))
cout << "Alocare bloc i=";
cout < < i < < "\n";
else
{ cout < < "Alocare imposibila\n";
exit(l);
}
}
Programul afi*eaz:
Dimensiune bloc ? 6000
Alocare bloc i=l
Alocare bloc i=2
Alocare.bloc i=3
Alocare bloc i=4
Alocare bloc i=5
Alocare imposibila
Eliminarea variabilei dinamice *i eliberarea zonei de
memorie se face cu operatorul delete, cu sintaxa:

delete tipd_ptr;

unde tipd_ptr este adresa obinut n urma unei alocri cu
Operatorul new (utilizarea altei valori este ilegal *i
comportarea programului ntr-o astfel de situaie este
nedefinit).

ex.3:
int *ip;
ip=new int;

delete ip;
Pentru tratarea mai elaborat a situaiilor n care
operatorul new nregistreaz un e*ec la alocare, se poate
utiliza funcia declarat n new.h cu prototipul:

void ( *set_new_handler( void(*)() ) ) ();

Funcia prime*te ca parametru adresa unei funcii definite
de utilizator pentru tratarea e*ecurilor de alocare *i ntoarce
un pointer ctre funcia de tratare care era utilizat anterior.
Programul din exemplul 4 ilustreaz modul de utilizare a
funciei set_new_handler() *i este echivalent cu cel din
exemplul 2 (afi*eaz exact acelea*i mesaje):

ex.4:
#include <iostream.h>
#include <new.h>
void no_mem();
void main()
{
int *ip;
long dim;
set_new_handler(&no_mem);
cout << "Dimensiune bloc?";
cin > > dim;
for(int i=l;;i++) {
ip=new int[dim];
cout < < "Alocare bloc i=";
cout < < i < < "\n";
}
}
void no_mem()
{
cout < < "Alocare imposibila\n";
exit(l);
}
7.7. Func#ii "inline"
Directiva preprocesor #define ofer posibilitatea
utilizrii macrodefiniiilor cu parametri. Pentru fiecare
apelare preprocesorul insereaz n textul programului, n
locul apelului, textul macrodefiniiei n care se substituie
numele parametrilor formali cu cele ale parametrilor
efectivi. Textul rezultat este preluat apoi de compilatorul
propriu-zis care ignor existena macrodefiniiilor.
Avantajul macrodefiniiei fa de funcie este
obinerea unui timp de execuie mai scurt, deoarece codul
obiect este inserat efectiv n program *i se elimin
operaiile asociate apelului unei funcii (salvri *i
19
restabiliri de registre ale microprocesorului, transfer de
parametri prin stiv, etc). Dezavantajele macrodefiniiilor
constau n:
- cre*terea dimensiunii codului obiect generat de
compilator, deoarce pentru fiecare apel se insereaz codul
corespunztor instruciunilor din macrodefiniie;
- imposibilitatea compilrii separate;
- lipsa unor verificri a apelurilor, relativ la numrul *i
tipurile parametrilor;
- necesitatea de a trata diferit fa de funcii problemele
legate de transferul parametrilor, domeniul variabilelor,
etc, cu posibile efecte mai greu decelabile n cazul unor
erori.

Un exemplu simplu l reprezint macrodefiniia:

ex.l:
#define fct(x) x*x

int i, j, rez;
rez=fct(i); //corect: rez=i*i;
rez=fct(i+l); //eroare: rez=i+l*i+l, deci rez=2*i+l

Eroarea din ultimul apel poate fi evitat redefinind fct(x)
astfel:

#define fct(x) (x)*(x)

rez=fct(i+l); //corect: rez=(i+l)*(i+l);



n orice caz, nici aceast ameliorare nu salveaz un apel
eronat de forma:

rez=fct(i++); //eroare:rez=(i++)*(i++),dubla incrementare

C++ ofer posibilitatea declarrii funciilor "inline" care
combin avantajele funciilor propriu-zise cu cele ale
macrodefiniiilor.
Diferena fa de funciile ordinare const n faptul c, la
fiecare apelare, codul obiect al funciei iniine este inserat n
codul programului de ctre compilator. n acest fel, ca *i n
cazul macrodefiniiilor se elimin operaiile aferente apelului.
Funciile inLine pstreaz ns toate proprietile funciilor n
privina verificrii validitii apelurilor, modului de transfer
al parametrilor, domeniului declaraiilor locale *i al
parametrilor.
Trebuie reinut c n cazul unei macrodefiniii are loc o
substituie de text ntr-o faz prealabil compilrii, iar pentru
funciile iniine compilatorul insereaz codul obiect al funciei
la fiecare apel.
Avantajul cre*terii vitezei se plte*te cu cre*terea
dimensiunii codului, deci funciile inline trebuie s fie foarte
scurte. n plus, este evident c nu mai este posibil
compilarea separat a unei funcii iniine sau utilizarea unui
pointer ctre o asemenea funcie.
Din punct de vedere sintactic, funciile inLine se definesc
*i se utilizeaz similar cu cele ordinare, cu excepia adugrii
specificatorului inline:

ex.2:

inline char comp(int a, int b)
{
if(a<b)return'<';
if(a>b)return'>';
return '=';
}
Ca *i n cazul specificatorului register, inline este o cerere
adresat compilatorului pe care acesta poate s nu o onoreze,
caz n care genereaz o funcie ordinar (de exemplu dac n
program se utilizeaz pointeri ctre funcia respectiv).

7.8 Operatorul de rezolu#ie
n C+ + este definit operatorul de rezoluie (::) care
permite accesul la un identificator cu domeniu fi*ier, dintr-un
bloc n care acesta nu este vizibil datorit unei alte declaraii.
Se mai nume*te operator de acces (de domeniu). De exemplu:

ex.l:

char str[20]="Sir global";
void fct()
{
char *str; //variabila locala
str="Sir local";
puts(::str); // afi*eaz *irul global
puts(str); // afi*eaz *irul local
}
20

UTILIZAREA LIMBAJULUI C N REZOLVAREA
PROBLEMELOR DE ANALIZW NUMERICW
8. CALCULUL RWDWCINILOR REALE
ALE ECUA8IEI ALGEBRICE

Pentru calculul rdcinilor reale ale unei ecuaii algebrice
se utilizeaz mai multe metode numerice dintre care amintim:
metoda biseciei (bipartiiei), metoda aproximaiilor
succesive , metoda Newton-Raphson ,metoda lui Lobacevski
*i metoda lui Bairstow.

8.1. Metoda bisec#iei (biparti#iei)
Fie funcia continu f : [a,b] h>R *i ecuaia f(x)=0 care
are soluie unic pe intervalul [a,b]. Pentru condiiile date
funcia satisface inecuaia f(a)f(b)j0 . Se pune problema
determinrii soluiei k a ecuaiei pe intervalul [a,b] (fig. 1),
cu o anumit eroare l.
Metoda const n a verifica dac a sau b sunt soluii ale
ecuaiei f(x)=0 . Dac a *i b nu sunt soluii , se trece la
njumtirea intervalului [a,b] *i se determin valoarea
x
m
=(a+b)/2 . Se verific dac x
m
este soluie a ecuaiei .
Aceast verificare poate fi fcut prin compararea |f(x
m
)| < l
sau compararea |b
n
-a
n
| < l , unde l este eroarea de calcul a
soluiei ecuaiei . Dac x
m
este soluie a ecuaiei , problema s-
a rezolvat ; n caz contrar se evalueaz f(a) , f(x
m
) *i se
verific dac produsul f(a)f(b)j0 . Dac inegalitatea este
satisfcut b
1
=x
m
*i a=a
1
*i soluia se caut in intervalul
[a
1
,b
1
] . Dac inegalitatea nu este satisfcut a
1
=x
m
*i b=b
1
*i
soluia se afl n intervalul [a
1
,b
1
] . Procedeul continu *i se
obin dou *iruri convergente : unul monoton cresctor
mrginit superior de b si altul monoton descresctor mrginit
inferior de a:
a < a
1
< a
2
< ... < a
n
< ...
b > b
1
> b
2
> ... > b
n
> ... (1)
birul lungimilor intervalelor care se obin prin njumtire
este :
b
1
-a
1
=(b-a)/2 , b
2
-a
2
=(b-a)/2
2
, ... , b
n
-a
n
=(b-a)/2
n
,
un *ir descresctor cu limita zero .
b
n
- a
n
lim =0 (2)
nop
2
n
lim b
n
=k (3)
nop
lim a
n
=k (4)
nop
Algoritmul de calcul se opre*te atunci cnd este ndeplinit
condiia |b
n
-a
n
| < l unde l este eroarea impus pentru
calculul soluiei ecuaiei date . Soluia ecuaiei este
aproximat cu valoarea mijlocului intervalului [a
n
, b
n
] .
Lungimea intervalului tinde la zero cnd n tinde la infinit ,
limita capetelor intervalelor fiind un punct a crui
abscis este soluia ecuaiei .

Fig . 1. Graficul funciei y = f(x) pe intervalul [a , b]

8.1.1. Algoritmul 1. Bisec#ia pentru polinoame

{ Variabile
n : gradul polinomului ,ntreg ;
A : coeficienii polinomului , vector ;
ls , ld : limitele intervalului , real ;
er : eroarea de calcul , real ;
rad : rdcina , real ;
x
m
: jumtatea intervalului [l
s
, l
d
] , real ;
{
dac poly( ls,n , A )* poly(ld, n , A ) > 0 atunci
{ scrie ecuaia nu are rdcin ;
stop ;
}
dac poly(ls, n , A) = 0 atunci
{ rad = ls ;
stop ;
}
dac poly(ld, n , A) = 0 atunci
{ rad = ld ;
stop ;
}
xm = ( ls + ld ) / 2 ;
ct timp ( abs( ld - ls ) > er ) si poly(xm, n , a) <> 0 execut
{ xm =( ls + ld ) / 2 ;
dac poly(xm, n , a) *poly(ls, n , a ) < 0 atunci ld = xm ;
altfel ls = xm ;
}
rad = xm;
}
21
8.1.2. Implementarea algoritmului 1

/* Funcia ntoarce :
0 in caz de eec
1 in cazul unui rezultat corect */
int BisectiePolinom (
double ls ,
double ld ,
int grad ,
double Coef[] ,
double eroare ,
double *radacina )
{
double xm ;
if( poly (ls,grad,Coef)*poly(ld,grad,Coef)>0) return 0;
if( poly (ls,grad,Coef) == 0 ) {
*radacina=ls;
return 1;
}
if(poly(ld,grad,Coef)==0){
*radacina=ld;
return 1;
}
xm=0.5*(ls+ld);
while((fabs(ld-ls)>eroare)
&&(poly(xm,grad,Coef)!=0))
{
xm=0.5*(ld+ls);
if(poly(ls,grad,Coef)*poly(xm,grad,Coef)<0)ld=xm;
else ls=xm;
}
*radacina=xm;
return 1;
}
8.1.3 Algoritmul 2. Bisec#ia pentru ecua#ii transcendente

{ Variabile
(F ecuaia,funcie real de variabil real)
ls,ld:limitele intervalului,real;
er:eroarea de calcul,real;
xm:mijlocul intervalului,real;
rad:rdcina,real;
{
dac F(ls)*F(ld)>0 atunci { soluia nu exist, stop }
altfel
dac F(ls)=0, atunci { soluia este rad=ls;
stop
}
dac F(ld)=0, atunci { soluia este rad=ld;
stop
}
xm=(ls+ld)/2;
ct timp (abs(ld-ls)>er) i (F(xm)<>0) execut
{ xm=(ls+ld)/2;
dac F(xm)*F(ls)<0 atunci ld=xm;
altfel ls=xm;
}
soluia este rad=xm;
}
8.1.4 Implementarea algorimului 2

/* Funcia ntoarce:
0 n caz de eec
1 n cazul unui rezultat corect
*/
int BisectieFunctie(double(*f)(double),
double ls,
double ld,
double err,
double *solutie)
{
double xm;
if(f(ls)*f(ld)>0) return 0;
if(f(ls)==0)
{ *solutie=ls;
return 1;
}
if(f(ld)==0)
{
*solutie=ld;
return 1;
}
xm=0.5*(ls+ld);
while( (fabs(ld-ls)>err)&&(f(xm)!=0) )
{
xm=0.5*(ls+ld);
if( f(ls)*f(xm)<0) ld=xm;
else ls=xm;
}
*solutie=xm;
return 1;
}
9 INTERPOLAREA

Interpolarea este una dintre metodele de aproximare a
funciilor. Considerm dat o funcie sub form de tabel.
Cunoscnd valorile funciei n anumite puncte pentru care
funcia este definit, se pune problema cunoa*terii valorilor
funciei n alte puncte ale domeniului de definiie, n care
funcia este necunoscut. Aceast problem se pune n cazul
reprezentrii grafice a funciei tabelate sau n cazul necesitii
cunoa*terii valorii funciei ntr-un punct n care nu este
necunoscut.
n cazul cunoa*terii expresiei analitice a funciei y=f(x),
valorile necunoscute ale funciei se calculeaz prin
introducerea argumentului corespunztor n funcie. Dac nu
se cunoa*te expresia analitic a funciei, se aproximeaz
funcia cu o alt funcie, care o aproximeaz cel mai bine pe
prima ntre punctele unde dorim valoarea funciei.
Aproximarea funciei date cu o funcie liniar sau cu o
funcie polinomial de un anumit grad poate da valori foarte
apropiate de valorile funciei.

9.1 Interpolarea polinomial3
Se consider funcia dat prin tabelul 1:

x x
0
x
1
x
k
x
n
y y
0
y
1
y
k
y
n
Cunoa*tem valoarea funciei n n+1 puncte. Prin n puncte
se poate duce un polinom de gradul n, unic determinat.
22
Fie polinomul:
0 1
1
1 1
... ) ( a x a x a x a x P
n
n
n
n n
+ + + + =


(5)
Conform tabelului 6.1 avem sistemul:

= + + + +
= + + + +
= + + + +

n n
n
n n
n
n n
n
n
n
n
n
n
n
n
y a x a x a x a
y a x a x a x a
y a x a x a x a
0 1
1
1
1 0 1 1
1
1 1 1
0 0 0 1
1
0 1 0
...
....... .......... .......... .......... .......... ..........
...
...
(6)
Consideram sistemul omogen :

= + + + +
= + + + +
= + + + +

0 ...
....... .......... .......... .......... .......... ..........
0 ...
0 ...
0 1
1
1
0 1 1
1
1 1 1
0 0 1
1
0 1 0
a x a x a x a
a x a x a x a
a x a x a x a
n
n
n n
n
n n
n
n
n
n
n
n
n
n
(7)
Determinantul sistemului omogen este diferit de zero. Dac
determinantul sistemului ar fi zero, ar nsemna c polinomul
de gradul n ar avea n+1 soluii
n
x x x x ,..., , ,
2 1 0
ceea ce
este imposibil. Acest sistem omogen admite numai soluii
banale, ca urmare, determinantul sistemul (6) rezultnd c
acest sistem este un ramer cu soluii unice determinate. Deci,
polinomul de grad n este unic determinat. Pentru
simplificarea calculului scriem polinomul sub forma
urmtoare :

0 1
1
1
.... ) ( a x a x a x x P
n
n
n
n
+ + + + =

(8)
El este obinut din polinomul (5) prin mprire cu a
n
lsnd
notaia neschimbat a coeficienilor dup mprire.
) )....( )( ( ) (
2 1 0 n
x x x x x x x = H
) )....( )( ( ) (
2 0 1 n
x x x x x x x = H (9)

) )....( )( ( ) (
1 1 0
= H
n n
x x x x x x x
Formm polinomul P
n
(x) sub forma:
) ( ... .... ) ( ) ( ) (
1 1 0 0
x b b x b x b x P
n n k k n
H + + H + + H + H = (10)
Trebuie s determinmcoeficienii b
0
,b
1
,,b
n
.
) (
) (
0 0
0
0
x
x P
b
n
H
= ,
) (
) (
1 2
1
1
x
x P
b
n
H
= ,.,
) (
) (
k k
k n
k
x
x P
b
H
= ,,
) (
) (
n n
n n
n
x
x P
b
H
= (11)
Ca urmare,

Polinomul de gradul n care trece prin n+1 puncte date, numit
*i polinomul de interpretare al lui Lagrange, are forma:
. ) (
, 0 0 j i
i
n
i j j
n
i
i n
x x
x x
y x P

=
H
= = =
(12)
Expresia polinomului lui Lagrange este funcie de
coordonatele punctelor cunoscute *i de variabila x. Cu
ajutorul formulei determinate (12) a polinomului, care
aproximeaz o funcie, se poate calcula valoarea funciei n
orice punct necunosut cuprins ntre x
0
si x
m.

9.1.1 Particulariz3ri ale polinomului lui Lagrange
Dac considermdou puncte, interpolate devine liniar
1 2
1
2
2 1
2
1
x x
x x
y
x x
x x
y y

= (13)
Eroarea de trunchiere a interpolrii liniare devine
( )
( )( )
2 1
' '
! 2
x x x x
f
e
T
=

2
x x
q
< < (14)
Pentru trei puncte, interpolarea devine ptratic.
9.1.2 Algoritmul 3. Polinomul lui Lagrange
{Variabilele
n: numrul de puncte cunoscute, ntreg;
x: abcisele punctelor cunoscute, vector;
y: ordonatele punctelor cunoscute, vector;
x : punctul n care se calculeaz interpolarea, real;
i,j: contoare, ntregi;
sum: variabila ce reine suma, real;
prod: variabila ce reine produsul, real;
{sum=0;
pentru i=0..n
{prod=1;
pentru j=0..n dac j=i atunci
calculeaz prod = prod ; *
j i
j
x x
x x

sum= sum +y
i
* prod;
}.

9.1.3 Implementarea algoritmului 3
/* Funcia care implementeaz metoda lui Lagrange
de interpolare
double Lagrange(int n,
double x[],
double y[],
double point)
{
int i,j;
double sum=0, prod;
for(i=0; i<=n; i++)
{
prod = 1;
for(j=0;j<=n;j++)
if (j!=i)
prod*=(point-x[j])/(x[i]-x[j]);
sum+=y[i]*prod;
}
return sum;
}
9.2 Metoda lui Aitken de interpolare

Metoda lui Aitken de interpolare d acela*i rezultat ca *i
metoda lui Lagrange de interpolare doar c prin aceast
metod nu se determin un polinom, ci se realizeaz mai
multe interpolri liniare. Cu fiecare interpolare, numrul
punctelor rmase se mic*oreaz cu o unitate, iar funcia ce
trece prin dou puncte de la etapa curent cre*te n grad,
astfel c n final, dac sunt date n+1 puncte, se obine o
funcie de gradul n.
Considernd c funcia e dat n tabelul 2

j i
i
n
i j j
n
i
i
n
i
n
i
i
i i
i
i n n
x x
x x
y
j
x
i
x
n
i j j
i
x x
n
i j j
y
x
x
x P x P

=
=
H
= =
H
= =
=
H
H
=
H

= = =
= =
, 0 0
0 0
) (
, 0
) (
, 0
) (
) (
) ( ) (
23
Tabelul 2
X Y
x
0
y
0
x
1
y
1
y
01
x
2
y
2
y
02
y
012

x
3
y
3
y
03
y
013
y
0123

x
4
y
4
y
04
y
014
y
0124
..
.. .. .. .. ..
x
n
y
n
y
0n
y
01n
y
012n
.. y
012..n
1
0
0
0
0
0
y
x x
x x
y
x x
x x
y
j j
j
j

= j=1,2,3,,n
Ioj
x x
x x
I
x x
x x
y
j j
j
j
1
1
01
1
01

= j= 2,3,,n (15)
.
n n
n n
n
n n
n n
n
n
I
x x
x x
I
x x
x x
y
) 2 ...( 012
1
1
) 1 )( 2 ...( 012
1
.. 012

= (16)

9.2.1 Algoritmul 4. Metoda lui Aitken
{Variabilele
n: numrul de puncte date ale funciei, ntreg;
x: abcisele punctelor date, vector;
y: ordonatele punctelor date, vector;
xp: punctul n care se interpoleaz funcia, real;
i,j: contoare, ntregi;
{
pentru i=1n
pentru j=i...n
calculeaz
;
1
1
1
1

=
i j
i p
i
j i
j p
i j
x x
x x
y
x x
x x
y y
}
valoarea interpolat este
}
9.2.2. Implementarea algoritmului 4

/* Funcia care implementeaz metoda lui Aitken de
interpolare
Functia ntoarce valoarea interpolar */
double Aitken(int n,
double x[],
double y[],
double point)
{
int i,j;
for(i=0; i<=n; i++)
for(j=i; j<=n; j++)
y[j]=y[i-1]*(point-x[j])/(x[i-1]-x[j])+y[j]*(point-x[i-
1])/(x[j]-x[i-1]);
return y[n];
}
10. REZOLVAREA NUMERICW A ECUA8IILOR
DIFEREN8IALE ORDINARE DE ORDINUL NTI
Se consider ecuaiile de tipul:
y=f(x,y) (17)
cu condiia iniial:
y(x
0
)=y
0
(18)
Ecuaia diferenial (17) define*te o curb n planul xOy. n
fiecare punct al curbei se d valoarea derivatei funcie de x *i
y. Ecuaia este satisfcut de o familie de curbe, iar condiia
(18) d curba din familie care trece printr-un anumit punct
din plan (x
0
,y
0
). Soluia analitic a ecuaiei (17) este o
expresie a lui y funcie de x. Metodele numerice ne ajut s
determinm puncte ale soluiei ecuaiei date.
O soluie numeric a ecuaiei se poate obine plecnd din
punctul dat (x
0
,y
0
), *tiind c dac nlocuim valorile date, n
ecuaia diferenial (8.1) se obine panta curbei cutate n
acest punct. Dup calculul pantei curbei n punctul x0 se
avanseaz cu un pas mic pe tangent n punctul (x
0
,y
0
)
y=f(x
0
,y
0
)(x-y
0
)+y
0
(19)
Dac considerm punctul de coordonare (y
1
,x
1
)pe tangent *i
pasul de cre*tere al lui x
1
fa de x
0
,h avem
x
1
=x
0
+h si y
1
=f(x
0
,y
0
)h+y
0
(20)
deci un nou punct cunoscut (x
1
,y
1
), foarte aproape de curba
soluiei cutate cu ct h este mai mic. Procedeul de calcul se
repet cu calculul pantei la curb n punctul (x
1
,y
1
) *i
determinarea unui alt punct pe tangent la curb n punctul
(x
1
,y
1
) cu x
2
=x
1
+h *i y
2
corespunztor. Continund n
acest mod se obine o succesiune de segmente de dreapt care
aproximeaz curba soluie a ecuaiei difereniale.
Aproximarea curbei soluie cu segmente de dreapt poate da
erori *i succesiunea de segmente de dreapt poate s se
deprteze considerabil de curba soluiei. Aceast problem
reprezint problema stabilitii procesului de rezolvare a
ecuaiei difereniale *i trebuie s-i acordm o atenie
deosebit. Trebuie implementat o metod prin care, n loc s
aproximm soluia printr-o succesiune de drepte, s se ia n
considerare *i curba soluiei adevrat.
Exist dou tipuri de metode:
a)Metode directe - n care soluia nu se itereaz *i se folose*te
numai o informaie asupra curbei ntr-un punct. Astfel de
metode constau n rezolvarea ecuaiilor prin serii Taylor, care
ns nu sunt practice. Metode practice Runge-Kutta pretind
un mare numr de evaluri ale funciilor, iar eroarea este
dificil de evaluat.
b)Metode indirecte n care se poate estima punctul urmtor
de pe curb folosind mai puine estimri ale funciei, dar
necesit iterri pentru a ajunge la o valoare suficient de
precis. Aceste metode sunt denumite predictor-corector *i
prin aplicarea lor se poate obine o estimare a erorii.

10.1. Metoda seriilor lui Taylor
Aceast metod asigur soluia oricrei ecuaii difereniale,
dar are o aplicabilitate redus din cauza dificultilor de
rezolvare. Totu*i, aceast metod serve*te pentru compararea
cu metodele practice pentru a le stabili ordinul metodei.
Dezvoltam pe y(x) in jurul lui x=x
m :
) 1 (
) 1 ( ) (
2
) (
)! 1 (
) (
) (
!
) (
! 2
) ( ) (
+
+

+
+ +
+ +
' '
+ ' + =
j
m
j
m j
m
j
m
m
m
m m m
x x
j
y
x x
j
y
x x
y
x x y y x y

L
(21)
unde m
j
y
) (
este derivata de ordinul j a lui y(x) n punctul
x=x
m
,iar x
m
<r<x

24
Utiliznd relaia x=x
m
+h obinem:
1
) 1 ( ) (
2
1
)! 1 (
) (
!
2
+
+
+
+
+ +
+ + ' ' + ' + =
j
j
m
j
m
m m m m
h
j
y
j
y
y
h
y h y y

L
(22)
Ultimul termen al relaiei (22) reprezint eroarea de
trunchiere. Aproximaia va fi cu att mai bun cu ct j este
mai mare.
) , (
m m m
y x f y = ' (23)
Derivnd funcia y=f(x,y) obinem:
f f f
dx
dy
dy
y x df
dx
y x df
y
y x
+ = + = ' '
) , ( ) , (
(24)
unde
dx
df
f
x
= si
dy
df
f
y
= (25)
Pentru x=x
m
rezult:
j f f x
y x m
+ = ' ' (26)
Pentru j = 2 rezult:
3
2
1
6
) (
2
h
y
y
h
y h y y
m m m m
' ' '
+ ' ' + ' + =
+
(27)
sau
(

+ + + =
+
) (
2
1 y x m m
f f f
h
f h y y (28)
cu eroarea de trunchiere
3
6
) (
h
y
e
T
' ' '
= (29)
Punnd m = 0 n ecuaia (28) se obine pentru x
1
=x
0
+h
valoarea soluiei y
1
deci punctul (x
1
,y
1
). Pentru m=1 rezult
punctul (x
2
,y
2
). Continund, se obin punctele soluiei
ecuaiile difereniale, cu erorile de trunchiere
corespunztoare, care se mresc n timp. Aceast metod este
direct deoarece pentru calculul lui y
m+1
sunt necesare numai
valorile lui y
m
*i x
m
. Pentru o eroare mai mic trebuie s
mrim ordinul termenilor utilizai n dezvoltarea Taylor.
Dac dorim
, , ,
m
y acesta are expresia:
2 2
2
y x y x yy xy xx m
f f f f f f ff f y + + + + = ' ' ' (30)
Complexitatea acestor derivate face practic inutilizabil
aceast metod.
10.2. Metodele Runge-Kutta
Metodele Runge-Kutta se caracterizeaz prin urmtoarele
proprieti:
1.Sunt metode directe, deci pentru calculul lui y
m+1
sunt
necesare informaiile de la punctul precedent x
m
*i y
m
.
2.Sunt echivalente cu seriile Taylor pn la termenii h
p
unde
p este diferit pentru metode diferite *i se nume*te ordinul
metodei.
3.Nu necesit evaluarea nici unei derivate a funciei f ci
numai valoarea funciei. Proprietatea a treia a metodelor
Runge-Kutta le recomand pentru utilizarea lor practic. Se
pune problema evalurii funciei soluie a ecuaiei difereniale
(17) n mai multe puncte. Geometric, problema const n
determinarea punctul (x
m+1
, y
m+1
) cunoscnd punctul

(x
m
,y
m
) *i c x
m+1
= y
m+h
. n punctul (x
m
, y
m
) se duce
tangenta la curb deoarece *tim panta curbei n acest punct.
y=y
m
+y
m
(x-x
m
) (31)
unde
y'
m
=f(x
m
,y
m
) (32)
*i
x
1 + m
=x
m
+h (33)
nlocuind n (31) relaia (32) *i (33) rezult:
x
1 + m
=x
m
+h (34)
iar eroarea este dat de segmentul e.
Dac n dezvoltarea lui Taylor lumj=1 rezult:
( )
2
1
2
h
y
y h y y
m m m
' ' '
+ ' + =
+
(35)
unde
1 +
< <
m m
x x (36)

Fig2 Determinarea grafic a soluiei ecuaiei difereniale.

Comparnd relaiile (35) si (36) rezult eroarea de trunchiere
pentru metoda aplicat:
( )
2
2
h
y
e
n
T

= (37)
Formula (35) reprezint metoda lui Euler de rezolvare a
ecuaiilor difereniale de ordinul nti. Metoda este veche, are
eroare de trunchiere relativ mare si eroarea de rotunjire se
mre*te odat cu mrirea lui x.

10.2.1 Algoritm 5 Metoda lui Euler
{ Variabile
0
x : abscisa punctului de start, real;
0
y :ordonata punctului de start, real;
h: pasul intre abscisele punctelor de calcul ale solutiei, real;
y: ordonatele solutiei numerice, vector;
x: abscisele solutiei numerice, vector;
n: numarul de puncte in care se calculeaza solutia, intreg;
{
x[0]=x
0
;y[0]=y
0
;h=const;
pentru i=0,1,2,n
calculeaza x[i]=x
0
+i*h;
calculeaza y[i+1]=y[i]+h*f(x[i-1],y[i-1]);
solutiile numerice sunt x[i]; y[i]; i=0,1,2,n;
}
}
m
y
m
x
1 + m
x
D1
x
y
25
10.2.2 Implementarea algoritmului 5

/* Functia care implementeaza algoritmul de
rezolvare a ecuatiilor diferentiale ordinare prin
metoda Euler.
/*
void EULERED(double(*f)(double x,doubel y),
double x0,
double y0,
double pas,
int nrp,
double sol[])
{
int i;
sol[0]=y0;
for(i=1;i<=nrp;i++)
sol[i]=sol[i-1]+pas*f(x0+(i-1)*pas,sol[i-1]);
}
10.3 Metoda Runge-Kutta de ordinul patru
Formula de calcul numeric a soluiei ecuaiei difereniale (17)
este dat de expresia (38)
h x x
m m
+ =
+1
[ ]
4 3 2 1 1
2 2
6
k k k k
h
y y
m m
+ + + + =
+
(38)
unde ( )
m m
y x f k ,
1
=
|
.
|

\
|
+ + =
1 2
2
,
2
k
h
y
h
x f k
m m
(39)
|
.
|

\
|
+ + =
2 3
2
,
2
k
h
y
h
x f k
m m
( )
3 4
, hk y h x f k
m m
+ + =
Eroarea de trunchiere a metodei este:
5
h k e
T
~ (40)

10.3.1. Algoritmul 6.Metoda Runge-Kutta de ordinul 4
{ Variabile
x
0
:abscisa punctului prin care trece solutia real;
y
0
:ordonata punctului prin care trece solutia , real;
h:pasul intre abscisele punctelor de calcul ale solutiei, real;
y:ordonatele solutiei numerice, vector;
x:abscisele solutiei numerice, vector;
n:numarul de puncte in care se calculeaza solutia, intreg;
{x[0]=x
0
; y[0]=y
0
;
pentru i=0,1-n
{
calculeaza x[i]=x
0
+i*h;
calculeaza k
1
=f(x[i],y[i]);
calculeaza k
2
=f(x[i]+0.5*h,y[i]+0.5*h*k
1
);
calculeaza k
3
=f(x[i]+0.5*h,y[i]+0.5*h *k
2
);
calculeaza k
4
=f(x[i]+0.5*h,y[i]+0.5*h *k
3
);
calculeaza y
1 + i
=y[i]+h/6(k
1
+2k
2
+2k
3
+k
4
);
}
Solutiile numerice ale ecuatiei sunt x[i], y[i], i=0,1,2n;
}
}
10.3.2. Implementarea algoritmului 6

/*Functia care implementeaza algoritmul de
rezolvare a ecuatiilordiferentiale ordinare prin
metoda Runge-Kutta de ordinul 4.
*/
void RK4(double(*f)(doublex,double y),
double x0,
double y0,
double pas,
int nrp,
double sol[])
{
int I;
double k1,k2,k3,k4;
sol[0]=y0;
for(i=1;i<=nrp;i++)
{
k1=f(x0+(i-1)*pas,sol[i-1]);
k2=f(x0+(i-1)*pas+0.5*pas,sol[i-1]+0.5*pas*k1);
k3=f(x0+(i-1)*pas+0.5*pas,sol[i-1]+0.5*pas*k2);
k4=f(x0+i*pas,sol[i-1]+pas*k3);
sol[i]=sol[i-1]+pas*(k1+2*k2+2*k3+k4)/6.0;
}
}
Concluzie: Putem spune despre metodele Runge-Kutta c
sunt metode cu vitez de calcul mare, deoarece calculul unui
punct curent de pe curba soluiei se face numai cu valorile
calculate de la punctul precedent. Precizia metodelor depinde
de eroarea de trunchiere.
Dac considerm ca n punctul x=x
0
+h valoarea exact a
soluiei este y
m
, cu metoda clasica de ordinul unu rezult:
( ) 2
kh y y
h
m m
+ = (41)
Unde
( ) h
m
y arat c y
m
s-a calculat cu pasul h. Se repet
calculul pentru pasul h/2 si avem
( )
|
|
.
|

\
|
+ =
4
2
2 /
h
k y y
h
m m
(42)
Din egalitatea relaiilor (41) *i (42) rezult :
( ) 2 2 /
4
3
h y y
h
m
h
m
~ (43)
Iar eroarea de trunchiere devine:
( ) ( )
( )
h
m
h
m T
y y kh e = ~
2 / 2
3
4
(44)
Aplicnd metodele Runge Kutta de ordinul doi rezult:
( ) ( )
( )
h
m
h
m T
y y kh e = = ~
2 / 3
7
8
(45)
Metoda Runge Kutta de ordinul patru are o eroare de
trunchiere care poate fi estimat cu relaia:

( ) ( )
( )
h
m
h
m T
y y kh e = ~
2 / 5
! 3
32
(46)
dedus prin acela*i procedeu ca *i metoda Runge Kutta de
ordinul nti.
n anumite condiii metodele Runge Kutta pot da
rezultate foarte imprecise chiar daca erorile de trunchiere *i
rotunjire sunt mici. Aceasta se datoreaz faptului c erorile de
trunchiere sau rotunjire pot cre*te o dat cu x.

26
Probleme rezolvate
1 Se consider un amplificator integrat,avnd n bucl
deschis o amplificare de forma:

7 0009680743 . 0 05120153 . 0 5284 . 0
6260295 . 338
) (
2
3
+ + +
=
s s
s
s H
S se determine daca funcia de amplificare are un pol in
(-0.5,-0.3), iar in caz afirmativ sa se afle valoarea acstui pol

#include<math.h>
#include<iostream.h>
int BisectiePolinom (
double ls ,
double ld ,
int grad ,
double Coef[] ,
double eroare ,
double *radacina )
{
double xm ;
if( poly (ls,grad,Coef)*poly(ld,grad,Coef)>0) return 0;
if( poly (ls,grad,Coef) == 0 ) {
*radacina=ls;
return 1;
}
if(poly(ld,grad,Coef)==0){
*radacina=ld;
return 1;
}
xm=0.5*(ls+ld);
while((fabs(ld-ls)>eroare)
&&(poly(xm,grad,Coef)!=0))
{
xm=0.5*(ld+ls);
if(poly(ls,grad,Coef)*poly(xm,grad,Coef)<0)ld=xm;
else ls=xm;
}
*radacina=xm;
return 1;
}
void main(void)
{
double *rad;
double f[]={0.0009687437,0.05120153,0.5284,1};
if (BisectiePolinom(-0.5,-0.3,3,f,0.000001,rad)==1)
{cout<<"Functia are un pol in (-0.5,-0.3) egal cu:";
cout<<*rad;}
else
cout<<"Functia nu are pol";
}
2. Se d ecuaia 0 / 1 = x e
x
care are o soluie n intervalul (0.1,1).S se calculeze soluia
ecuaiei aplicnd metoda biseciei pentru ecuaii
transcendente cu o eroare de calcul de 0000000001 . 0 = c
/*Funcia care implementeaz algoritmul Bisecte,
prime*te un pointer (adresa) ctre functia matematica pentru
care se cauta radacinile*/
#include<math.h>
#include<iostream.h>
double fct(double x)
{
double val_fct;
val_fct=exp(x)-1/x;
return (val_fct);
}
int BisectieFunctie(double(*f)(double),
double ls,
double ld,
double err,
double *solutie)
{
double xm;
if(f(ls)*f(ld)>0) return 0;
if(f(ls)==0)
{ *solutie=ls;
return 1;
}
if(f(ld)==0)
{
*solutie=ld;
return 1;
}
xm=0.5*(ls+ld);
while( (fabs(ld-ls)>err)&&(f(xm)!=0) )
{
xm=0.5*(ls+ld);
if( f(ls)*f(xm)<0) ld=xm;
else ls=xm;
}
*solutie=xm;
return 1;
}
void main(void)
{
double ls=0.1,ld=1.0,err=0.00000001,*sol;
BisectieFunctie(fct,ls,ld,err,sol);
cout<<"Solutia ecuatiei f(x)=0 pe intervalul:
("<<ls<<","<<ld<<") este: "<<*sol;
}
3 . Se consider datele experimentale obinute pentru
caracteristica rezistenei termice jonciune teminal R
jt
[
0
C/W]
funcie de lungimea terminalului 1[inch],pentru o diod
Zener prezentare n tabelul urmtor:

1
[inch]
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
Rjt
[
0
C/w]
70 140 175 200 225 250 265 280 290 300
Se cere s se determine puncte ntre valorile date pentru o
reprezentare grafic ct mai precis. De exemplu pentru :
l=0.45 ; l=0.54 ; l=0.67

#include<iostream.h>
double Lagrange(int n,
double x[],
double y[],
double point)
27
{
int i,j;
double sum=0, prod;
for(i=0; i<n; i++)
{
prod = 1;
for(j=0;j<n;j++)
if (j!=i)
prod*=(point-x[j])/(x[i]-x[j]);
sum+=y[i]*prod;
}
return sum;
}
void main(void)
{
int n=10;
double val;
double x[]={0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};
double
y[]={70,140,175,200,225,250,265,280,290,300};
double l=0.45;
val=Lagrange(n,x,y,l);
cout<<"Valoarea rezistentei pentru l="<<l<<" este:
"<<val;
}
4 Se consider un circuit R,L in serie alimentat de la o
sursa de curent alternativ e=10cos(100Nt)V, f=50Hz,
prezentat in fig.(3).
R
i
L
e
k
Fig.3 Circuitul R,L

Cunoscnd R=10s, L=10mH *i c la t=0 i=0, s se calculeze
valorile curentului la t=0.001; 0.002, 0.003; 0.004; 0.005,
0.006; 0.007, 0.008, 0.009; 0.01 s.
Se aplic circuitului electric legea a doua a lui Kirchhoff *i se
obine ecuaia diferenial e Ri
dt
di
L = + .
/*Functia care implementeaza algoritmul RK4,
primeste un pointer (adresa) catre functia
matematica corespunzatoare ec diferentiale*/

#include<math.h>
#include<iostream.h>
double fct(double x,double y)
{
double val_fct;
val_fct=(10*cos(314*x)-10*y)/0.01;
return (val_fct);
}
void RK4(double(*f)(double x,double y),
double x0,
double y0,
double pas,
int nrp,
double sol[])
{
int i;
double k1,k2,k3,k4;
sol[0]=y0;
for(i=1;i<=nrp;i++)
{
k1=f(x0+(i-1)*pas,sol[i-1]);
k2=f(x0+(i-1)*pas+0.5*pas,sol[i-1]+0.5*pas*k1);
k3=f(x0+(i-1)*pas+0.5*pas,sol[i-1]+0.5*pas*k2);
k4=f(x0+i*pas,sol[i-1]+pas*k3);
sol[i]=sol[i-1]+pas*(k1+2*k2+2*k3+k4)/6.0;
cout<<"\n"<<(i)*pas<<" "<<sol[i];
}
}
void main(void)
{
double x0=0,y0=0,h=0.001,sol[10];
cout<<"t[s] i[A]";
cout<<"\n0.000 0.000";
RK4(fct,x0,y0,h,10,sol);
}

S-ar putea să vă placă și