MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Pointeri

Dacă ați programat în C/C++, este posibil să fiți familiarizat cu conceptul de pointeri. Pointerii permit accesul la o anumită locație din memorie și efectuarea unor operațiuni asupra valorii stocate în acea locație.

În limbajul C#, pointerii sunt folosiți rar, dar în anumite cazuri pot fi utilizați pentru optimizarea aplicațiilor. Codul care folosește pointeri este numit cod nesigur (unsafe).

Totuși, acest lucru nu înseamnă că prezintă un pericol. Pur și simplu, atunci când lucrăm cu acest tip de cod, toate acțiunile legate de utilizarea memoriei, inclusiv eliberarea ei, revin în totalitate programatorului, nu mediului CLR. Din punctul de vedere al CLR, acest cod nu este sigur, deoarece mediul nu poate verifica acest cod, ceea ce crește probabilitatea de erori de diverse tipuri.

Pentru a utiliza cod nesigur în C#, trebuie să specificăm proiectului că va lucra cu cod nesigur. Pentru aceasta, trebuie să activăm setarea corespunzătoare în setările proiectului - din meniul Project (Proiect) selectăm Properties (Proprietăți). Apoi, în meniul Build, bifăm caseta Unsafe code (Cod nesigur):

Cuvântul cheie unsafe

Un bloc de cod sau o metodă care utilizează pointeri este marcată cu cuvântul cheie unsafe:

// bloc de cod care utilizează pointeri
unsafe
{
   
}

Metodă care folosește pointeri:

unsafe void Test()
{

}

De asemenea, cu ajutorul unsafe putem declara structuri și clase:

unsafe struct State
{

}

unsafe class Person
{

}

Operațiile * și &

Operația centrală în lucrul cu pointerii este operația *, numită și operație de dereferențiere. Operația de dereferențiere permite obținerea sau setarea valorii la adresa indicată de pointer. Pentru a obține adresa unei variabile, se folosește operația &:

unsafe
{
   int* x; // definirea unui pointer
   int y = 10; // definim o variabilă

   x = &y; // pointerul x acum indică adresa variabilei y
   Console.WriteLine(*x); // 10

   y = y + 20;     // schimbăm valoarea
   Console.WriteLine(*x); // 30

   *x = 50;
   Console.WriteLine(y); // variabila y=50
}

La declararea unui pointer, indicăm tipul: int* x; - în acest caz, se declară un pointer către un număr întreg. Dar, pe lângă tipul int, se pot folosi și altele: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal sau bool. De asemenea, se pot declara pointeri către tipuri enum, structuri și alți pointeri.

Expresia x = &y; ne permite să obținem adresa variabilei y și să setăm pointerul x la acea adresă. Înainte de aceasta, pointerul x nu indica nimic.

După aceasta, toate operațiile asupra lui y vor afecta valoarea obținută prin pointerul x și invers, deoarece ambele indică aceeași zonă din memorie.

Pentru a obține valoarea stocată în zona de memorie la care indică pointerul x, se folosește expresia *x.

Obținerea adresei

Folosind conversia pointerului într-un tip numeric întreg, putem obține adresa din memorie la care indică pointerul:

int* x; // definirea unui pointer
int y = 10; // definim o variabilă

x = &y; // pointerul x acum indică adresa variabilei y

// obținem adresa variabilei y
ulong addr = (ulong)x;
Console.WriteLine($"Adresa variabilei y: {addr}");

Pentru a obține adresa, se folosește conversia într-un tip uint, long sau ulong. Deoarece valoarea unei adrese este un număr întreg, iar pe sistemele pe 32 de biți, intervalul de adrese este de la 0 la 4.000.000.000, adresa poate fi stocată într-o variabilă de tip uint/int.

Pe sistemele pe 64 de biți, intervalul adreselor disponibile este mult mai mare, deci în acest caz este mai bine să se folosească ulong pentru a evita eroarea de depășire.

Pointer către alt pointer

Declarația și utilizarea unui pointer către alt pointer:

unsafe
{
   int* x; // definirea unui pointer
   int y = 10; // definim o variabilă

   x = &y; // pointerul x acum indică adresa variabilei y
   int z = &x; // pointerul z acum indică adresa pointerului x
   z = z + 40; // schimbarea pointerului z va duce la schimbarea variabilei y
   Console.WriteLine(y); // variabila y=50
   Console.WriteLine(z); // variabila z=50
}

Acest cod ilustrează cum pointerul z, care indică adresa pointerului x, poate fi folosit pentru a modifica valoarea la care indică x, afectând astfel și valoarea variabilei y.

← Lecția anterioară Lecția următoare →