Compartir a través de


Operadores relacionados con el puntero: tome la dirección de las variables, las ubicaciones de almacenamiento de desreferencia y las ubicaciones de memoria de acceso

Los operadores de puntero permiten tomar la dirección de una variable (&), desreferenciar un puntero (*), comparar valores de puntero y agregar o restar punteros e enteros.

La documentación de referencia del lenguaje C# cubre la versión más reciente publicada del lenguaje C#. También contiene documentación inicial sobre las características de las versiones preliminares públicas de la próxima versión del lenguaje.

La documentación identifica cualquier característica introducida por primera vez en las últimas tres versiones del idioma o en las versiones preliminares públicas actuales.

Sugerencia

Para buscar cuándo se introdujo por primera vez una característica en C#, consulte el artículo sobre el historial de versiones del lenguaje C#.

Use los operadores siguientes para trabajar con punteros:

Para obtener información sobre los tipos de punteros, vea Tipos de puntero.

Nota

Cualquier operación con punteros requiere un contexto unsafe. Debe compilar el código que contiene bloques no seguros con la opción del compilador AllowUnsafeBlocks .

Operador Address-of y

El operador unario & devuelve la dirección de su 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

El operando del operador & debe ser una variable fija. Las variables fijas son variables que residen en ubicaciones de almacenamiento que el recolector de elementos no utilizados no afecta. En el ejemplo anterior, la variable number local es una variable fija porque reside en la pila. Las variables que residen en ubicaciones de almacenamiento que el recolector de elementos no utilizados puede afectar (por ejemplo, reubicar) se denominan variables extraíbles . Los campos de objeto y los elementos de matriz son ejemplos de variables móviles. Puede obtener la dirección de una variable extraíble si se "corrige" o "anclar", mediante una fixed instrucción . La dirección obtenida solo es válida dentro del bloque de una instrucción fixed. En el ejemplo siguiente se muestra cómo usar una instrucción fixed y el operador &:

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

No se puede obtener la dirección de una constante o un valor.

Para obtener más información sobre las variables fijas y móviles, vea la sección Variables fijas y móviles de Especificación del lenguaje C#.

El operador binario & calcula el AND lógico de sus operandos booleanos o el AND lógico bit a bit de sus operandos enteros.

Operador de direccionamiento indirecto del puntero *

El operador * de direccionamiento indirecto de puntero unario accede a la variable a la que apunta su operando. También se conoce como operador de desreferencia. El operando del operador * debe ser un tipo de puntero.

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

No se puede aplicar el operador * a una expresión de tipo void*.

El operador binario * calcula la multiplicación de sus operandos numéricos.

Operador de acceso de miembro de puntero ->

El operador -> combina el direccionamiento indirecto del puntero y el acceso a miembros. Si x es un puntero de tipo T* y y es un miembro accesible de tipo T, una expresión del formulario

x->y

es equivalente a

(*x).y

En el siguiente ejemplo se muestra el uso del operador ->:

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

No se puede usar el -> operador en una expresión de tipo void*.

Operador de acceso a elementos de puntero []

Para una expresión p de un tipo de puntero, el acceso a un elemento de puntero del formulario p[n] se evalúa como *(p + n). El valor n debe ser de un tipo convertible implícitamente a int, uint, longo ulong. Para obtener información sobre el comportamiento del operador + con punteros, vea la sección Suma o resta de un valor entero en un puntero.

En el ejemplo siguiente se muestra cómo obtener acceso a los elementos de matriz mediante un puntero y el [] operador :

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

En el ejemplo anterior, una expresión stackalloc asigna un bloque de memoria en la pila.

Nota

El operador de acceso de elemento de puntero no busca errores fuera de límites.

No puede usar [] para el acceso de elemento de puntero con una expresión de tipo void*.

También puede usar el operador [] para acceso de elemento de matriz o indizador.

Operadores aritméticos de puntero

Puede realizar las siguientes operaciones aritméticas con punteros:

  • Agregar o restar un valor entero en un puntero
  • Restar dos punteros
  • Incrementar o reducir un puntero

No es posible realizar esas operaciones con punteros de tipo void*.

Para obtener información sobre las operaciones aritméticas admitidas mediante tipos numéricos, consulte Operadores aritméticos.

Agregar o restar un valor entero en un puntero

Para un puntero p de tipo T* y una expresión n de un tipo convertible implícitamente a int, , uintlongo ulong, el trabajo de suma y resta como se indica a continuación:

  • Tanto p + n como n + p le proporcionan un puntero de tipo T*. Para obtener este puntero, agregue n * sizeof(T) a la dirección a la que p apunta.
  • La p - n expresión proporciona un puntero de tipo T*. Obtiene este puntero restando n * sizeof(T) de la dirección a la que p apunta.

El sizeof operador obtiene el tamaño de un tipo en bytes.

En el ejemplo siguiente se muestra cómo usar el + operador con un puntero:

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

Resta de puntero

Para dos punteros p1 y p2 de tipo T*, la expresión p1 - p2 proporciona la diferencia entre las direcciones a las que p1 y p2 apunta, divididas por sizeof(T). El resultado es de tipo long. En otras palabras, p1 - p2 se calcula como ((long)(p1) - (long)(p2)) / sizeof(T).

En el ejemplo siguiente se muestra la resta del puntero:

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 y decremento de puntero

El operador de incremento ++agrega 1 a su operando de puntero. El operador de decremento --resta 1 a su operando de puntero.

Ambos operadores admiten dos formas: postfijo (p++ y p--) y prefijo (++p y --p). El resultado de p++ y p-- es el valor de pantes de la operación. El resultado de ++p y --p es el valor de pdespués de la operación.

El ejemplo siguiente muestra el comportamiento de los operadores de incremento postfijo y prefijo:

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

Operadores de comparación de puntero

Puede usar los operadores ==, !=, <, >, <= y >= para comparar los operandos de cualquier tipo de puntero, incluido void*. Estos operadores comparan las direcciones dadas por los dos operandos como si fueran enteros sin signo.

Para obtener información sobre el comportamiento de esos operadores para operandos de otros tipos, vea los artículos Operadores de igualdad y Operadores de comparación.

Prioridad de operadores

En la lista siguiente se ordenan los operadores relacionados con el puntero desde la prioridad más alta a la más baja:

  • Operadores de incremento x++ y decremento x-- postfijos y operadores -> y []
  • Operadores de incremento ++x y decremento --x prefijos y operadores & y *
  • Operadores + y - de suma
  • Operadores de comparación <, >, <= y >=
  • Operadores de igualdad == y !=

Use paréntesis, (), para cambiar el orden de evaluación impuesto por la prioridad de los operadores.

Para obtener la lista completa de los operadores de C# ordenados por nivel de prioridad, vea la sección Prioridad de operadores del artículo Operadores de C#.

Posibilidad de sobrecarga del operador

No se pueden sobrecargar los operadores &relacionados con el puntero , *, ->y [] en un tipo definido por el usuario.

Especificación del lenguaje C#

Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:

Consulte también