开发者

Best way to convert int[][] to int**?

This is kind of a curiosity question. I do have an existing solution, but I wonder if people know of a better approach.

My callers want to call me with int[][]. I have a routine that needs to process an int**. Wha开发者_开发知识库t's the best way to do this conversion? In other words:

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

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

Following is the best approach I could come up with. It works fine, but I can't say I'm 100% happy with the recursive approach (and the O(data.Length) stack space it requires)

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]);
    }
  }
}


There's no need to copy the whole array. You can create an array of pointers (i.e. IntPtr[]), and then cast that to int**. It's not pretty, and I wouldn't suggest doing it. But it can be done. The code below shows how.

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();
    }
}


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];
                }
            }
        }

This works but uses unmanaged memory, and there is no recursion, is that valid ?


You can do it with O(1) stack space, if you are willing to copy all the data into another buffer:

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);
    }
  }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜