A pointer is a variable that points to the address of another variable. In other words, a pointer holds the memory address of another variable or a memory location. Until recently, the only way to work with pointers in C# was by using unsafe code. You could take advantage of the
unsafe keyword to define an unsafe context and then create unmanaged pointers or invoke native functions using unmanaged pointers.
It should be noted here that unsafe code implies code that is executed outside of the context of the CLR. It is unmanaged code. However, since you are turning off the safety provided by the CLR by default, it is advisable that you use unsafe code only if you are aware of how memory management works in .Net.
An object reference in C# is a type-safe pointer that points to the beginning of an object. There is another type of pointer in the CLR known as a managed pointer. This article examines what managed pointer are, why they are useful, and how we can work with them in C#.
Managed pointers in C# explained
A managed pointer differs from a type-safe pointer in being able to point to other locations of an object, i.e., not just the beginning of the object. Like an object reference, a managed pointer can point to objects stored in the managed heap. The difference is that, while an object reference points to the beginning of the object, a managed pointer can point to method parameters, fields, array elements, or any other part of the object.