Pointers In C#

C# Pointer is a variable that holds memory address of another type. In this article, learn how to implement pointers in C#. Here you will learn how to define C# Pointers.

C# supports pointers in a limited extent. A C# pointer is nothing but a variable that holds the memory address of another type. But in C# pointer can only be declared to hold the memory address of value types and arrays. Unlike reference types, pointer types are not tracked by the default garbage collection mechanism. For the same reason pointers are not allowed to point to a reference type or even to a structure type which contains a reference type. We can say that pointers can point to only unmanaged types which includes all basic data types, enum types, other pointer types and structs which contain only unmanaged types.
 

Declaring a Pointer type

 
The general form of declaring a pointer type is as shown below,
 
type *variable_name;
 
Where * is known as the de-reference operator. For example the following statement
 
int *x ;
 
Declares a pointer variable x, which can hold the address of an int type. The reference operator (&) can be used to get the memory address of a variable.
  1. int x = 100;  
The &x gives the memory address of the variable x, which we can assign to a pointer variable 
  1. int *ptr = & x;.  
  2. Console.WriteLine((int)ptr) // Displays the memory address  
  3. Console.WriteLine(*ptr) // Displays the value at the memory address.   

Unsafe Codes

 
The C# statements can be executed either as in a safe or in an unsafe context. The statements marked as unsafe by using the keyword unsafe runs outside the control of Garbage Collector. Remember that in C# any code involving pointers requires an unsafe context.
 
We can use the unsafe keyword in two different ways. It can be used as a modifier to a method, property, and constructor etc. For example
  1. // Author: rajeshvs@msn.com  
  2. using System;  
  3. class MyClass  
  4. {  
  5.     public unsafe void Method()  
  6.     {  
  7.         int x = 10;  
  8.         int y = 20;  
  9.         int* ptr1 = &x;  
  10.         int* ptr2 = &y;  
  11.         Console.WriteLine((int)ptr1);  
  12.         Console.WriteLine((int)ptr2);  
  13.         Console.WriteLine(*ptr1);  
  14.         Console.WriteLine(*ptr2);  
  15.     }  
  16. }  
  17. class MyClient  
  18. {  
  19.     public static void Main()  
  20.     {  
  21.         MyClass mc = new MyClass();  
  22.         mc.Method();  
  23.     }  
  24. }  
The keyword unsafe can also be used to mark a group of statements as unsafe as shown below.
  1. // Author: rajeshvs@msn.com  
  2. //unsafe blocks  
  3. using System;  
  4. class MyClass  
  5. {  
  6.     public void Method()  
  7.     {  
  8.         unsafe  
  9.         {  
  10.             int x = 10;  
  11.             int y = 20;  
  12.             int* ptr1 = &x;  
  13.             int* ptr2 = &y;  
  14.             Console.WriteLine((int)ptr1);  
  15.             Console.WriteLine((int)ptr2);  
  16.             Console.WriteLine(*ptr1);  
  17.             Console.WriteLine(*ptr2);  
  18.         }  
  19.     }  
  20. }  
  21. class MyClient  
  22. {  
  23.     public static void Main()  
  24.     {  
  25.         MyClass mc = new MyClass();  
  26.         mc.Method();  
  27.     }  
  28. }  

Pinning an Object

 
The C# garbage collector can move the objects in memory as it wishes during the garbage collection process. The C# provides a special keyword fixed to tell Garbage Collector not to move an object. That means this fixes in memory the location of the value types pointed to. This is what is known as pinning in C#.
 
The fixed statement is typically implemented by generating tables that describe to the Garbage Collector, which objects are to remain fixed in which regions of executable code. Thus as long as a Garbage Collector process doesn't actually occur during execution of fixed statements, there is very little cost associated with this. However when a Garbage Collector process does occur, fixed objects may cause fragmentation of the heap. Hence objects should be fixed only when absolutely necessary and only for the shortest amount of time.
 

Pointers & Methods 

 
The points can be passed as an argument to a method as showing below. The methods can also return a pointer.
  1. // Author: rajeshvs@msn.com  
  2. using System;  
  3. class MyClass  
  4. {  
  5.     public unsafe void Method()  
  6.     {  
  7.         int x = 10;  
  8.         int y = 20;  
  9.         int* sum = swap(&x, &y);  
  10.         Console.WriteLine(*sum);  
  11.     }  
  12.     public unsafe int* swap(int* x, int* y)  
  13.     {  
  14.         int sum;  
  15.         sum = *x + *y;  
  16.         return ∑  
  17.     }  
  18. }  
  19. class MyClient  
  20. {  
  21.     public static void Main()  
  22.     {  
  23.         MyClass mc = new MyClass();  
  24.         mc.Method();  
  25.     }  
  26. }  

Pointers & Conversions

 
In C# pointer types do not inherit from object and no conversion exists between pointer types and objects. That means boxing and un-boxing are not supported by pointers. But C# supports conversions between the different pointer types and pointer types and integral types.
 
C# supports both implicit and explicit pointer conversions within un-safe context. The implicit conversions are
  1. From any type pointer type to void * type.
  2. From null type to any pointer type.
The cast operator (()) is necessary for any explicit type conversions. The explicit type conversions are
  1. From any pointer type to any other pointer type.
  2. From sbyte, byte, short, ushort, int, uint, long, ulong to any pointer type.
  3. From any pointer type to sbyte, byte, short, ushort, int, uint, long, ulong types.
For example
  1. char c = 'R';  
  2. char *pc = &c;  
  3. void *pv = pc; // Implicit conversion  
  4. int *pi = (int *) pv; // Explicit conversion using casting operator  

Pointer Arithmetic

 
In an un-safe context, the ++ and - operators can be applied to pointer variable of all types except void * type. Thus for every pointer type T* the following operators are implicitly overloaded.
  1. T* operator ++ (T *x);  
  2. T*operator -- (T *x);  
The ++ operator adds sizeof(T) to the address contained in the variable and - operator subtracts sizeof(--) from the address contained in the variable for a pointer variable of type T*.
 
In an un-safe context a constant can be added or subtracted from a pointer variable. Similarly a pointer variable can be subtracted from another pointer variable. But it is not possible to add two pointer variables in C#.
 
In un-safe context = =, ! =, <, >, < =, > =  operators can be applied to value types of all pointer types. The multiplication and division of a pointer variable with a constant or with another pointer variable is not possible in C#.
 

Stack Allocation 

 
In an unsafe context, a local declaration may include a stack allocation initialiser, which allocates memory from the call stack.
 
The stackalloc T[E] requires T to be an unmanaged type and E to be an expression of type int. The above construct allocates E * sizeof(T) bytes from the call stack and produces a pointer of the type T* to the newly allocated block. The E is negative, a System.OverFlowException is thrown. If there is not enough memory to allocate, a System.StackOverflowException is thrown.
 
The content of newly allocated memory is undefined. There is no way to implicitly free memory allocated using stackalloc. Instead all stack allocated memory block are automatically discarded once the function returns.
  1. class Test  
  2. {  
  3.    char *buffer =  
  4. }  

Pointers & Arrays 

 
In C# array elements can be accessed by using pointer notations.
  1. // Author: rajeshvs@msn.com  
  2. using System;  
  3. class MyClass  
  4. {  
  5.     public unsafe void Method()  
  6.     {  
  7.         int[] iArray = new int[10];  
  8.         for (int count = 0; count < 10; count++)  
  9.         {  
  10.             iArray[count] = count * count;  
  11.         }  
  12.         fixed (int* ptr = iArray)  
  13.             Display(ptr);  
  14.         //Console.WriteLine(*(ptr+2));  
  15.         //Console.WriteLine((int)ptr);   
  16.     }  
  17.     public unsafe void Display(int* pt)  
  18.     {  
  19.         for (int i = 0; i < 14; i++)  
  20.         {  
  21.             Console.WriteLine(*(pt + i));  
  22.         }  
  23.     }  
  24. }  
  25. class MyClient  
  26. {  
  27.     public static void Main()  
  28.     {  
  29.         MyClass mc = new MyClass();  
  30.         mc.Method();  
  31.     }  
  32. }  

Pointers & Structures

 
The structures in C# are value types. The pointers can be used with structures if it contains only value types as its members. For example
  1. // Author: rajeshvs@msn.com  
  2. using System;  
  3. struct MyStruct  
  4. {  
  5.     public int x;  
  6.     public int y;  
  7.     public void SetXY(int i, int j)  
  8.     {  
  9.         x = i;  
  10.         y = j;  
  11.     }  
  12.     public void ShowXY()  
  13.     {  
  14.         Console.WriteLine(x);  
  15.         Console.WriteLine(y);  
  16.     }  
  17. }  
  18. class MyClient  
  19. {  
  20.     public unsafe static void Main()  
  21.     {  
  22.         MyStruct ms = new MyStruct();  
  23.         MyStruct* ms1 = &ms;  
  24.         ms1->SetXY(10, 20);  
  25.         ms1->ShowXY();  
  26.     }  
  27. }