Revision

Back to C#


Pointers

Unsafe mode

Pointers can be used in C# in unsafe mode.
C# code is generally verifiably safe code.

Microsoft defines safe code as follow:
Verifiably safe code means .NET tools can verify that the code is safe. In general, safe code doesn’t directly access memory using pointers. It also doesn’t allocate raw memory. It creates managed objects instead.

As said previously, pointers can be used in C# in unsafe mode.
unsafe code should either be included in a block:

  unsafe
  {
    //Your code
  }

or the a function can call unsafe code if it uses the keyword unsafe:

  static unsafe void myFunction(int* myInt, float* myFloat){
    // Function definition
  }

Also to use unsafe code in your project you must activate unsafe code compilation in your project parameters.


Pointers declaration

  int* p; // p is a pointer to an integer
  int** p; // p is a pointer to a pointer to an integer
  int*[] p; // p is a single-dimensional array of pointers to integers
  char* p; // p is a pointer to a char
  void* p; // p is a pointer to an unknown type

As a pointer points to a memory slot, you should assign it the memory adress of a variable. You access the memory adress of a variable using &:

  int* pi;
  int i = 1, int j = 2;

  pi = &i; // pi is a pointer to the adress of i
  int* pj = &j; // pj is a pointer to the adress of j

Once a pointer points to the memory adress of a variable, modifying the value stored at this adress will also modify the variable value (ie if you modify *pi - the value store where pi points - you will modify i).


Access

You can then access the value stored at the adress of your pointer using * (*p for a pointer p):

  int i = 1;
  int* pi = &i;
  Console.WriteLine(*pi); // Output: 1

  *pi = *pi + 1;
  Console.WriteLine(*pi); // Output: 2
  Console.WriteLine(i); // Output: 2

Fixed

You can block a pointer adress value using fixed. You assign the pointers value using fixed and then apply code in this fixed statement. Using this if you copy this pointer to another pointer and change the location of this second pointer, the first one will not be impacted:

  int[] a = new int[2] { 1, 2 };
  unsafe
  {
    fixed (int* p = &a[0])
    {
      int* p2 = p;
      Console.WriteLine(*p2); // Output: 1
      p2 += 1; // move memory pointed by p2 (by four bytes)
      Console.WriteLine(*p2); // Output: 2 - p2 now points to the second element of the list

      Console.WriteLine(*p); // Output: 1 - p1 still points to the first element of the list
      *p += 10;
      Console.WriteLine(*p) // Output: 11
      Console.WriteLine(a[0]) // Output: 11
    }
  }


Operator/Statement

Operator/Statement Use
* Performs pointer indirection.
-> Accesses a member of a struct through a pointer.
[] Indexes a pointer.
& Obtains the address of a variable.
++ and -- Increments and decrements pointers
+ and - Performs pointer arithmetic.
==, !=, <, >, <=, and >= Compares pointers.
stackalloc Allocates memory on the stack.
fixed statement Temporarily fixes a variable so that its address may be found.


C# Reference

Passing an argument by reference

When used on a method’s parameter, the ref keyword indicates that the argument is passed by reference, not by value. Any operation on the parameter is made on the argument (from Microsoft documentation on Reference).


To use a ref parameter, both the method definition and the calling method must explicitly use the ref keyword:

  void MethodRef(ref int argumentRef){
    argumentRef += 44;
  }

  int number = 1;
  MethodRef(ref number);
  Console.WriteLine(number); // Output: 45


You can also overload a method using the ref keyword:

  public void SampleMethod(int i) { }
  public void SampleMethod(ref int i) { }

However a method can’t have signatures that differ only by ref, in, or out.


ref, out and in

out

From Microsoft documentation on out: out is like the ref keyword, except that ref requires that the variable be initialized before it is passed.
To use an out parameter, both the method definition and the calling method must explicitly use the out keyword:

  void MethodOut(out int argumentOut){
    argumentOut = 44;
  }

  int number; // no need to initialized number
  MethodOut(out number);
  Console.WriteLine(number); // Output: 44


in

From Microsoft documentation on in: in is like the ref or out keywords, except that in arguments cannot be modified by the called method.

  void MethodIn(in int argumentIn){
    // Uncomment the following line to see error CS8331
    // argumentIn = 45;
  }
  int number = 44;
  MethodIn(number); // Do not (can't) modify number


Source

See: