I need to convert a double array in c# to an IntPtr to properly send it to my c DLL. I have successfully been able to convert from IntPtr to double[,] using the method from this answer. Ive also found another answer that is close to what I need but deals with 1D arrays.
Im missing something in my logic and get the error code after a crash: Managed ' has exited with code -1073740940 (0xc0000374).
This is what I have so far
IntPtr p = Marshal.AllocHGlobal(rows * columns);
for (int i = 0; i < rows; i++) //rows
{
double[] temp = new double[columns];
for (int x = 0; x < columns; x++)
temp[x] = input.cells[i, x];
Marshal.Copy(temp, 0, p, columns);
p = (IntPtr)(p.ToInt64() + IntPtr.Size);
}
toReturn.cells = p;
Marshal.FreeHGlobal(p);
return toReturn;
toReturn.cells is my IntPtr inside a struct that I return. cells is structured as cells[rows, columns]
IntPtr's are still very new to me.
Edit: thanks to harold. their suggestions worked beautifully
There are various things wrong with that.
First,
rows * columnsis not the size of the data, it's only the total number of elements. The elements are not one byte each, but eight, orsizeof(double)if you prefer.Second,
pis updated byp = (IntPtr)(p.ToInt64() + IntPtr.Size);(ie advancing it by 4 or 8 bytes depending on how big pointers are in the current mode), but you've writtencolumns * 8(or,columns * sizeof(double)) bytes of data. Advancingpby less thancolumns * 8makes the writes overwrite each other, so not all data ends up in the result. By the way, the complicated conversions here are actually not necessary, you can add directly to anIntPtr, since .NET 4.Third,
pis changed in the loop, which is not bad on its own, but it's done in a way that loses track of the original pointer.toReturn.cells = p;andMarshal.FreeHGlobal(p);use apwhich does not refer to the area that you allocated, they use apwhich now points just past the end of the data (well it would point there ifpwas updated by the right amount). The originalpmust be remembered.Fourth, freeing the data before returning means that it now no longer exists, so whatever code this data is passed to, still doesn't have it: it has a pointer to nothing which will be invalid to use (it may accidentally work, but it's dangerous and wrong).
The first three points are easy to fix, but the last one needs a non-local change to how your application works: the memory cannot be freed here, but it should be freed at some point, namely when the user of the data is done with it.
Some fixes applied:
Keep in mind you should still free the memory at the appropriate time.