Sunteți pe pagina 1din 9

Cur FP 6

Tipul struct
Cu ajutoruil cuvâ ntului rezervat struct putem construi un tip de date complex pornind de la
tipuri de date existente. O structură este alcă tuită în C dintr-o colecție de așa-numite câmpuri
(date). În C ca membrii unei structuri nu putem avea funcții.
Struct nume
{
Tip1 camp11, camp12,…….;
Tip camp21, camp22,………;
……………………………………….
Tip campn1,…………………….;
};
Declacarea unei structuri se încheie obligatoriu cu ;. Tipul de date construit în C poartă
denumirea de struct nume.
Declarații de variabile:
Struct nume v1,v2,.........;
Nume v1,v2,……….;
În C pentru a scă pa de cuvâ ntul rezervat struct atunci câ nd ne referim la o structură se
foloseștre de obicei un typedef.
Typedef struct nume nume;
Nume v1,v2,……….; (acum e corect)
Pentru a simplifica scrierea de mai sus de multe ori se procedează astfel:
Typedef struct
{
………………….
}nume;
Nume t1,t2,………..;
Între acolada închisă } și ; pot apă rea declarații de variabile (opțional).

Pointeri

Definiție: Un pointer este o variabilă care poate reține o adresă de memorie.


Declarare:
Tipdate * p;
Cur FP 6

Despre variabila p se spune că este de tipul tipdate steluță sau este un pointer că tre tipdate
unde tipdate este un tip de date existent.
ex: int* p; un pointer că tre int
int v=1;
p=&v;
&(and) este un operator unar ce se aplică unei variabile și returnează adresa de memorie a
variabilei respective. O adresă de memorie este de fapt un numă r întreg pozitiv și care
reprezintă o poziție în memorie relativ la începutul acesteia.
V=1 .................... p
1 2 3 4
*p==1
Pentru operatorul and(&) există operatorul asterisc(*) care este inversul operatorului and ca
funcționalitate. Operatorul asterisc este tot un operator unar, dar care se aplică numai unui
pointer. Prin *p se înțelege valoarea de la adresa reținută în variabila p.
În exemplul nostru p fiind pointer că tre int. *p va fi o valoare de tip int. Evident *p în exemplul
nostru este 1 fiind practic valoarea variabilei v.
*&v==v
&*p=p
*&p==p
&*v v nu mai e de tip pointer
Un pointer din cauză că reține practic valori numerice întregi înseamnă că au sens operatorii +,-.
++,-- aplicați unui pointer.
p+1 reprezintă adresa locației de memorie aflată imediat după locațiade la adresa p.
Practic p+1 este egal cu valoareal lui p la care se adaugă sizeof(int). Adică p+1 e cu 4 unită ți mai
mare decâ t p.
p++ în p se va reține adresa de după p.
p-1
ex:
int v=1;
int *p=&v;
char *p2;
p2=p;
Atribuirea p2=p de mai sus este posibilă deoarece atâ t p câ t și p2 sunt variabile pregă tite pentru
a reține adrese de memorie. În C atribuirea p2=p este considerată validă. În C++ o astfel de
atribuire conduce la eroare la compilare.
Cur FP 6

p2=(char*)p; (e okey in C și în C++)

int v=…..;
char* p=(char*)&v;
*p==R roșu
*(p+1)=G galben
*(p+2)=B albastru
*(p+3)=α transparență

struct test
{
int i; structura ocupă 8 octeți
float f;
};
struct test t;
scanf(“%d%f”,&t.i,&t.f);
printf(“%d %f”,t.i,t.f);
printf(“%d %f”,*(int*)&t,*(float*)((int*)&t+1));

DESEN

struct t
{
short s; structura ocupă 4 octeți
char c;
};

int a[10];
În scrierea a[10], a este o variabilă ce reține adresa primei locații de memorie din vectorul de
lungime 10. Din acest punct de vedere a se aseamă nă cu un pointer. Deosebirea este că a este o
constantă care reține o adresă de memorie, deci a nu își poate modifica valoarea.
a=7;
Cur FP 6

a++;

ALT DESEN

În C pentru tipul pointer există declarat operatorul binar „[]”.


Prin a[k] compilatorul înțelege și traduce, practic, în * aplicat lui a+k.
Operatorul [] este introdus pentru a lucra cu vectori în limbajul C mai aproape de limbajul
natural, dar scrierea a[k] este tradusă la compilare imadiat în *(a+k).
a[k]==*(a+k)==*(k+a)==k[a]; pentru că + este comutativ
1[a] a doua că suță din a

Pointeri către funcții


În C, pe lâ ngă pointeri că tre variabile, putem avea pointeri că tre funcții. Practic un astfel de
pointer reține adresa de memorie unde este implementată o funcție.
ex: int inc(int i)
{
return i+1;
}
void main()
{
int (*p)(int);
p=&intc;
printf(“%d\n”,(*p)(7)); // se afișează pe ecran 8
}

În momentul în care un pointer că tre o funcție primește adresa unei funcții compilatorul
acceptă și scrierea p=inc;. De asemenea apelul unei funcții a că rei adrese este reținută într-un
pointer poate fi fă cut și fă ră a mai folosi operatorul *, adică pot scrie direct p(7), dar corect este
(*p)(7).
Din cauză că în C putem avea pointeri că tre funcții putem aduce astfel în interiorul unui struct și
funcții, scriind practic pointeri că tre funcții pe care îi inițializă m cu adresele funcțiilor dorite.
struct t
{
int i;
Cur FP 6

int (*f)(int);
};

Apeluri de funcții în C
void inc(int i)
{
i++;
}

void main()
{
int x=1;
inc(x);
printf(“%d”,x); // Se afișează 1
}
În C există numai transmitere de parametrii prin valoare, adică practic parametrii funcției în
momentul apelului se inițializează cu valorile de apel.
Pentru exemplul de mai sus, în stiva de execuție a programului avem:
1. x intră în stiva de execuție la întâ lnirea declarației variabilei x și se inițializează cu 1
2. La apelul funcției inc se întâ lnește declarația variabilei i ca fiind de tip int care intră în
stiva de execuție și primește valoarea de apel, adică valoarea lui x din momentul apelului
(i devine1)
3. i crește cu o unitate și devine 2
4. La pă ră sirea funcției inc variabila i este scoasă din stiva de execuție
5. Execuția contunuă în funcția main după apelul inc și se afișează valoarea lui x, care a
ră mas evident 1
6. La pă ră sirea funcției main variabila x pă ră sește stiva de execuție.
ALT DESEN

Pentru a returna valori calculate într-o funcție prin intermediul parametrilor în C se face un
artificiu în sensul că în loc să transmitem în această situație valoarea unei variabile transmitem
adresa ei.
int intc2(int* i)
{
(*i)++;
}
Cur FP 6

void main()
{
int x=1;
inc2(&x); & ca să se potrivească
printf(“%d\n”,x);
}
1. În stiva de execuție intră x avâ nd valoarea 1.
2. În stiva de execuție intră variabila-------------
3. Scrierea (*i)++ incrementează practic variabila x cu o unitate pentru că *i=*&i=x.
4. Variabila
ex:
void div(int x, int y, int* c, int* r)
{
*c=x/y; *r=x%y;
}

void main()
{
int a,b,c,r;
scanf(“%d%d”,&a,&b); a, b se inițializează în funcția scanf
div(a,b,&c,&r);
printf(“%d %d”,c,r);
}
Cur FP 6

Alocarea dinamică a memoriei

Ex: int a[10];


În scrierea int a[10] avem alocată static 10 că suțe de memorie pentru variabila a. Între
paranteze pă trate în exemplul de mai sus trebuie obligatoriu să apară o constantă . În momnetul
în care alocă m static memorie trebuie să estimă m încă din momentul redactă rii codului care
este lungimea maximă a zonei de memorie pe care o vom folosi, în exemplul de mai sus pentru
vectorul a.
În momentul rulă rii aplicației de cele mai multe ori din contextul execuției programului se poate
determina lungimea zonei de memorie necesară execuției. De aceea, de cele mai multe ori se
preferă ca pentru vectori, matrici, etc, să se aloce dinamic memorie în momentul execuției
aplicației.
Avantaje:
 Putem aloca exact atâ ta memorie câ t avem nevoie
 Putem elibera oricâ nd zonele de memorie de care nu mai avem nevoie
 Dinamic putem aloca memorie mult mai mult decâ t static
Pentru a aloca dinamic memorie în C se folosesc funcțiile: malloc, calloc, realloc, free.
Antetele funcțiilor de mai sus le întâ lnim în ”malloc.h” sau ”stdlib.h”
Funcția malloc primește ca parametru un numă r întreg care reprezintă de octeți de memorie ce
se dorește a se aloca. Funcția returnează o valoare de tip void*. În cazul în care alocarea s-a făcut
cu succes se returnează adresa de memorie a zonei alocate dinamic. În caz de insucces se
returnează adresa nulă, adică se returnează valoarea constantei NULL.
ex:
malloc(int)
int*x=(int*)malloc(sizeof(int)); am alocat un octet
nr de octeți
int*a=(int*)malloc(n*sizeof(int));
if(a==NULL) exit(1);

În exemplul 2 am alocat n că suțe de tip int, unde n este variabilă . a va reține în acest caz adresa
de început a vectorului.
*Constanta NULL are valoarea 0.
Un pointer câ nd are valoarea NULL înseamnă că nu reține nicio adresă de memorie.

void *p; e okey


*p
Cur FP 6

Funcția calloc primește doi parametrii. Primul parametru reprezintă nr. de blocuri de memorie
ce se dorește a se aloca, iar al doilea parametru reprezintă lungimea în octeți a unui bloc. calloc
se potrivește foarte bine pentru alocare de memorie pentru un vector.
Calloc(int,int)
Ex: int*a=(int*)calloc(n,sizeof(int));
Spre deosebire de malloc, fincția calloc inițializează toți octeții zonei de memorie alocate
dinamic cu valoarea 0. În consecință un apel calloc este mai lent decâ t un apel malloc echivalent.
3. realloc(void*,int)
Funcția realloc realocă memoria de la adresa primită în primul parametru la o altă adresă. Noua
locație de memorie va avea lungimea în octeși specificată de al doilea parametru. Dacă alocarea
este cu succes pentru noua locație informația de la adresa dată în primul parametru este copiată
la noua adresă .
int n, * a; * nu vine lipit de a
a=(int*)malloc(n*sizeof(int));
…………………………………………..
n*=2;
a=(int*)realloc(a,n*sizeof(int));
……………………………………………
Dacă lungimea noii zone de memorie este mai mică atunci de la adrsa inițială se copiază exact
atâ ția octeți câ ți am specificat în al doilea parametru.
4.Funcția free(void*)
Funcția free eliberează zona de memorie alocată dinamic de la adresa primită ca parametru.
Observație: Cu free putem elibera numai o zonă de memorie alocată anterior cu succes cu un
apel malloc, calloc sau realloc.
Dacă se încearcă a se aloca dinamic memorie de lungime negativă funcția returnează valoarea
NULL. Dacă se încearcă a se aloca 0 octeți în funcție de compilator funcția va returna valoarea
NULL sau o adresă de memorie unde evident nu avem că suțe alocate.
ex:
int a[10];
int n=10;
int* b=(int*)malloc(n*sizeof(int));
printf(“%d %d”,sizeof(a),sizeof(b)); //40_4
free(b);
a reține adresa de memorie a unei zone de lungime 4x10 octeți în stiva de execuție, iar b este un
pointer că tre int și orice pointer se reprezintă pe 4 octeți (sizeof(b)=4).
Cur FP 6

Memory leak

În momentul în care alocă m dinamic memorie și o zonă astfel alocată nu este eliberată spunem
că avem „memory leak”.
Dezavantajele memory leak:
 Zonele alocate dinamic și neeliberate pe parcursul execuției aplicației pot crește ca nr. și
ca dimensiune existâ nd riscul ca execuția aplicației să nu mai poată continua,
nemaiexistâ nd la un moment dat memorie pentru a fi alocată dinamic
 Prin acumularea zonelor neeliberate calculatorului i-se va îngreuna funcționalitatea
 La închiderea unei aplicații cu memory leak sistemul de operare va identifica și elibera
zonele de memorie alocate dinamic neeliberate pe parcursul execuției, proces care este
lent sau extrem de lent

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