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.
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
).
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
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 | 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. |
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.
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
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
See: