Pointers in C#

In this article, I will share my thoughts on Pointers in C#. Please note that It is important to know the difference between managed and unmanaged code in C# before continue reading.

The unsafe keyword

Pointers in C# are rarely required, but when needed, they are used with the unsafe keyword. Unsafe is used to distinguish managed from unmanaged code, also called safe and unsafe codes. The safe code is the one that most of you usually write in your daily tasks. It is managed by the CLR, which is providing type checking, exception handling, garbage collection, and a lot more. However, if you want to do the CLR job on your own you can tell the compiler that the current code is unmanaged, by using the unsafe keyword.

What exactly are pointers in C#?

So, what are the pointers? They are just variables which are holding the memory address of another variable. By default, C# doesnโ€™t allow pointers usage, unless you donโ€™t use the unsafe code mode. Since the unsafe code doesnโ€™t have garbage collection, you will need pointers to deal with the application memory on your own.

To start using pointers and unsafe code in an application, you must implicitly allow it. This can be done by clicking project properties in Visual Studio, and then select the Build tab:

Enable unsafe code in Visual Studio
Enable unsafe code in Visual Studio

After that set, you are ready to go. To declare a pointer, use the following syntax:

[type]* [name]

and actual example:

int* customPointer

As I already said the pointer is a variable holding the address of another variable. To tell the compiler this is a pointer we mark it with the * sign. Above all, a type marked like this is called referent, and it is available only inside the unsafe mode. In addition, an important note is that a pointer cannot point to a reference or to a struct, containing references.

You may also see the following syntax with double * -> int**. This means a pointer holding the address of another pointer. Or int*** (and so on) – pointer, holding the pointer, which is holding the address of another pointer.

Simple example

Letโ€™s look at the following code:

C#
unsafe
{
    int number = 1;
    int* customPointer = &number;
    int** customPointerPointer = &customPointer;
    int*** customPointerPointerPointer = &customPointerPointer;

    Console.WriteLine($"The value of the integer is {number}");
    
    Console.WriteLine($"Address of {nameof(customPointer)}: {(int)customPointer}");
    Console.WriteLine($"Address of {nameof(customPointerPointer)}: {(int)customPointerPointer}");
    Console.WriteLine($"Address of {nameof(customPointerPointerPointer){(int)customPointerPointerPointer}");
    Console.WriteLine();
}

The output of this code is:

Pointers in C# - simple example
Pointers in C# – simple example

As you can see I am using the syntax int* customPointer = &number. The operator & means – get the memory address of the integer variable number. The unsafe keyword is used inline here, but you can also use it in a method declaration:

C#
static unsafe void UnsafeMethod()
{
    // some code ...
}

What is the fixed keyword used for?

Another important thing about the pointers is the fixed keyword. If you are working with arrays, for instance, the CLR’s garbage collector can move your array objects to different addresses for some optimizations. Therefore, the compiler will not let you declare a pointer to an array element since it can be changed at runtime. However, you can lock that array element and prevent it from relocation with the fixed keyword. For instance:

C#
byte[] byteArray = { 1, 2, 3 };
fixed (byte* pointerToSecondElement = &(byteArray[2]))
{
    Console.WriteLine($"First element address: {(long)pointerToSecondElement:X}.");
    Console.WriteLine($"First element value: {*pointerToSecondElement}.");
}

The address of the second variable will not change while in the fixed statement.

Downloads

1 Comment

Comments are closed