Presentation is loading. Please wait.

Presentation is loading. Please wait.

CURS 7 Pointeri tipuri speciale de variabile sau constante care au ca valori adrese ale unor alte variabile sau constante (adrese ale unor locaţii de memorie)

Similar presentations


Presentation on theme: "CURS 7 Pointeri tipuri speciale de variabile sau constante care au ca valori adrese ale unor alte variabile sau constante (adrese ale unor locaţii de memorie)"— Presentation transcript:

1 CURS 7 Pointeri tipuri speciale de variabile sau constante care au ca valori adrese ale unor alte variabile sau constante (adrese ale unor locaţii de memorie) permit calcule cu adrese specifice limbajelor de asamblare sunt folosiţi în scopul scrierii unor programe mai eficiente atât din punctul de vedere al timpului de execuţie cât şi din punctul de vedere al utilizării resurselor hard, în mod concret al utilizării memoriei computerelor. sunt în mod special utili la alocarea dinamică a memoriei şi la apelul prin referinţă.

2 Pointerii păstrează adresa începutului locaţiei în care este stocată o anumită valoare. pachet compus din două părţi: pointerul însuşi care are ca valoare adresa primului octet al locaţiei de memorie în care este stocată o variabilă (sau constantă) tipul valorii stocate în locaţia de memorie la începutul căreia pointează spune computerului câtă memorie să citească după adresa la care pointează şi cum să o interpreteze

3 Limbajul C foloseşte pointerii în trei moduri:
a) pentru a crea structuri dinamice de date construite din blocuri de memorie b) pentru a opera cu parametrii pasaţi funcţiilor la apelul acestora c) pentru a accesa informaţia stocată în tablouri În cazul unui pointer la o funcţie, tipul pointerului va fi tipul de dată returnat de către funcţie, iar valoarea sa va fi adresa la care începe codul funcţiei respective Pentru lucrul cu pointeri, limbajul C oferă doi operatori: & - &x înseamnă adresa variabilei x (de fapt adresa primului octet al locaţiei de memorie în care este stocată variabila x) * *p1 valoarea stocată în locaţie de memorie la care pointează pointerul p1.

4 Declararea şi iniţializarea pointerilor
tip *nume_pointer; sau tip* nume_pointer; tip tip de date de bază sau tip utilizator nume_pointer identificator folosit pentru pointerul care se declară Exemple float *pf; //pf poate conţine adrese la care se află memorate date de tip float int *pi; //pi poate conţine adrese la care se află memorate date de tip int char* pc; //pc poate conţine adrese la care se află memorate date de tip char struct agenda { char nume[20]; char tel[15]; }; struct agenda *psa; //psa este un pointer la date de tip structură agenda.

5 precizarea adresei unui obiect definit în memorie.
Iniţializare precizarea adresei unui obiect definit în memorie. p - numele unui pointer => *p reprezintă valoarea de la adresa la care "pointează" pointerul p. Exemple double a, *pd; a=8.406; pd=&a; int n=1, m=2, s[10]; int *pi; // pi este un pointer la tipul întreg pi = &n; // pi pointează acum la n m = *pi; // m are valoarea de la adresa lui n, adică 1 *pi = 0; // n are acum valoarea 0 pi = &s[0]; // pi pointează acum la s[0], adică are ca // valoare adresa elementului s[0] *pi=5*m; // s[0] are acum valoarea 5*1=5 float pi, *p; p=π *p= ; // se atribuie lui pi valoarea int* p1, p2, p3; //numai p1 este pointer float *pf1, fact(int *); // se declară pointerul pf1 la tipul float şi o funcţie fact care returnează o valoare de tip float şi care are ca argument un pointer la tipul int. Un pointer este constrâns să pointeze la un anumit tip de date!!!

6 Atenţie la iniţializarea pointerilor !!! + referinta nevalida
Program exemplu #include <stdio.h> #include <math.h> int main() { float a,b; float* p; p = &a; *p=4*atan(1.0); b=2*a; printf("a=%f b=%f",a,b); printf("\nValoarea din locatia de memorie la care pointeaza p este %f \nAdresa lui a: %X", *p, p); return 0; } Atenţie la iniţializarea pointerilor !!! + referinta nevalida + pointeri nuli Exemplu //testare pointer  int* pi=0; ... if(pi!=0) n=*pi; //se foloseşte pointerul dacă pointează la o adresă legală (validă)

7 #include <stdio.h>
#include <math.h> void main() { int* pi=NULL; int n; scanf("%d",&n); if(n<10) pi=&n; if(pi) printf("dublul lui n este %d",2*(*pi)); printf("\nAdresa lui n este %X",pi); } else printf("Adresa nevalida: \\x%X",pi);

8 Operaţii cu pointeri a) Incrementare şi decrementare Fie declaraţia:
int *p; Instrucţiunile: ++p; şi p++; respectiv: --p; şi p--; măresc, respectiv micşorează valoarea lui p cu o unitate (4 octeti) b) Adunarea şi scăderea unui întreg dintr-un pointer Rezultatul operaţiei p+n, unde p este un pointer şi n este un întreg este: p+n·r, unde r reprezintă numărul de octeţi folosiţi pentru păstrarea în memorie a datelor de tipul celor spre care pointează p. Exemplu Fie declaraţiile: int n,*pin=&n; float x,*pre=&x; Dacă pin are valoarea 1BBC, expresia pin+3 va avea valoarea 1BBC+6, adică 1BC2. Dacă pre are valoarea 1BB6, atunci expresia pre-5 va avea valoarea 1BB6-20, adică 1BA2.

9 c) Scăderea pointerilor Adunarea pointerilor nu este permisa!!!
pmed=(pin+pfin)/2; //  Invalid pointer addition pmed=pin+(pfin-pin)/2; este o instructiune corecta (la pin se adauga un intreg) int num , *ptr1 ,*ptr2 ; num=ptr1-ptr2; // rezultatul este un intreg, egal cu numarul de obiecte (locatii de memorie) dintre valorile pointerilor d) Compararea pointerilor Comparaţiile logice !=, ==, <, <=, >, >= sunt valabile şi în cazul pointerilor. Exemplu // functie pentru determinarea lungimii unui sir de caractere int lsir(char *pc) { int i; for(i=0;*pc!=NULL;pc++) i++; return i; } int main() { char sir[50]; gets(sir); printf(“Lungimea sirului este %d”,lsir(sir)); return 0; }

10 Pointeri şi tablouri Pointerii sunt intim legaţi de tablouri
- numele unui tablou este un pointer constant care are ca valoare adresa elementului de index 0 al tabloului respectiv. - orice operaţie care se face folosind indicii tablourilor poate fi făcută, chiar mai rapid, prin folosirea pointerilor. Exemple char text[10]="Anul1Fizica", *pc; pc=text; putchar(*pc); //se va tipări caracterul A pc+=4; putchar(*pc); //se va tipări caracterul 1 2. char sir[10]="BorlandC"; char *p; p=sir; while(*p) putchar(*p++); //se va tipări sirul BorlandC 3. double a[15],t; t=*(a+3); //este echivalent cu t=a[3];

11 Program exemplu: adunarea elementelor unui şir folosind pointeri
#include <stdio.h> #include<conio.h> #include <stdlib.h> #include <math.h> int main() { float x[100], *y,v; double s=0.0,med; int i; //genereaza aleator elementele sirului x for(i=0;i<100;i++) v=rand()/pow(2,15); x[i]=1000*v-500; //printf("%5.3f\t",x[i]); } //se aduna elementele sirului x; pointerul y a fost initializat cu adresa //primului element al sirului x for(y=x;y!=&x[100];) s+=*y++; med=s/100; printf("\ns= %lg\tmedia= %lg",s,med); getche(); return 0;

12 Construcţiile &a[i] şi a+i sunt de asemenea identice.
Exemplu Iniţializarea elementelor unui tablou fără pointeri şi cu pointeri fără pointeri: #define DIM 50 int x[DIM],i; for(i=0;i<DIM;i++) x[i]=0; cu pointeri: #define DIM 50 int x[DIM], *pi; for(pi=x;pi<&x[DIM];pi++) *pi=0; În primul caz, pentru aflarea adresei elementului x[i] compilatorul generează un cod care înmulţeşte pe i cu dimensiunea unui element al tabloului. În al doilea caz (varianta cu pointeri), compilatorul evaluează o singură dată indicele şirului, salvând astfel 49 de operaţii de multiplicare. Referirea la elementul unui tablou sub forma a[i] este identică cu *(a+i). Construcţiile &a[i] şi a+i sunt de asemenea identice. Echivalenţa v[2] cu *(v+2)

13 Apelul prin referinţă utilizând parametri de tip pointer
Apelul funcţiilor prin valoare funcţiei i se transmite valoarea argumentului Apel: f(x) Antet: void f(int x) void printsir(float sir[], int dim) { int i; for (i=0; i<dim; i++) printf("%f\n",sir[i]); } prin referinţă funcţiei i se transmite adresa argumentului Apel: g(&x) Antet: void g(int *pi) void printsir(float *p,int dim) { int i; for (i=0; i<dim; i++) printf("%f\n",*p++); }

14 Program exemplu: ordonarea unui şir folosind pointeri şi funcţie care returnează un pointer la şirul ordonat #include <stdio.h> void printsir(float *p, int dim) { int i; for (i=0; i<dim; i++) printf("%f\n",*p++); } float* ordsir(float *p0, int dim) float *p=p0,t; int k,i; do k=1; p=p0; while(p<(p0+dim-1)) //p0+dim-1 are ca valoare adresa ultimului element if(*p<*(p+1)) t=*p; *p=*(p+1); *(p+1)=t; k=0; p++; while(k==0); return p-dim+1; int main() { float x[100],*p; int n,i; printf("Dimensiunea sirului: "); scanf("%d",&n); for(i=0;i<n;i++) printf("x[%d]= ",i); scanf("%f",&x[i]); } p=x; p=ordsir(p,n); printsir(p,n); return 0;

15 sc2 schimba valorile variabilelor din functia apelanta.
Program exemplu: funcţii swap cu apel prin valoare şi prin referinţă #include <stdio.h> void sc1(double v1, double v2) { double t; t=v1;v1=v2;v2=t; } void sc2(double *i, double *j) t=*i;*i=*j;*j=t; int main() double a,b; printf("Adresa la care incepe codul functiei sc1 este: %X\n",sc1); scanf("%lf%lf",&a,&b); sc1(a,b); printf("\nApelul functiei sc1:\na= %lg\tb=%lg",a,b); sc2(&a,&b); printf("\nApelul functiei sc2:\na= %lg\tb=%lg",a,b); return 0; sc1 nu interschimbă valorile variabilelor din funcţia apelantă ci numai copii ale acestora! sc2 schimba valorile variabilelor din functia apelanta.

16 Pointeri la funcţii Exerciţiu
Să se scrie o funcţie care să returneze 1 dacă se citeşte un număr de la tastatură şi să returneze 0 în caz contrar. Vezi funcţia getint din B.W. Kernighan and D.M. Ritchie, The C Programming Language, pag. 81 Pointeri la funcţii numele unei funcţii este un pointer la funcţia respectivă numele funcţiei este o reprezentare în mod intern a adresei la care începe codul funcţiei se utilizează pentru transmiterea funcţiilor ca parametri ai altor funcţii. Exemplu Dacă dorim ca funcţia f să apeleze funcţia g sub forma f(g), funcţia g având antetul: float g(int x) atunci antetul lui f trebuie să fie de forma: double f (float (*) (int))

17 Exemplu //Funcţia bisect are ca parametru o altă funcţie f //======================= Functia f ========================= double f(double x) { return x-sqrt(2); } //======================Functia bisect ======================= double bisect(double inf, double sup, double (*pf)(double)) double c,sol; if((*pf)(inf)==0) return inf; if((*pf)(sup)==0) return sup; if((*pf)(inf)*(*pf)(sup)>0) printf("\n\a\aNu exista sol. sau exista sol. multiple"); getch(); exit(1); do c=(inf+sup)/2.0; if((*pf)(c)==0) return c; if((*pf)(inf)*(*pf)(c)<0) sup=c; else inf=c; while(fabs((*pf)(c)) >= eps); return c; //=================Apelul functiei bisect======================= s=bisect(A,B,f);

18 Structuri de date dinamice în C
structuri care îşi modifică dimensiunea prin alocarea şi eliberarea (dealocarea) memoriei dintr-o zonă specială de memorie numită "heap“ permit programatorului să controleze exact consumul de memorie al unui program. managementul structurilor dinamice se face folosind pointeri => o utilizare eficientă a memoriei Memoria heap este o zonă aparte de memorie corespunzătoare unui program, folosită pentru crearea şi distrugerea structurilor de date care au timp de viaţă limitat. Memoria heap - zonă de memorie complet separată, controlată de către un manager de memorie de tip "run-time", care face managementul memoriei în timpul execuţiei programului. - este disponibilă programelor de aplicaţii în timpul execuţiei acestora folosind funcţiile malloc şi free.

19 Memoria stack (stiva) stocheaza variabile temporare (locale) create de catre functii variabilele din stack dispar la iesirea din functie este limitata => “stack overflow” managementul ei este facut de catre CPU acces foarte rapid Memoria heap - variabilele pot fi accesate global, de catre orice functie - trebuie facut managementul ei (altfel => “memory leak”) - se acceseaza folosind pointeri nu este limitata d.p.d.v. al numarului de date stocate (evident, e limitata fizic) accesul este mai putin rapid

20 Funcţia malloc - prototipul în <stdlib.h> şi în <alloc.h> - alocă o zonă contiguă de memorie şi este de forma: (void *) malloc(dimensiune) dimensiune - mărimea blocului de memorie alocat în octeţi. - returnează un pointer la primul octet al primei locaţii a blocului de memorie alocat - in caz de eroare, sau daca dimensiune este egală cu zero, returnează pointerul NULL. Funcţia free - eliberează un bloc de memorie alocat cu funcţia malloc - apelul acesteia se face cu un parametru care reprezintă pointerul la originea blocului de memorie care se eliberează.

21 Program exemplu: folosirea funcţiilor malloc şi free
//Se aloca dinamic un tablou de n elemente; #include<stdio.h> #include<stdlib.h> int main() { int n,i; float *p,*p0; printf("Introduceti dimensiunea tabloului: "); scanf("%d",&n); p=(float *)malloc(n*sizeof(float)); //(float *) converteste pointerul void //returnat de catre malloc intr-un pointer la tipul float p0=p; if (p==NULL) printf("Eroare: Memorie nedisponibila\n"); exit(1); } for(i=0;i<n;i++) *p=i; printf("\n%X\t%g",p,*p); p++; free(p0); return 0; Exerciţiu Scrieţi un program care să aloce un bloc de memorie capabil să stocheze 10 valori de tip long double, să iniţializeze fiecare dintre aceste valori cu 0.0 şi apoi să elibereze blocul respectiv de memorie.


Download ppt "CURS 7 Pointeri tipuri speciale de variabile sau constante care au ca valori adrese ale unor alte variabile sau constante (adrese ale unor locaţii de memorie)"

Similar presentations


Ads by Google