Condividi tramite


Operatori correlati al puntatore: accettare l'indirizzo delle variabili, dereferenziare le posizioni di archiviazione e accedere alle posizioni di memoria

Gli operatori puntatore consentono di accettare l'indirizzo di una variabile (&), dereferenziare un puntatore (*), confrontare i valori del puntatore e aggiungere o sottrarre puntatori e interi.

Il riferimento al linguaggio C# documenta la versione rilasciata più di recente del linguaggio C#. Contiene anche la documentazione iniziale per le funzionalità nelle versioni di anteprima pubblica per la prossima versione del linguaggio di programmazione.

La documentazione identifica tutte le funzionalità introdotte nelle ultime tre versioni della lingua o nelle anteprime pubbliche correnti.

Suggerimento

Per trovare quando una funzionalità è stata introdotta per la prima volta in C#, vedere l'articolo sulla cronologia delle versioni del linguaggio C#.

Usare gli operatori seguenti per usare i puntatori:

Per informazioni sui tipi di puntatori, vedere Tipi di puntatori.

Nota

Qualsiasi operazione con i puntatori richiede un contesto unsafe. È necessario compilare il codice che contiene blocchi non sicuri con l'opzione del compilatore AllowUnsafeBlocks .

Operatore address-of &

L'operatore & unario restituisce l'indirizzo del relativo operando:

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

L'operando dell'operatore & deve essere una variabile fissa. Le variabili fisse sono variabili che risiedono in posizioni di archiviazione che il Garbage Collector non influisce. Nell'esempio precedente la variabile locale è una variabile number fissa perché risiede nello stack. Le variabili che risiedono in posizioni di archiviazione che il Garbage Collector può influire (ad esempio, rilocare) sono denominate variabili mobili . I campi degli oggetti e gli elementi delle matrici sono esempi di variabili mobili. È possibile ottenere l'indirizzo di una variabile mobile se si "fix" o "pin", usando un'istruzionefixed . L'indirizzo ottenuto è valido solo all'interno del blocco di un'istruzione fixed. L'esempio seguente mostra come usare un’istruzione fixed e l'operatore &:

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

Non è possibile ottenere l'indirizzo di una costante o di un valore.

Per altre informazioni sulle variabili fisse e mobili, vedere la sezione Variabili fisse e mobili dell'articolo relativo alla specifica del linguaggio C#.

L'operatore & binario calcola l'AND logico dei relativi operandi booleani o l'AND logico bit per bit dei relativi operandi integrali.

Operatore * (riferimento indiretto a puntatore)

L'operatore * di riferimento indiretto puntatore unario accede alla variabile a cui punta il relativo operando. L'operatore è chiamato anche operatore di dereferenziazione. L'operando dell'operatore * deve essere un tipo di puntatore.

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

Non è possibile applicare l'operatore * a un'espressione di tipo void*.

L'operatore * binario calcola il prodotto dei relativi operandi numerici.

Operatore di accesso ai membri del puntatore ->

L'operatore -> unisce il riferimento indiretto al puntatore e l'accesso ai membri. Se x è un puntatore di tipo T* ed y è un membro accessibile di tipo T, un'espressione del modulo

x->y

equivale a

(*x).y

Nell'esempio seguente viene illustrato l'uso dell'operatore ->:

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

Non è possibile usare l'operatore su un'espressione -> di tipo void*.

Operatore di accesso all'elemento Pointer []

Per un'espressione p di un tipo di puntatore, l'accesso di un elemento puntatore della maschera p[n] viene valutato come *(p + n). Il valore n deve essere di un tipo convertibile in modo implicito in int, uint, longo ulong. Per informazioni sul comportamento dell'operatore + con i puntatori, vedere la sezione Addizione o sottrazione di un valore integrale da un puntatore.

Nell'esempio seguente viene illustrato come accedere agli elementi della matrice usando un puntatore e l'operatore [] :

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

Nell'esempio precedente, un'espressione stackalloc alloca un blocco di memoria nello stack.

Nota

L'operatore di accesso agli elementi del puntatore non ricerca gli errori relativi a valori non compresi nell'intervallo.

Non è possibile usare [] per l'accesso all’elemento del puntatore con un'espressione di tipo void*.

È anche possibile usare l'operatore [] per l'accesso agli elementi di una matrice o all'indicizzatore.

Operatori aritmetici dei puntatori

È possibile eseguire le operazioni aritmetiche seguenti con i puntatori:

  • Aggiungere o sottrarre un valore integrale da un puntatore
  • Sottrarre due puntatori
  • Incrementare o decrementare un puntatore

Non è possibile eseguire queste operazioni con puntatori di tipo void*.

Per informazioni sulle operazioni aritmetiche supportate tramite tipi numerici, vedere Operatori aritmetici.

Aggiungere o sottrarre un valore integrale da un puntatore

Per un puntatore p di tipo T* e un'espressione n di un tipo convertibile in modo implicito in int, uintlong, o ulong, l'addizione e la sottrazione funzionano nel modo seguente:

  • Entrambi p + n e n + p forniscono un puntatore di tipo T*. Per ottenere questo puntatore, aggiungere n * sizeof(T) all'indirizzo a cui p punta.
  • L'espressione p - n fornisce un puntatore di tipo T*. Questo puntatore viene ottenuto sottraendo n * sizeof(T) dall'indirizzo a cui p punta.

L'operatoresizeof ottiene le dimensioni di un tipo in byte.

L'esempio seguente illustra come usare l'operatore + con un puntatore:

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

Sottrazione di puntatori

Per due puntatori p1 e p2 di tipo T*, l'espressione p1 - p2 fornisce la differenza tra gli indirizzi che p1 e p2 puntano a, divisi per sizeof(T). Il risultato è di tipo long. In altre parole, p1 - p2 viene calcolato come ((long)(p1) - (long)(p2)) / sizeof(T).

L'esempio seguente mostra la sottrazione del puntatore:

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
}

Incremento e decremento dei puntatori

L'operatore di incremento ++somma 1 al relativo operando puntatore. L'operatore di decremento --sottrae 1 dal relativo operando puntatore.

Entrambi gli operatori supportano due forme: suffisso (p++ e p--) e prefisso (++p e --p). Il risultato di p++ e p-- è il valore di pprima dell'operazione. Il risultato di ++p e --p è il valore di pdopo l'operazione.

L'esempio seguente illustra il comportamento di entrambi gli operatori di incremento suffisso e prefisso:

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

Operatori di confronto dei puntatori

È possibile usare gli operatori ==, !=, <, >, <= e >= per confrontare gli operandi di qualsiasi tipo di puntatore, incluso void*. Questi operatori confrontano gli indirizzi specificati dai due operandi come se fossero numeri interi senza segno.

Per informazioni sul comportamento di questi operatori per gli operandi di altri tipi, vedere gli articoli Operatori di uguaglianza e Operatori di confronto.

Precedenza tra gli operatori

Nell'elenco seguente gli operatori correlati ai puntatori sono ordinati dalla precedenza più elevata a quella più bassa:

  • Operatori di incremento x++ e decremento x-- suffisso e operatori -> e []
  • Operatori di incremento ++x e decremento --x prefisso e operatori & e *
  • Operatori di addizione + e -
  • Operatori di confronto <, >, <= e >=
  • Operatori di uguaglianza == e !=

Usare le parentesi, (), per cambiare l'ordine di valutazione imposto dalla precedenza tra gli operatori.

Per l'elenco completo degli operatori C# ordinati per livello di precedenza, vedere la sezione precedenza dell'operatore nell'articolo operatori C#.

Overload degli operatori

Non è possibile eseguire l'overload degli operatori &correlati al puntatore , , *->e [] in un tipo definito dall'utente.

Specifiche del linguaggio C#

Per altre informazioni, vedere le sezioni seguenti delle specifiche del linguaggio C#:

Vedi anche