C#idiomatic C#
fixedcsharp/language-reference/statements

Language

fixed statement - pin a variable for pointer operations

Use the C# `fixed` statement to pin a moveable variable and declare a pointer to that variable. The address of a pinned variable doesn't change during execution of the statement.

  • page csharp/language-reference/statements/fixed
  • updated 06/16/2026

The fixed statement prevents the garbage collector from relocating a moveable variable and declares a pointer to that variable. The address of a fixed, or pinned, variable doesn't change during execution of the statement. You can use the declared pointer only inside the corresponding fixed statement. The declared pointer is readonly and can't be modified:

sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedArray

csharp
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();

static void PinnedArray()
{
    // <PinnedArray>
    unsafe
    {
        byte[] bytes = [1, 2, 3];
        fixed (byte* pointerToFirst = bytes)
        {
            Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
            Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
        }
    }
    // Output is similar to:
    // The address of the first array element: 2173F80B5C8.
    // The value of the first array element: 1.
    // </PinnedArray>
}

static void PinnedVariable()
{
    // <PinnedVariable>
    unsafe
    {
        int[] numbers = [10, 20, 30];
        fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
        {
            Console.WriteLine(toLast - toFirst);  // output: 2
        }
    }
    // </PinnedVariable>
}

static void PinnedSpan()
{
    // <PinnedSpan>
    unsafe
    {
        int[] numbers = [10, 20, 30, 40, 50];
        Span<int> interior = numbers.AsSpan()[1..^1];
        fixed (int* p = interior)
        {
            for (int i = 0; i < interior.Length; i++)
            {
                Console.Write(p[i]);  
            }
            // output: 203040
        }
    }
    // </PinnedSpan>
    Console.WriteLine();
}

static void PinnedString()
{
    // <PinnedString>
    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    // </PinnedString>
}

ms.custom: "updateeachrelease"

The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.

The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.

  • With an array, as the example at the beginning of this article shows. The initialized pointer contains the address of the first array element.
  • With an address of a variable. Use the address-of & operator, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedVariable

csharp
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();

static void PinnedArray()
{
    // <PinnedArray>
    unsafe
    {
        byte[] bytes = [1, 2, 3];
        fixed (byte* pointerToFirst = bytes)
        {
            Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
            Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
        }
    }
    // Output is similar to:
    // The address of the first array element: 2173F80B5C8.
    // The value of the first array element: 1.
    // </PinnedArray>
}

static void PinnedVariable()
{
    // <PinnedVariable>
    unsafe
    {
        int[] numbers = [10, 20, 30];
        fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
        {
            Console.WriteLine(toLast - toFirst);  // output: 2
        }
    }
    // </PinnedVariable>
}

static void PinnedSpan()
{
    // <PinnedSpan>
    unsafe
    {
        int[] numbers = [10, 20, 30, 40, 50];
        Span<int> interior = numbers.AsSpan()[1..^1];
        fixed (int* p = interior)
        {
            for (int i = 0; i < interior.Length; i++)
            {
                Console.Write(p[i]);  
            }
            // output: 203040
        }
    }
    // </PinnedSpan>
    Console.WriteLine();
}

static void PinnedString()
{
    // <PinnedString>
    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    // </PinnedString>
}

Object fields are another example of moveable variables that you can pin.

When the initialized pointer contains the address of an object field or an array element, the fixed statement guarantees that the garbage collector doesn't relocate or dispose of the containing object instance during the execution of the statement body.

  • With the instance of the type that implements a method named GetPinnableReference. That method must return a ref variable of an unmanaged type. The .NET types System.Span and System.ReadOnlySpan make use of this pattern. You can pin span instances, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedSpan

csharp
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();

static void PinnedArray()
{
    // <PinnedArray>
    unsafe
    {
        byte[] bytes = [1, 2, 3];
        fixed (byte* pointerToFirst = bytes)
        {
            Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
            Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
        }
    }
    // Output is similar to:
    // The address of the first array element: 2173F80B5C8.
    // The value of the first array element: 1.
    // </PinnedArray>
}

static void PinnedVariable()
{
    // <PinnedVariable>
    unsafe
    {
        int[] numbers = [10, 20, 30];
        fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
        {
            Console.WriteLine(toLast - toFirst);  // output: 2
        }
    }
    // </PinnedVariable>
}

static void PinnedSpan()
{
    // <PinnedSpan>
    unsafe
    {
        int[] numbers = [10, 20, 30, 40, 50];
        Span<int> interior = numbers.AsSpan()[1..^1];
        fixed (int* p = interior)
        {
            for (int i = 0; i < interior.Length; i++)
            {
                Console.Write(p[i]);  
            }
            // output: 203040
        }
    }
    // </PinnedSpan>
    Console.WriteLine();
}

static void PinnedString()
{
    // <PinnedString>
    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    // </PinnedString>
}

For more information, see the System.Span.GetPinnableReference API reference.

  • With a string, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedString

csharp
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();

static void PinnedArray()
{
    // <PinnedArray>
    unsafe
    {
        byte[] bytes = [1, 2, 3];
        fixed (byte* pointerToFirst = bytes)
        {
            Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
            Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
        }
    }
    // Output is similar to:
    // The address of the first array element: 2173F80B5C8.
    // The value of the first array element: 1.
    // </PinnedArray>
}

static void PinnedVariable()
{
    // <PinnedVariable>
    unsafe
    {
        int[] numbers = [10, 20, 30];
        fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
        {
            Console.WriteLine(toLast - toFirst);  // output: 2
        }
    }
    // </PinnedVariable>
}

static void PinnedSpan()
{
    // <PinnedSpan>
    unsafe
    {
        int[] numbers = [10, 20, 30, 40, 50];
        Span<int> interior = numbers.AsSpan()[1..^1];
        fixed (int* p = interior)
        {
            for (int i = 0; i < interior.Length; i++)
            {
                Console.Write(p[i]);  
            }
            // output: 203040
        }
    }
    // </PinnedSpan>
    Console.WriteLine();
}

static void PinnedString()
{
    // <PinnedString>
    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    // </PinnedString>
}

You can allocate memory on the stack, where it's not subject to garbage collection and therefore doesn't need to be pinned. To do that, use a stackalloc expression.

You can also use the fixed keyword to declare a fixed-size buffer.

C# language specification

For more information, see the following sections of the C# language specification:

See also