greenoldman
greenoldman

Reputation: 21072

How to get a pointer to memory of Array instance?

There are many examples over the net how to get pointer to byte[] or int[,], i.e. when you know exactly the element type and rank of the array. But how to get the pointer for generic Array?

The main problem here is I don't know rank in the advance. I don't know element type too but I know there can be only primitive numeric type (in my case), so I could type few extra ifs to cope with it.

Background: I would like to make this solution https://stackoverflow.com/a/52750659/6734314 more general -- in its current form it works only with double[,] so classic rank+type is given:

double[,] doubles =  {
     { 1, 2, 3, 4 },
     ...
};
fixed (double* p = doubles)
{
  ...

First attempt

From Olivier answer, all mistakes are mine.

Array data = new float[,] { { 4, 2 }, { 77, 3 } };
var reference = __makeref(data);
IntPtr pointer = **(IntPtr**)(&reference);

float* ptr = (float*)pointer.ToPointer();
{
  for (int i = 0; i < data.LongLength; ++i)
    Console.WriteLine(ptr[i]);
}

Upvotes: 1

Views: 1261

Answers (3)

greenoldman
greenoldman

Reputation: 21072

I think I found it, please comment if you found something too fragile/suspicious:

Array data = new float[,] { { 4, 2 }, { 77, 3 } };
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
  IntPtr address = handle.AddrOfPinnedObject();

  float* ptr = (float*)address.ToPointer();
  for (int i = 0; i < data.LongLength; ++i)
    Console.WriteLine(ptr[i]);
}
finally
{
  handle.Free();
}

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062895

If the data is always the same shape (for example, 2D rectangular array), but potentially different types, then you can perhaps use the T : unmanaged constraint and the fixed keyword:

    static void Main()
    {
        // sample taken from comtrade91.pdf section 6.6
        var data = new float[,] { { 4, 2 }, { 77, 3 } };
        ShowAddressAndData(data);
    }
    static unsafe void ShowAddressAndData<T>(T[,] data) where T : unmanaged
    {
        fixed(T* ptr = data)
        {
            Console.WriteLine((IntPtr)ptr);
            for (int i = 0; i < data.Length; i++)
            {
                Console.WriteLine(ptr[i]);
            }
        }
    }
    // this extra method just to show that we can overload on dimension
    static unsafe void ShowAddressAndData<T>(T[] data) where T : unmanaged
    {
        fixed (T* ptr = data)
        {
            Console.WriteLine((IntPtr)ptr);
            //..
        }
    }

Upvotes: 2

user12031933
user12031933

Reputation:

Combining:

Memory address of an object in C#

And

How can I display a pointer address in C#?

Writing:

Array array = Array.CreateInstance(typeof(int), 10);
unsafe
{
  var reference = __makeref(array);
  var pointer = **(IntPtr**)( &reference );
  Console.WriteLine("0x{0:x}", (ulong)&reference);
  Console.WriteLine("0x{0:x}", (long)&reference);
  Console.WriteLine("0x{0:x}", (ulong)pointer);
  Console.WriteLine("0x{0:x}", (long)pointer);
}

Outputs:

0x8cb87af070
0x8cb87af070
0x1a9c1c46290
0x1a9c1c46290

Source code of Array class

Upvotes: 2

Related Questions