将 double[,] 转换为 IntPtr C#

6se*_*ine 3 c# double intptr

我需要将 c# 中的双数组转换为 IntPtr 以将其正确发送到我的 c DLL。我已经成功地使用这个答案中的方法从IntPtr 转换为 double[,] 。我还找到了另一个接近我需要但处理一维数组的答案

我在我的逻辑中遗漏了一些东西并在崩溃后得到错误代码:Managed ' has exited with code -1073740940 (0xc0000374)。

这是我到目前为止

            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;
Run Code Online (Sandbox Code Playgroud)

toReturn.cells 是我返回的结构内的 IntPtr。单元格的结构为单元格[行,列]

IntPtr 对我来说仍然很陌生。

编辑:感谢哈罗德。他们的建议效果很好

har*_*old 5

有各种各样的问题。

首先,rows * columns不是数据的大小,它只是元素的总数。每个元素不是一个字节,而是八个,或者sizeof(double)如果您愿意的话。

其次,p更新为p = (IntPtr)(p.ToInt64() + IntPtr.Size);(即,根据当前模式下指针的大小,将其推进 4 或 8 个字节),但您已写入columns * 8(或,columns * sizeof(double))字节的数据。推进p小于columns * 8使写入相互覆盖,因此并非所有数据最终都会出现在结果中。顺便说一句,这里复杂的转换实际上是不必要的,您可以直接添加到IntPtr.NET 4 中。

第三,p在循环中被改变,这本身就不错,但它以一种失去原始指针跟踪的方式完成。toReturn.cells = p;Marshal.FreeHGlobal(p);使用p不引用您分配的区域的 a ,他们使用 ap现在指向数据末尾(如果p更新了正确的数量,它将指向那里)。p必须记住原文。

第四,在返回之前释放数据意味着它现在不再存在,所以无论这个数据传递给什么代码,仍然没有它:它有一个指向无效的指针(它可能会意外地工作,但是这是危险和错误的)。

前三点很容易解决,但最后一点需要对应用程序的工作方式进行非本地更改:内存不能在这里释放,但应该在某个时刻释放,即当数据的用户完成时用它。

应用了一些修复:

        int stride = columns * sizeof(double);
        IntPtr p = Marshal.AllocHGlobal(rows * stride);
        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 + stride * i, columns);
        }

        toReturn.cells = p;
        return toReturn;
Run Code Online (Sandbox Code Playgroud)

请记住,您仍应在适当的时候释放内存。