Dela via


Pekarrelaterade operatorer – ta adressen till variabler, dereferencelagringsplatser och komma åt minnesplatser

Med pekaroperatorerna kan du ta adressen till en variabel (&), dereferera en pekare (*), jämföra pekarvärden och lägga till eller subtrahera pekare och heltal.

C#-språkreferensen dokumenterar den senaste versionen av C#-språket. Den innehåller även inledande dokumentation för funktioner i offentliga förhandsversioner för den kommande språkversionen.

Dokumentationen identifierar alla funktioner som först introducerades i de tre senaste versionerna av språket eller i aktuella offentliga förhandsversioner.

Tips/Råd

Information om när en funktion först introducerades i C# finns i artikeln om språkversionshistoriken för C#.

Använd följande operatorer för att arbeta med pekare:

Information om pekartyper finns i Pekartyper.

Kommentar

Alla åtgärder med pekare kräver en osäker kontext. Du måste kompilera koden som innehåller osäkra block med kompileringsalternativet AllowUnsafeBlocks .

Adress för operatorn &

Den unary & operatorn returnerar adressen för dess operand:

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

Operatorns & operande måste vara en fast variabel. Fasta variabler är variabler som finns på lagringsplatser som skräpinsamlaren inte påverkar. I föregående exempel är den lokala variabeln number en fast variabel eftersom den finns i stacken. Variabler som finns på lagringsplatser som skräpinsamlaren kan påverka (till exempel flytta) kallas flyttbara variabler. Objektfält och matriselement är exempel på rörliga variabler. Du kan hämta adressen till en flyttbar variabel om du "korrigerar" eller "fäster" den med hjälp av en fixed instruktion. Den erhållna adressen är endast giltig i blocket för en fixed -instruktion. I följande exempel visas hur du använder en fixed -instruktion och operatorn & :

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

Du kan inte hämta adressen till en konstant eller ett värde.

Mer information om fasta och rörliga variabler finns i avsnittet Fasta och flyttbara variabler i C#-språkspecifikationen.

Den binära & operatorn beräknar det logiska OCH för dess booleska operander eller den bitvis logiska AND för dess integrerade operander.

Indirekta pekaroperatorer *

Den unary pekaren indirection operatorn * kommer åt variabeln som dess operand pekar till. Det kallas även för dereferenceoperatorn. Operatorns * operand måste vara av pekartyp.

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

Du kan inte tillämpa operatorn på * ett uttryck av typen void*.

Den binära * operatorn beräknar produkten av dess numeriska operander.

Pekarens medlemsåtkomstoperator ->

Operatorn -> kombinerar indirekt pekare och medlemsåtkomst. Om x är en pekare av typen T* och y är en tillgänglig medlem av typen T, ett uttryck för formuläret

x->y

motsvarar

(*x).y

I följande exempel visas hur operatorn -> används:

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)
    }
}

Du kan inte använda operatorn för -> ett uttryck av typen void*.

Åtkomstoperator för pekarelement []

För ett uttryck p av pekartyp utvärderas en pekarelementåtkomst för formuläret p[n] som *(p + n). Värdet n måste vara av en typ som implicit kan konverteras till int, uint, longeller ulong. Information om operatorns + beteende med pekare finns i avsnittet Addition eller subtraktion av ett integralvärde till eller från en pekare .

I följande exempel visas hur du kommer åt matriselement med hjälp av en pekare och operatorn [] :

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

I föregående exempel allokerar ett stackalloc uttryck ett minnesblock i stacken.

Kommentar

Åtkomstoperatorn för pekarelementet söker inte efter fel utanför gränserna.

Du kan inte använda [] för åtkomst till pekarelement med ett uttryck av typen void*.

Du kan också använda operatorn [] för matriselement eller indexerareåtkomst.

Pekarens aritmetiska operatorer

Du kan utföra följande aritmetiska åtgärder med pekare:

  • Lägga till eller subtrahera ett integralvärde till eller från en pekare
  • Subtrahera två pekare
  • Öka eller minska en pekare

Du kan inte utföra dessa åtgärder med pekare av typen void*.

Information om aritmetiska åtgärder som stöds med hjälp av numeriska typer finns i Aritmetiska operatorer.

Lägga till eller subtrahera ett integralvärde till eller från en pekare

För en pekare p av typen T* och ett uttryck n av en typ som implicit kan konverteras till int, uint, longeller ulong, fungerar addition och subtraktion enligt följande:

  • Både p + n och n + p ger dig en pekare av typen T*. Du får den här pekaren genom att lägga n * sizeof(T) till den adress som p pekar på.
  • Uttrycket p - n ger dig en pekare av typen T*. Du får den här pekaren genom att subtrahera n * sizeof(T) från adressen som p pekar på.

Operatornsizeof hämtar storleken på en typ i byte.

I följande exempel visas hur du använder operatorn + med en pekare:

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

Pekarundertraktion

För två pekare p1 och p2 av typen T*ger uttrycket p1 - p2 dig skillnaden mellan de adresser som p1 och p2 pekar på, dividerat med sizeof(T). Resultatet är av typen long. Med andra ord p1 - p2 beräknas som ((long)(p1) - (long)(p2)) / sizeof(T).

I följande exempel visas pekarens subtraktion:

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
}

Ökning och minskning av pekare

Inkrementsoperatorn ++lägger till 1 i pekaroperatorn. Decrementoperatorn --subtraherar 1 från dess pekaroperator.

Båda operatorerna stöder två formulär: postfix (p++ och p--) och prefix (++p och --p). Resultatet av p++ och p-- är värdet p för före åtgärden. Resultatet av ++p och --p är värdet p för efter åtgärden.

I följande exempel visas beteendet för både postfix- och prefixökningsoperatorer:

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

Jämförelseoperatorer för pekare

Du kan använda operatorerna ==, !=, <, >, <=och >= för att jämföra operander av valfri pekartyp, inklusive void*. Dessa operatorer jämför de adresser som anges av de två operanderna som om de vore osignerade heltal.

Information om beteendet för operatorerna för operander av andra typer finns i artiklarna Likhetsoperatorer och Jämförelseoperatorer .

Prioritet för operator

Följande listordningspekare relaterade operatorer från den högsta prioriteten till den lägsta:

  • Postfix-inkrementsx++- och deskrementsoperatorer x-- samt operatorerna -> och []
  • Prefixets inkrements++x- och deskrementsoperatorer --x och operatorerna & och *
  • Additiva + och - operatorer
  • Jämförelse <, >, <=och >= operatorer
  • Likhet == och != operatorer

Använd parenteser, (), för att ändra ordningen på utvärderingen som har införts av operatorprioriteten.

En fullständig lista över C#-operatorer ordnade efter prioritetsnivå finns i avsnittet Operatorprioriteten i artikeln C#-operatorer .

Överlagring av operator

Du kan inte överbelasta pekarrelaterade operatorer &, *, ->och [] i en användardefinierad typ.

Språkspecifikation för C#

Mer information finns i följande avsnitt i C#-språkspecifikationen:

Se även