Mutatóval kapcsolatos operátorok – a változók címe, a dereferencia tárolási helyei és a memóriahelyek elérése

A mutató operátorai lehetővé teszik a változók címét (&), a mutató elhalasztását (*), a mutatóértékek összehasonlítását, valamint a mutatók és egész számok hozzáadását vagy kivonását.

A következő operátorokkal dolgozhat a mutatókkal:

A mutatótípusokról további információt a Mutatótípusok című témakörben talál.

Feljegyzés

A mutatókkal végzett műveletekhez nem biztonságos környezet szükséges. A nem biztonságos blokkokat tartalmazó kódot az AllowUnsafeBlocks fordítóbeállítással kell lefordítani.

Operátor címe >

A unary & operátor az operandus címét adja vissza:

unsafe
{
    int number = 27;
    int* pointerToNumber = &number;

    Console.WriteLine($"Value of the variable: {number}");
    Console.WriteLine($"Address of the variable: {(long)pointerToNumber:X}");
}
// Output is similar to:
// Value of the variable: 27
// Address of the variable: 6C1457DBD4

Az operátor operandusának & rögzített változónak kell lennie. A rögzített változók olyan változók, amelyek olyan tárolóhelyeken találhatók, amelyeket a szemétgyűjtő működése nem érint. Az előző példában a helyi változó number rögzített változó, mert a veremen található. A szemétgyűjtő által érinthető (például áthelyezett) tárolóhelyeken található változókat mozgatható változóknak nevezzük. Az objektummezők és a tömbelemek ingó változókra mutatnak példákat. Egy ingó változó címét lekérheti, ha "kijavítja", vagy "kitűzi" egy fixed utasítással. A kapott cím csak az utasításblokkon fixed belül érvényes. Az alábbi példa egy utasítás és az & operátor használatát fixed mutatja be:

unsafe
{
    byte[] bytes = { 1, 2, 3 };
    fixed (byte* pointerToFirst = &bytes[0])
    {
        // The address stored in pointerToFirst
        // is valid only inside this fixed statement block.
    }
}

Állandó vagy érték címét nem lehet lekérni.

A rögzített és mozgatható változókkal kapcsolatos további információkért lásd a C# nyelvspecifikáció Rögzített és mozgatható változók szakaszát.

A bináris & operátor kiszámítja a logikai és logikai operandusok és a bitenkénti logikai ÉS az integrál operandusok logikai ÉS logikai számításait.

Mutató indirekt operátora *

A nem mutató indirekt operátor * beolvasja azt a változót, amelyre az operandusa rámutat. Dereference operátornak is nevezik. Az operátor operandusának * mutató típusúnak kell lennie.

unsafe
{
    char letter = 'A';
    char* pointerToLetter = &letter;
    Console.WriteLine($"Value of the `letter` variable: {letter}");
    Console.WriteLine($"Address of the `letter` variable: {(long)pointerToLetter:X}");

    *pointerToLetter = 'Z';
    Console.WriteLine($"Value of the `letter` variable after update: {letter}");
}
// Output is similar to:
// Value of the `letter` variable: A
// Address of the `letter` variable: DCB977DDF4
// Value of the `letter` variable after update: Z

Az operátor nem alkalmazható * típuskifejezésre void*.

A bináris * operátor kiszámítja a numerikus operandusok szorzatát .

Mutatótag-hozzáférési operátor –>

Az -> operátor egyesíti a mutató indirekt ésa tagok hozzáférését. Vagyis ha x egy mutató típusú T* , és y a típus Takadálymentes tagja, akkor az űrlap kifejezése

x->y

egyenértékű a

(*x).y

Az alábbi példa az operátor használatát -> mutatja be:

public struct Coords
{
    public int X;
    public int Y;
    public override string ToString() => $"({X}, {Y})";
}

public class PointerMemberAccessExample
{
    public static unsafe void Main()
    {
        Coords coords;
        Coords* p = &coords;
        p->X = 3;
        p->Y = 4;
        Console.WriteLine(p->ToString());  // output: (3, 4)
    }
}

Az operátor nem alkalmazható -> típuskifejezésre void*.

Mutatóelem-hozzáférési operátor []

Egy mutató típusú kifejezés p esetében az űrlap p[n] mutatóelem-hozzáférését a rendszer a következőképpen értékeli ki*(p + n), ahol n implicit módon átalakíthatónak intkell lennie , uintlongvagy ulong. A mutatókkal rendelkező operátor viselkedésével + kapcsolatos információkért tekintse meg az integrálértékek összeadását vagy kivonását egy mutatószakaszba vagy abból.

Az alábbi példa bemutatja, hogyan érheti el a tömbelemeket egy mutatóval és az [] operátorral:

unsafe
{
    char* pointerToChars = stackalloc char[123];

    for (int i = 65; i < 123; i++)
    {
        pointerToChars[i] = (char)i;
    }

    Console.Write("Uppercase letters: ");
    for (int i = 65; i < 91; i++)
    {
        Console.Write(pointerToChars[i]);
    }
}
// Output:
// Uppercase letters: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Az előző példában egy stackalloc kifejezés lefoglal egy memóriablokkot a veremen.

Feljegyzés

A mutatóelem hozzáférési operátora nem ellenőrzi a határtalan hibákat.

Nem használható [] mutatóelem-hozzáféréshez típuskifejezéssel void*.

Az operátort [] tömbelemhez vagy indexelőhöz is használhatja.

Mutató aritmetikai operátorai

A következő aritmetikai műveleteket hajthatja végre mutatókkal:

  • Integrálérték hozzáadása vagy kivonása mutatóhoz vagy mutatóból
  • Két mutató kivonása
  • Mutató növelése vagy csökkentése

Ezeket a műveleteket nem lehet ilyen típusú void*mutatókkal végrehajtani.

A numerikus típusokkal végzett támogatott aritmetikai műveletekről további információt az Aritmetikai operátorok című témakörben talál.

Egy integrálérték hozzáadása vagy kivonása egy mutatóhoz vagy abból

Egy típusmutató pT* és egy implicit módon átalakítható inttípus kifejezése n esetén az uintlongulongösszeadás és kivonás az alábbiak szerint van definiálva:

  • Mind a n + p kifejezések, mind p + n a kifejezések olyan típusú T* mutatót hoznak létre, amely a megadott pcímhez való hozzáadásból n * sizeof(T) ered.
  • A p - n kifejezés olyan típusú T* mutatót n * sizeof(T) hoz létre, amely a megadott címből pvaló kivonásból ered.

Az sizeof operátor bájtban szerzi be egy típus méretét.

Az alábbi példa egy mutatóval szemlélteti az + operátor használatát:

unsafe
{
    const int Count = 3;
    int[] numbers = new int[Count] { 10, 20, 30 };
    fixed (int* pointerToFirst = &numbers[0])
    {
        int* pointerToLast = pointerToFirst + (Count - 1);

        Console.WriteLine($"Value {*pointerToFirst} at address {(long)pointerToFirst}");
        Console.WriteLine($"Value {*pointerToLast} at address {(long)pointerToLast}");
    }
}
// Output is similar to:
// Value 10 at address 1818345918136
// Value 30 at address 1818345918144

Mutató kivonása

Két mutató p1 és p2 típus T*esetén a kifejezés p1 - p2 a megadott és p2 a osztva sizeof(T)megadott címek p1 közötti különbséget hozza létre. Az eredmény típusa: long. Vagyis p1 - p2 a számítás a ((long)(p1) - (long)(p2)) / sizeof(T)következőképpen történik: .

Az alábbi példa a mutató kivonását mutatja be:

unsafe
{
    int* numbers = stackalloc int[] { 0, 1, 2, 3, 4, 5 };
    int* p1 = &numbers[1];
    int* p2 = &numbers[5];
    Console.WriteLine(p2 - p1);  // output: 4
}

Mutató növekménye és csökkentése

A ++ növekmény operátor 1-et ad hozzá a mutató operandusához. A -- decrement operátor kivon 1-et a mutató operandusából.

Mindkét operátor két formában támogatott: postfix (p++ és p--) és előtag (++p és --p). A művelet eredménye p++ és p-- értékep. A művelet eredménye ++p és --p értékep.

Az alábbi példa a postfix és az előtag növekményes operátorainak viselkedését mutatja be:

unsafe
{
    int* numbers = stackalloc int[] { 0, 1, 2 };
    int* p1 = &numbers[0];
    int* p2 = p1;
    Console.WriteLine($"Before operation: p1 - {(long)p1}, p2 - {(long)p2}");
    Console.WriteLine($"Postfix increment of p1: {(long)(p1++)}");
    Console.WriteLine($"Prefix increment of p2: {(long)(++p2)}");
    Console.WriteLine($"After operation: p1 - {(long)p1}, p2 - {(long)p2}");
}
// Output is similar to
// Before operation: p1 - 816489946512, p2 - 816489946512
// Postfix increment of p1: 816489946512
// Prefix increment of p2: 816489946516
// After operation: p1 - 816489946516, p2 - 816489946516

Mutató-összehasonlító operátorok

A ==, , !=, <<=>, és >= operátorokkal bármilyen mutatótípusú operandusokat összehasonlíthat, beleértve a elemet is.void* Ezek az operátorok úgy hasonlítják össze a két operandus által megadott címeket, mintha alá nem írt egész számok lennének.

Az operátorok más típusú operandusok viselkedéséről az Egyenlőség operátorok és az Összehasonlító operátorok című cikkekben olvashat bővebben.

Operátorok műveleti sorrendje

Az alábbi lista a mutatóval kapcsolatos operátorokat a legmagasabb prioritástól a legalacsonyabbig rendeli:

  • A postfix növekményes x++ és decrement x-- operátorai, valamint az és [] az -> operátorok
  • Az előtag növekményes ++x és decrement --x operátorai, valamint az és * az & operátorok
  • Additív + és - operátorok
  • Összehasonlítás <, >, <=és >= operátorok
  • Egyenlőség == és != operátorok

Zárójelek ()használatával módosíthatja az operátorok elsőbbsége által előírt kiértékelési sorrendet.

A C#-operátorok elsőbbségi szint szerint rendezett teljes listájáért tekintse meg a C# operátorok cikkének Operátorok elsőbbsége című szakaszát.

Operátorok túlterhelése

A felhasználó által definiált típus nem terhelheti túl a mutatóval kapcsolatos operátorokat &, *és ->[].

C# nyelvspecifikáció

További információt a C# nyelvspecifikációjának alábbi szakaszaiban talál:

Lásd még