What is the correct way to pass a numpy 2d – array to a c function using ctypes ? My current approach so far (leads to a segfault):
C code :
void test(double **in_array, int N) { int i, j; for(i = 0; i<N; i++) { for(j = 0; j<N; j++) { printf("%e t", in_array[i][j]); } printf("n"); } }
Python code:
from ctypes import * import numpy.ctypeslib as npct array_2d_double = npct.ndpointer(dtype=np.double,ndim=2, flags='CONTIGUOUS') liblr = npct.load_library('libtest.so', './src') liblr.test.restype = None liblr.test.argtypes = [array_2d_double, c_int] x = np.arange(100).reshape((10,10)).astype(np.double) liblr.test(x, 10)
Advertisement
Answer
This is probably a late answer, but I finally got it working. All credit goes to Sturla Molden at this link.
The key is, note that double**
is an array of type np.uintp
. Therefore, we have
xpp = (x.ctypes.data + np.arange(x.shape[0]) * x.strides[0]).astype(np.uintp) doublepp = np.ctypeslib.ndpointer(dtype=np.uintp)
And then use doublepp
as the type, pass xpp
in. See full code attached.
The C code:
// dummy.c #include <stdlib.h> __declspec(dllexport) void foobar(const int m, const int n, const double **x, double **y) { size_t i, j; for(i=0; i<m; i++) for(j=0; j<n; j++) y[i][j] = x[i][j]; }
The Python code:
# test.py import numpy as np from numpy.ctypeslib import ndpointer import ctypes _doublepp = ndpointer(dtype=np.uintp, ndim=1, flags='C') _dll = ctypes.CDLL('dummy.dll') _foobar = _dll.foobar _foobar.argtypes = [ctypes.c_int, ctypes.c_int, _doublepp, _doublepp] _foobar.restype = None def foobar(x): y = np.zeros_like(x) xpp = (x.__array_interface__['data'][0] + np.arange(x.shape[0])*x.strides[0]).astype(np.uintp) ypp = (y.__array_interface__['data'][0] + np.arange(y.shape[0])*y.strides[0]).astype(np.uintp) m = ctypes.c_int(x.shape[0]) n = ctypes.c_int(x.shape[1]) _foobar(m, n, xpp, ypp) return y if __name__ == '__main__': x = np.arange(9.).reshape((3, 3)) y = foobar(x)
Hope it helps,
Shawn