See the question and my original answer on StackOverflow

There are multiple ways to return arrays, but in all cases you must solve two problems:

  • be able to tell .NET the count of items in the array;
  • use a common memory allocator for the native and .NET Size. The allocator of choice is the COM allocator as it's known to .NET;

Here are two examples using .NET safe code:

Native code 1:

extern __declspec(dllexport) SAFEARRAY * sumSafeArray()
{
    int a = 50, b = 80, sum, neg;
    sum = a + b;
    neg = b - a;
    int arr[2] = { sum, neg };

    // SAFEARRAY is a OLE/COM automation type well known to Windows and .NET
    // (note it implicitly uses the COM allocator too)
    SAFEARRAY* psa = SafeArrayCreateVector(VT_I4, 0, 2);
    void* data;
    SafeArrayAccessData(psa, &data);
    CopyMemory(data, arr, sizeof(arr));
    SafeArrayUnaccessData(psa);
    return psa;
}

Managed code 1:

[DllImport("mydll")]
[return: MarshalAs(UnmanagedType.SafeArray)]
private static extern int[] sumSafeArray();

foreach (var i in sumSafeArray())
{
    Console.WriteLine(i);
}

Native code 2:

extern __declspec(dllexport) void sumArray(int** out, int* count)
{
    int a = 50, b = 80, sum, neg;
    sum = a + b;
    neg = b - a;
    int arr[2] = { sum, neg };

    // always use COM allocator
    *out = (int*)CoTaskMemAlloc(sizeof(arr));
    CopyMemory(*out, arr, sizeof(arr));
    *count = sizeof(arr) / sizeof(int);
}

Managed code 2:

[DllImport("mydll")]
private static extern void sumArray(out IntPtr array, out int size);

sumArray(out var ptr, out var size);
var ints = new int[size];
Marshal.Copy(ptr, ints, 0, size);
Marshal.FreeCoTaskMem(ptr);
foreach (var i in ints)
{
    Console.WriteLine(i);
}

And one example using .NET unsafe code:

Native code:

extern __declspec(dllexport) int* sum(int* count)
{
    int a = 50, b = 80, sum, neg;
    sum = a + b;
    neg = b - a;
    int arr[2] = { sum, neg };

    // always use COM allocator
    int* out = (int*)CoTaskMemAlloc(sizeof(arr));
    CopyMemory(out, arr, sizeof(arr));
    *count = sizeof(arr) / sizeof(int);
    return out;
}

Managed code:

[DllImport("mydll")]
private unsafe static extern int* sum(out int count);

var ints = sum(out var count);
for (var i = 0; i < count; i++)
{
    Console.WriteLine(*ints);
    ints++;
}

You could also use another allocator (new/malloc/custom, etc.) but in this case you would need to expose/export to .NET the corresponding "free" method and do the free yourself when needed.