“Pointer is a variable which contains memory address of another variable”
In very short terms we can say that a “pointer is a memory address”. The address that a pointer variable holds directly points to value stored in memory and that value is assigned to another variable which is not a pointer. That’s why we call them pointers because they point, they point to a value, they point because they have address to point.
What is an Unsafe code in C#?
In C# an unsafe code is a block of code that not runs under the control of CLR. Unsafe code actually a block of code that include pointers, so in C# pointers are unsafe.
Before we start discussing why pointers are unsafe you should be aware of some common terms. Terms like CLR, managed code and unmanaged code.
What is CLR?
CLR is common language runtime that controls the execution of .net programs from loading into memory to exception handling and type safety. CLR also provides a Debug Engine, Garbage Collector, Thread management and many other features for handling the execution of C# programs and other .net based programming languages.
When you install .net framework on your computer you basically install to main components of .net framework.
• BCL (.net framework base class library)
• CLR (common language runtime)
BCL is standard .net base class library, you can access BCL through windows based console apps, windows winform and WPF apps, asp.net web apps, asp.net web services and windows services. .Net framework also contains two more components
• CTS: CTS stands for Common Type Specification which defines the data types that can be used in C# and others .net languages.
• CLS: CLS stands for Common Language Specification which is part of CTS and it defines the rules that must be obeyed by all language compilers.
Discussing all components and features of .Net Framework is not the part of this article but as we are learning pointers and unsafe code we should be aware of these terms.
There are two more concepts that you must be aware of before discussing pointers and these are Managed Code and Unmanaged Code.
Managed Code: Managed code runs under the control of CLR. Managed code is trackable and can be garbage collected. Managed code runs by CLR under managed environment and have access to all CLR features, CLR verifies the security and type safety of managed code.
Unmanaged Code: Unmanaged code cannot be executed by CLR it is executed directly by computer CPU and have no access to CLR features. As CLR has no authorities on unmanaged code, so CLR cannot verifies the security and type safety of unmanaged code.
Why Should I learn?
Well that’s very important question, after all why should we learn pointers?
It’s because you need to use them and when you are going to use them that’s another important question.
You are going to use pointers when performance is at first priority. The pointers run in unmanaged environment where all the advantages of managed environment are removed.
• Pointers come with many benefits like there is no time waste in unnecessary runtime checks for type safety and other correctness.
• Pointers also used to build data structures like linked list, stack, queue etc.
Discussing and explaining the practical applications of pointers is not in scope of this article but at minimum you have reasons to continue from here.
Now Let’s Learn
Now we have very good reasons to learn pointers so let’s dive into experimenting and writing some operations involved pointers.
Unsafe Context
In C# we cannot directly declare and use pointers and the reasons we have discussed above. We need a specific code block for defining and using pointers. Using “unsafe” keyword, we can define a specific code block for writing unsafe code. Unsafe keyword denotes an unsafe context where we can define and use pointers. You can use “unsafe” modifier to declare a class or any member of it to make entire class or member considered as unsafe.
/unsafe compiler option: The /unsafe is compiler option that allows C# compiler to compile unsafe code block, unsafe types and unsafe members. If you are unable to compile unsafe code then you have to manually check allow unsafe code option from project properties page.
• Go to Projects property page (Project ->Properties).
• Navigate to build tab
• Select Allow Unsafe Checkbox
That’s all you have to do.
Unsafe Code Properties
• Unsafe modifier can be used at class and a method in order to make them unsafe.
• Unsafe modifier can be used to define an unsafe code block.
• CLR cannot verifies the security of Unsafe code so it can cause some security risks.
• Unsafe code can improve performance by avoiding runtime checks, array bounds and other CLR advantages.
Declaring Pointers
Pointers can be declared in an unsafe context by specifying asterisk (*) sign with type specification. The asterisk (*) sign called pointer indirection operator that is used to get the actual content from location pointed by pointer variable.
The asterisk (*) also called de-reference operator and it can also be specified with variable name but it’s a good practice to keep it with type name. When you declare multiple pointers in one declaration then you have to specify the asterisk (*) with underlying type only.
Types of Pointers
In unsafe context a variable type can be of reference type, value type and pointer type but pointers can only point to
• primitive value types
• struct containing value types only
• other pointer types
In C# pointers cannot point to reference types it’s because reference types managed by CLR and can be garbage collected but on other hand pointers run under unmanaged environment and cannot be tracked by GC (garbage collector), a reference can be garbage collected any time when a pointer pointing to it, so in C# pointers cannot point to
• reference types
• struct containing reference types
1
internalunsafeclassProgram
2
{
3
privatestaticvoidMain()
4
{
5
unsafe
6
{
7
inta=20;
8
int*ptr=&a;
9
10
int*ptr2=ptr;
11
12
Console.WriteLine($"Value of a is {*ptr}");
13
Console.WriteLine($"Address of a is {(int)ptr2}");
14
}
15
}
16
}
Result:
Obtaining Value
You can use pointer indirection operator (*) to obtain the value at location pointed by pointer.
Paste the following code in main method of your console app.
1
Unsafe
2
{
3
inta=23;
4
int*ptr=&a;
5
6
Console.WriteLine($"Value of ptr {*ptr}");
7
}
Result:
you cannot use pointer indirection operator on void pointer to obtain value.
Obtaining Address
The address of variable can be obtained by ampersand (&) sign. The ampersand (&) sign also called address-of operator.
Make sure variable is initialized before you obtain the address because compiler will not show an error message. if variable is not initialized then you will receive garbage value at runtime.
1
unsafe
2
{
3
inta=30;
4
int*ptr=&a;
5
6
Console.WriteLine($"Address of a is {(int)ptr}");
7
}
Result:
Note:You cannot obtain address of a value directly and also of a constant variable.
Structs and Pointers
In C# pointers can also be used to point to Structs only if struct contains primitive value types. If a struct contains any reference type like string or any type derived from object type, then you can’t use a pointer to point that specific struct.
The members of struct declared in unsafe context can be accessed both by member access operator (→) and de-reference operator (*).
1
structRectangle
2
{
3
publicintWidth { get; set; }
4
publicintHeight { get; set; }
5
}
6
7
internalunsafeclassProgram
8
{
9
privatestaticvoidMain()
10
{
11
Rectanglestd;
12
unsafe
13
{
14
Rectangle*stdPtr=&std;
15
16
stdPtr->Width=35;
17
(*stdPtr).Height=23;
18
19
Console.WriteLine($"Width of Rectangle : {stdPtr->Width}");
20
Console.WriteLine($"Height of Rectangle: {(*stdPtr).Height}");
21
}
22
}
23
}
Result:
Pointer to Arrays
We can also define pointers to access array elements from memory using pointer element access arr[index]. The index can be any int, uint, long ro ulong.
Array element can also be accessed using *(arr+index) expression.
1
internalunsafeclassProgram
2
{
3
privatestaticvoidMain()
4
{
5
unsafe
6
{
7
int*arr=stackallocint[3];
8
9
arr[0] =97;
10
arr[1] =98;
11
arr[2] =99;
12
Console.WriteLine("\t Values");
13
for (inti=0; i<=2; i++)
14
{
15
Console.WriteLine($"Value at {i}: {arr[i]}");
16
}
17
Console.WriteLine("\n\tChars");
18
for (inti=0; i<=2; i++)
19
{
20
Console.WriteLine($"Char at {i}: {(char)*(arr + i)}");