1

I have a 3D array that I allocate in Python and pass to a library I am writing as a type double *. In my C code, I dynamically create a separate 3D array using

double ***coords_mle = (double ***)malloc(num_coords*sizeof(double**));
for (i = 0; i < num_coords; i++) {
    coords_mle[i] = (double **)malloc((end_frame-start_frame+1)*sizeof(double*));
    for (j = 0; j < end_frame-start_frame+1; j++)
        coords_mle[i][j] = (double *)malloc(2*sizeof(double)); }

and fill with values. I am dynamically creating the array because it depends on parameters from my python code. The array in the C library is correctly filled. I've tried to return the array to the double * pointer using either

std::copy(**coords_mle, **coords_mle + 2*3*3, coords_ret); or memcpy(coords_ret, **coords_mle, 2*3*3*sizeof(double));

(2*3*3 are the dimensions of the array). However, what I get back in python has only a few of the values I expect. The rest of the array is filled with other numbers.

What is the best way to return a 3D array from C to python using ctypes?

2 Answers 2

1

I recommend Cython, actually. Ctypes is kind of slow at the python-C boundary, and a bit brittle too. I like to use Ctypes for multi-interpreter code that targets CPython and Pypy, though today perhaps CFFI would be better for that.

You could, if you really want ctypes, you could probably create an array.array('d') that's got the appropriate length (dimx*dimy*dimz), and pass that to your C code via ctypes. array.array is supposed to create contiguous, traditional arrays, so it's likely to work.

Sign up to request clarification or add additional context in comments.

Comments

1

You aren't returning a 3-dimensional C array. That would be done with a single, contiguous allocation:

#include <stdlib.h>

double *test(int ni, int nj, int nk)
{
    int i, j, k;
    size_t n, njk, nijk;
    njk = nj * nk;
    nijk = ni * njk;
    double *result = (double *)malloc(nijk * sizeof(double));
    for (i = 0; i < ni; i++)
        for (j = 0; j < nj; j++)
            for (k = 0; k < nk; k++) {
                n = i * njk + j * nk + k;
                *(result + n) = n;
            }
    return result;
}

Then in Python you'd cast the result to the desired array dimensions:

from ctypes import *

lib = CDLL('./lib.so')
lib.test.restype = POINTER(c_double)
lib.test.argtypes = [c_int, c_int, c_int]

r = lib.test(2, 2, 2)
a = cast(r, POINTER(((c_double * 2) * 2) * 2))[0]

>>> [[a[i][j][:] for j in range(2)] for i in range(2)]
[[[0.0, 1.0], [2.0, 3.0]], [[4.0, 5.0], [6.0, 7.0]]]

More idiomatic:

>>> [[row[:] for row in grid] for grid in a]
[[[0.0, 1.0], [2.0, 3.0]], [[4.0, 5.0], [6.0, 7.0]]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.