2015-12-22 9 views
4

Почему я не могу нарисовать массив массивов в C# до Указатель на указатель?«Массив массивов» на «указатель на указатель» на C#

public int WriteAudio(short[][] audio, uint num_channels, uint channel_len) 
{ 
    int ret = 0; 
    unsafe 
    { 
     fixed (short** d = audio) // Compiler complains about this 
     { 
      ret = MyCppDLL.WriteDeinterlacedAudio(d, num_channels, channel_len); 
     } 
    } 
    return ret; 
} 

Я знаю, возможно следующее:

public int WriteAudio(short[] audio, uint num_channels, uint channel_len) 
{ 
    int ret = 0; 
    unsafe 
    { 
     fixed (short* d = audio) // No complaints here 
     { 
      ret = MyCppDLL.WriteInterlacedAudio(d, num_channels, channel_len); 
     } 
    } 
    return ret; 
} 

Спасибо!

+0

Почему вы не можете использовать 'Collection' или многомерный массив? – Greg

+0

Функция: 'MyCppDLL.WriteDeinterlacedAudio()' находится в DLL-оболочке C++. Я не думаю, что может быть запущен «Collection» или многомерный массив, не так ли? – savetruman

+0

Я думаю, что у вас может быть только массив указателей .. не указатели указателей ... см. Это, если это помогает: http://www.tutorialspoint.com/cprogramming/c_array_of_pointers.htm – MaxOvrdrv

ответ

2

Функция: MyCppDLL.WriteDeinterlacedAudio() находится в C++ обертку DLL. Я не думаю, что коллекция или многомерный массив могут быть отлиты , не так ли?

Это может, но нужно немного потрудиться.

Поскольку short[][] является массив массивов и так unsafe кода поддерживает максимум 1 «преобразование» из массива-указатель в то время в C#, то лучшее, что вы можете сделать это, чтобы преобразовать его в массив указателей первый перед преобразованием его в указатель указателей

Короче говоря, вам нужно сделать: массив массивов -> массив указателей -> указатель указателей

Редактировать: Я решил поставить эту заметку после комментария г-на д-ра, пожалуйста, обратитесь к его объяснениям и коду. Идея выше заключается в преобразовании массива массивов в массив указателей перед преобразованием в указатель на указатели все еще можно использовать. Но как это сделать безопасно, обратитесь к его более полному ответу.

Что-то вроде этого:

public int WriteAudio(short[][] audio, uint num_channels, uint channel_len) { 
    int ret = 0; 
    unsafe { 
      fixed (short* d = &audio[0][0]) //pointer to the address of first element in audio 
      { 
       short*[] arrOfShortPtr = new short*[audio.Length]; //here is the key!! really, this is now array of pointers! 
       for (int i = 0; i < arrOfShortPtr.Length; ++i) { 
        fixed (short* ptr = &audio[i][0]) { 
         arrOfShortPtr[i] = ptr; //like magic, casting from array of arrays to array of pointers 
        } 
       } 
       fixed (short** ptrOfPtr = &arrOfShortPtr[0]) { //now it is fine... second casting from array of pointers to pointer of pointers 
        //do what you want 
       } 
      } 
     } 
     return ret; 
    } 
+0

Этот ответ содержит ошибку. После того, как цикл 'for' завершен,' arrOfShortPtr' содержит указатели на нефиксированную память, и GC может перераспределить эту память в любой момент. – drf

+0

Я обновил свой ответ и расскажу о том, как безопасно это сделать для вашего кода и объяснений. – Ian

2

Чтобы использовать двойной указатель, вы можете получить фиксированный указатель на каждый элемент массива, поместить каждый элемент в новый массив double* с, и зафиксируем указатель на что массив, чтобы получить желаемое double**:

GCHandle[] handles = null; 
try 
{ 
    handles = audio 
     .Select((z, j) => GCHandle.Alloc(audio[j], GCHandleType.Pinned)) 
     .ToArray(); 

    double*[] audioPtr = new double*[audio.Length]; 
    for (int j = 0; j < audioPtr.Length; j++) 
     audioPtr[j] = (double*)handles[j].AddrOfPinnedObject(); 

    fixed (double** z = audioPtr) 
    { 
     // call extern method here 
    } 
} 
finally 
{ // unpin the memory 
    foreach (var h in handles) 
    { 
     if (h.IsAllocated) h.Free(); 
    } 
} 

Обратите внимание, что принятый ответ на Converting from a jagged array to double pointer in C# представляет подобную ситуацию, но принял ответ неверен. Другой ответ на этот вопрос использует ту же неверную методику:

for (int i = 0; i < array.Length; i++) 
    fixed (double* ptr = &array[i][0]) 
    { 
     arrayofptr[i] = ptr; 
    } 

fixed (double** ptrptr = &arrayofptr[0]) 
{ 
    //whatever 
} 

Не делай этого! Указатель *ptr задан в фиксированном контексте, но используется вне фиксированного контекста как элемент адреса в arrayofptr. После завершения блока fixed GC может свободно перераспределять память, после чего *ptr может указывать на другой объект. Ответ выше предотвращает эту возможность, используя GCHandle для выделения фиксированного указателя, гарантируя, что отдельные элементы в audio не будут перемещены в памяти до тех пор, пока не завершится нативный вызов.

+0

Спасибо за этот ответ! Выглядит хорошо. Сейчас это время отпуска, но я попробую, как только смогу, и в этот момент пометить ответ как принятый. – savetruman

 Смежные вопросы

  • Нет связанных вопросов^_^