How to pass List<DoubleArray> to C function with "double**" signature?

Hi everybody!

NOTE: I will have to use [,] for type information instead of <> in the post because ‘>’ seems to break the formatting in weird way (probably HTML escaping bug).

I have the C function like ‘void fun(double** myArray)’. I have a List[DoubleArray] in Kotlin that represents a matrix of doubles.

I can’t convert that List to the data structure required by CInterop: CValuesRef[CPointerVar [DoubleVar]]

I have read the documentation but something just doesn’t click.

Like, how do I convert each DoubleArray to CPointerVar[DoubleVar]? DoubleArray.toCValues() seems to return different types.

And if I somehow manage to do that, how do I convert the list/array of CPointerVar[DoubleVar] to CValuesRef[CPointerVar[DoubleVar]]?

Hope it is something obvious that I missed.

Try formating the code in your post. You can add ` at the start and end of each code segment to format it. If you use 3 on a single line you get a code block. That way <> should work fine.

The problem is that objects (including arrays) are in general not safe to pass by reference to C functions. Usually, Kotlin may move or garbage collect objects at any time. However if the objects are passed to C code, then Kotlin has no chance of knowing when it is safe to move or collect the objects. Thus you, as the programmer, need to come up with a strategy to make the objects safe to use by the C code. You have the following options:

  1. Copy the objects into native memory and deallocate it afterwards. The documentation has examples of how to do that.
  2. Pin the objects in place for the duration they are used by the C function
  3. When calling a function that takes a CValuesRef, then you also have the option of copying a List or Array onto the stack using the toCValues extension. This copy will be deallocated once the function returns, so it may only be used if the C function does not use the pointer after returning.

In your particular example, you have to do something both for the inner arrays, and the outer array. The inner arrays can be handled using either option 1 or 2. The outer array can be handled using either option 1 or 3.

Below is an example of one way to solve it. It handles the inner arrays by pinning them, while the outer array is passed by value using toCValues. Note that the solution assumes that the C function does not use any of the pointers after returning.

val sourceList : List<DoubleArray> = /*..*/
val pinnedList : MutableList<Pinned<DoubleArray>> = mutableListOf()
try {
  sourceList.forEach { pinnedList.add(it.pin()) } // If an exception is thrown after pin() returns but before add() returns, then a memory leak might occur. Not sure how to avoid this problem entirely
  externalFunction(pinnedList.map{ it.addressOf(0) }.toCValues())
} finally {
  pinnedList.forEach { it.unpin() }
}