You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++传递数组到C#时arrayPtr为null引发Marshal.Copy报错问题求解

问题原因

你的代码存在3个核心错误,直接导致指针返回null和后续潜在崩溃:

  • C++侧函数参数是值传递的int*,函数内修改arrayPtr只会改动函数栈上的局部副本,根本不会把地址回传给外层调用方,这是C#拿到空指针的直接原因
  • C++函数内定义的int array[] = {1,2}是栈上局部变量,函数返回时对应栈帧直接销毁,就算指针传递正确,拿到的也是指向已回收内存的野指针,读取时会出现脏数据或访问违例
  • C#侧Marshal.Copy的最后一个参数是待复制的元素个数,不是字节总长度,你传入计算出的字节数会导致内存拷贝越界

可行修复方案

方案1:C++侧分配堆内存回传(适合数组长度动态变化的场景)

需要修改C++侧参数为二级指针用于回传数组地址,配套内存释放接口避免泄漏,代码如下:

C++头文件定义

extern "C" GMSH_API void GMSH_Model_OCC_Fragments(int** outArrayPtr, int* outArrayLen);
extern "C" GMSH_API void GMSH_Free_Array(int* arrayPtr);

C++实现代码

void GMSH_Model_OCC_Fragments(int** outArrayPtr, int* outArrayLen)
{
    *outArrayLen = 2;
    // 必须在堆上分配数组内存,不能使用栈上局部变量
    int* heapArray = new int[2]{1, 2};
    *outArrayPtr = heapArray;
}

void GMSH_Free_Array(int* arrayPtr)
{
    // 配套释放C++侧new出来的数组内存
    delete[] arrayPtr;
}

C#侧调用代码

[DllImport("GMSHCSHARP.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GMSH_Model_OCC_Fragments(out IntPtr arrayPtr, out int arrayLen);
[DllImport("GMSHCSHARP.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GMSH_Free_Array(IntPtr arrayPtr);     
    
public void Create()
{
    IntPtr arrayPtr = IntPtr.Zero;
    int arrayLen = 0;
    GMSH_Model_OCC_Fragments(out arrayPtr, out arrayLen);
    try
    {
        int[] returnArray = new int[arrayLen];
        // 最后一个参数直接传元素个数,不需要计算字节长度
        Marshal.Copy(arrayPtr, returnArray, 0, arrayLen);
        // 此处可正常使用returnArray
    }
    finally
    {
        if (arrayPtr != IntPtr.Zero)
        {
            GMSH_Free_Array(arrayPtr);
        }
    }
}

方案2:C#侧预分配数组传入(适合数组长度固定的场景)

不需要来回传指针、手动拷贝内存,实现更简单,也没有内存泄漏风险:

C++实现代码

extern "C" GMSH_API void GMSH_Model_OCC_Fragments(int* outArray, int arrayLen);

void GMSH_Model_OCC_Fragments(int* outArray, int arrayLen)
{
    // 需保证传入的数组长度足够容纳要写入的数据
    outArray[0] = 1;
    outArray[1] = 2;
}

C#侧调用代码

[DllImport("GMSHCSHARP.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GMSH_Model_OCC_Fragments(int[] outArray, int arrayLen);     
    
public void Create()
{
    int[] returnArray = new int[2];
    GMSH_Model_OCC_Fragments(returnArray, returnArray.Length);
    // 调用完成后returnArray直接拿到{1,2},可直接使用
}

注意事项
  • 禁止返回C++函数内栈上局部变量的地址,函数退出后栈内存自动回收,指针会失效
  • 要跨层回传指针时,C++侧必须使用二级指针接收参数,值传递的指针无法把地址写回外层
  • 不要用Marshal.FreeHGlobal释放C侧通过new分配的内存,二者内存堆不匹配,必须调用C侧配套的释放接口

内容的提问来源于stack exchange,提问作者Aris Theo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 01:57:22