Megosztás:


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 C# nyelv referenciadokumentuma a C# nyelv legújabb kiadású verzióját ismerteti. Emellett a közelgő nyelvi kiadás nyilvános előzetes verziójú funkcióinak kezdeti dokumentációját is tartalmazza.

A dokumentáció azonosítja azokat a funkciókat, amelyeket először a nyelv utolsó három verziójában vagy az aktuális nyilvános előzetes verziókban vezetnek be.

Jótanács

Ha meg szeretné tudni, hogy mikor jelent meg először egy funkció a C#-ban, tekintse meg a C# nyelvi verzióelőzményeiről szóló cikket.

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ítania.

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, amelyekre a szemétgyűjtő nincs hatással. 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 befolyásolható (például áthelyezési) tárolási 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 egy utasítássalfixed lekérheti, ha "kijavítja", vagy "kitűzi". 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 fixed operátor használatát & 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 * hozzáfér ahhoz a változóhoz, amelyhez 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. Ha x egy mutató típusú T* , és y a típus Takadálymentes tagja, 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 használható -> típuskifejezésen 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ése a következőképpen lesz kiértékelve *(p + n). Az értéknek n implicit módon átalakíthatónak intkell lennie , uintvagy longulong. 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ó és egy [] operátor használatával:

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 az Aritmetikai operátorok című témakörben olvashat bővebben.

Integrálérték hozzáadása vagy kivonása mutatóhoz vagy mutatóból

Egy típusmutató pT* és egy implicit módon átalakítható inttípus kifejezése n esetén az uintlongulongalábbiak szerint lehet összeadási és kivonási munkát végezni:

  • Mindkettőt p + n , és n + p adjon meg egy ilyen típusú T*mutatót. Ezt a mutatót úgy érheti el, hogy hozzáadja n * sizeof(T) azt a címet, amely p a mutatóra mutat.
  • A p - n kifejezés típusmutatót T*ad. Ezt a mutatót úgy érheti el, hogy p kivonja a mutatót n * sizeof(T) a címből.

Az sizeof operátor bájtban kapja meg a típus méretét.

Az alábbi példa bemutatja, hogyan használhatja az + operátort mutatóval:

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ó és típus esetén a kifejezés p1 - p2 megadja a különbséget azoknak a címeknek a között, amelyekre p1p2 mutat, osztva a következővelsizeof(T): .T*p2p1 Az eredmény típusa .long Más szóval a p1 - p2 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 űrlapot támogat: postfix (p++ és p--) és előtag (++p és --p). A művelet eredménye p++ és p-- értéke p. A művelet eredménye ++p és --p értéke p.

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áíratlan 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

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

C# nyelvspecifikáció

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

Lásd még