将int [] []转换为int **的最佳方法?

时间:2011-07-15 20:44:34

标签: c#

这是一个好奇的问题。我确实有一个现有的解决方案,但我想知道人们是否知道更好的方法。

我的来电者想用int [] []给我打电话。我有一个需要处理int **的例程。这种转换的最佳方法是什么?换句话说:

public static void Func1(int[][] data) {
  Func2(data); //how to do this?
}

private unsafe static void Func2(int** data) {
  //process data
}

以下是我能想到的最佳方法。它工作正常,但我不能说我对递归方法(以及它需要的O(data.Length)堆栈空间)100%满意。

public static void Main() {
  var test=new[] {
    new [] {10},
    new [] {20,30},
    new [] {40,50,60},
    new [] {70,80,90,100},
  };
  MySolution_Func1(test);
}

public unsafe static void MySolution_Func1(int[][] data) {
  var items=new int*[data.Length];
  Recurse(0, data, items);
}

public unsafe static void Recurse(int index, int[][] data, int*[] build) {
  if(index==data.Length) {
    fixed(int** finalp=build) {
      Func2(finalp);
    }
  } else {
    fixed(int* nextp=data[index]) {
      build[index]=nextp;
      Recurse(index+1, data, build);
    }
  }
}

private unsafe static void Func2(int** data) {
  for(var j=0; j<4; ++j) {
    for(var i=0; i<j+1; ++i) {
      Debug.WriteLine("{0},{1}: {2}", j, i, data[j][i]);
    }
  }
}

3 个答案:

答案 0 :(得分:0)

public unsafe void ConvertToNative(int[][] jarray, out int** ptr)
        {

            ptr= (int**)Marshal.AllocHGlobal(jarray.Length*sizeof(int));

            for (int i = 0; i < jarray.Length; i++)
            {
                *(ptr+i) = (int*)Marshal.AllocHGlobal(jarray[i].Length*sizeof(int));
                for (int j = 0; j < jarray[i].Length; j++)
                {
                    (*(i + ptr))[j] = jarray[i][j];
                }
            }
        }

这可以工作但是使用非托管内存,并且没有递归,这是否有效?

答案 1 :(得分:0)

无需复制整个阵列。您可以创建一个指针数组(即IntPtr[]),然后将其转换为int**。它不漂亮,我不建议这样做。但这是可以完成的。下面的代码显示了如何。

int[][] myArray = new int[10][];
for (int i = 0; i < 10; ++i)
{
    int[] x = new int[10];
    for (int j = 0; j < 10; ++j)
    {
        x[j] = 10 * i + j;
    }
    myArray[i] = x;
}

// Output the array
Console.WriteLine("int[][]");
for (int i = 0; i < 10; ++i)
{
    for (int j = 0; j < 10; ++j)
    {
        Console.Write("{0}, ", myArray[i][j]);
    }
    Console.WriteLine();
}

// Convert to int*[]
unsafe
{
    GCHandle[] handles = new GCHandle[10];
    IntPtr[] ArrayOfPointer = new IntPtr[10];
    for (int i = 0; i < 10; ++i)
    {
        handles[i] = GCHandle.Alloc(myArray[i], GCHandleType.Pinned);
        ArrayOfPointer[i] = handles[i].AddrOfPinnedObject();
    }
    // Okay, let's output that
    Console.WriteLine("int*[]");
    for (int i = 0; i < 10; ++i)
    {
        int* p = (int*)ArrayOfPointer[i];
        for (int j = 0; j < 10; ++j)
        {
            Console.Write("{0}, ", *p);
            ++p;
        }
        Console.WriteLine();
    }

    // now convert to int**
    GCHandle bigHandle = GCHandle.Alloc(ArrayOfPointer, GCHandleType.Pinned);
    int** ppInt = (int**)bigHandle.AddrOfPinnedObject();

    // and output it
    Console.WriteLine("int**");
    int** pa = ppInt;
    for (int i = 0; i < 10; ++i)
    {
        int* p = *pa;
        for (int j = 0; j < 10; ++j)
        {
            Console.Write("{0}, ", *p);
            ++p;
        }
        Console.WriteLine();
        ++pa;
    }

    // Need to free the handles
    bigHandle.Free();
    for (int i = 0; i < 10; ++i)
    {
        handles[i].Free();
    }
}

答案 2 :(得分:0)

如果您愿意将所有数据复制到另一个缓冲区,可以使用O(1)堆栈空​​间:

public unsafe static void AlternateSolution_Func1(int[][] data) {
  var buffer=new int[data.Sum(a => a.Length)];
  fixed(int* pBuffer=buffer) {
    var items=new int*[data.Length];
    int count=0;
    for(int i=0; i<data.Length; ++i) {
      items[i]=pBuffer+count;
      var array=data[i];
      for(int j=0; j<array.Length; ++j) {
        pBuffer[count++]=array[j];
      }
    }
    fixed(int** pItems=items) {
      Func2(pItems);
    }
  }
}