17 pointeri

2
17. Pointeri Un pointer este o variabilă a cărei valoare este adresa de memorie a unei variabile de tip valoare. Operatorul & returnează adresa unei variabile. Operatorul * este utilizat pentru a declara o variabilă de tip pointer, dar şi pentru a o de-referenţia. Dacă pointerul referă o structură, câmpurile (publice) se pot accesa cu *. sau cu ->. Pentru a împiedica CLR-ul să gestioneze memoria care este accesată direct prin intermediul pointerilor, operatorii pe pointeri se pot utiliza doar în contexte nesigure; din acest motiv, cuvântul cheie unsafe trebuie utilizat atât la definirea unei metode ce utilizează pointeri, cât şi la apelul acesteia. Suplimentar, trebuie utilizată opţiunea de compilare /unsafe. using System; namespace pnoro{ class Aplicatie{ unsafe static void Swap(int* p1, int* p2){ int aux = *p1 ; *p1 = *p2 ; *p2 = aux; } public static void Main(){ int i=0; int j=1; unsafe { Swap(&i ,&j );} Console.WriteLine("i={0} \t j={1}", i,j); Console.ReadLine(); } }; } În cursul execuţiei unei aplicaţii se poate declanşa colectorul de resurse, iar acesta defragmentează memoria heap. Acesta poate conduce la mutarea unor obiecte dintr-o zonă de memorie într-alta (evident, nu poate fi vorba decât de instanţe ale tipurilor referinţă, căci instanţele tipurilor valoare sunt alocate pe stivă). Se poate ajunge astfel la invalidarea unor pointeri. Cuvântul cheie fixed poate fi utilizat doar în contexte nesigure şi specifică faptul că un obiect nu poate fi mutat la o altă adresă de memorie în timpul defragmentării heap-ului. Încercarea de a utiliza fixed cu instanţe ale tipurilor valoare conduce la eroare de compilare. Observaţie: Nu se poate obţine adresa unei variabile de tip referinţă, dar se poate obţine adresa unui câmp de un tip valoare dintr-o instanţă de un tip referinţă!

Transcript of 17 pointeri

Page 1: 17 pointeri

17. Pointeri Un pointer este o variabilă a cărei valoare este adresa de memorie a unei

variabile de tip valoare.

Operatorul & returnează adresa unei variabile. Operatorul * este utilizat pentru

a declara o variabilă de tip pointer, dar şi pentru a o de-referenţia. Dacă pointerul

referă o structură, câmpurile (publice) se pot accesa cu *. sau cu ->.

Pentru a împiedica CLR-ul să gestioneze memoria care este accesată direct prin

intermediul pointerilor, operatorii pe pointeri se pot utiliza doar în contexte nesigure;

din acest motiv, cuvântul cheie unsafe trebuie utilizat atât la definirea unei metode ce

utilizează pointeri, cât şi la apelul acesteia. Suplimentar, trebuie utilizată opţiunea de

compilare /unsafe. using System; namespace pnoro{ class Aplicatie{ unsafe static void Swap(int* p1, int* p2){ int aux = *p1; *p1 = *p2; *p2 = aux; } public static void Main(){ int i=0; int j=1; unsafe{ Swap(&i,&j);} Console.WriteLine("i={0} \t j={1}", i,j); Console.ReadLine(); } }; } În cursul execuţiei unei aplicaţii se poate declanşa colectorul de resurse, iar

acesta defragmentează memoria heap. Acesta poate conduce la mutarea unor obiecte

dintr-o zonă de memorie într-alta (evident, nu poate fi vorba decât de instanţe ale

tipurilor referinţă, căci instanţele tipurilor valoare sunt alocate pe stivă). Se poate

ajunge astfel la invalidarea unor pointeri. Cuvântul cheie fixed poate fi utilizat doar în

contexte nesigure şi specifică faptul că un obiect nu poate fi mutat la o altă adresă de

memorie în timpul defragmentării heap-ului. Încercarea de a utiliza fixed cu instanţe

ale tipurilor valoare conduce la eroare de compilare.

Observaţie:

Nu se poate obţine adresa unei variabile de tip referinţă, dar se poate obţine

adresa unui câmp de un tip valoare dintr-o instanţă de un tip referinţă!

Page 2: 17 pointeri

2

using System; namespace pnoro{ class C{ public int i; public C(int i){this.i=i;} }; class Aplicatie{ unsafe static void Swap(int* p1, int* p2){ int aux = *p1; *p1 = *p2; *p2 = aux; } public static void Main(){ C v1 = new C(10); C v2 = new C(20); unsafe{ fixed (int* p1= &v1.i, p2 = &v2.i){ //obiectele sunt “fixate” doar in interiorul blocului //delimitat de fixed Swap(p1,p2); } } Console.WriteLine("v1.i={0}\tv2.i={1}", v1.i,v2.i); Console.ReadLine(); } }; } Tablourile sunt tipuri referinţă, pentru care se alocă memorie din heap; dacă

componentele tabloului sunt tipuri valoare, numele tabloului este pointer la prima

componentă şi poate fi atribuit unei variabile de tipul pointer corespunzător. Ca şi în

C++, se poate utiliza arimetica pe pointeri pentru a parcurge elementele tabloului;

este însă responsabilitatea programatorului să facă această operaţie sigură (să nu

acceseze elemente dincolo de graniţele tabloului). De asemenea, adresa tabloului

trebui fixată pentru a preveni invalidarea pointerilor de către o operaţie de

defragmentare.

Pentru a evita “fixarea” unui tablou, se poate aloca pe stivă, cu stackalloc, un

bloc de memorie capabil să conţină un număr de elemente de un tip precizat;

elementele nu pot fi iniţializate şi li se atribuie , separat, valori: unsafe{ int* pt = stackalloc int[3]; pt[0] = 10; pt[1] = 20; pt[2] = 30; ... }