使用ctypes将2d numpy数组传递给c

使用ctypes将numpy 2d – 数组传递给ac函数的正确方法是什么? 到目前为止我的当前方法(导致段错误):

c代码:

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代码:

 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) 

这可能是一个迟到的答案,但我终于得到了它的工作。 所有功劳都归功于Sturla Molden的链接 。

关键是,请注意, double**np.uintp类型的数组。 因此,我们有

 xpp = (x.ctypes.data + np.arange(x.shape[0]) * x.strides[0]).astype(np.uintp) doublepp = np.ctypeslib.ndpointer(dtype=np.uintp) 

然后使用doublepp作为类型,传递xpp 。请参阅附加的完整代码。

C代码:

 // dummy.c #include  __declspec(dllexport) void foobar(const int m, const int n, const double **x, double **y) { size_t i, j; for(i=0; i 

Python代码:

 # 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) 

希望能帮助到你,

肖恩

 #include  void test(double (*in_array)[3], 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"); } } int main(void) { double a[][3] = { {1., 2., 3.}, {4., 5., 6.}, {7., 8., 9.}, }; test(a, 3); return 0; } 

如果你想在函数中使用double ** ,你必须将指针数组传递给double(不是2d数组):

 #include  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"); } } int main(void) { double a[][3] = { {1., 2., 3.}, {4., 5., 6.}, {7., 8., 9.}, }; double *p[] = {a[0], a[1], a[2]}; test(p, 3); return 0; } 

另一个(由@eryksun建议):传递一个指针并做一些算术来获取索引:

 #include  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 * N + j]); } printf("\n"); } } int main(void) { double a[][3] = { {1., 2., 3.}, {4., 5., 6.}, {7., 8., 9.}, }; test(a[0], 3); return 0; } 

虽然答复可能相当晚,但我希望它可以帮助其他有同样问题的人。

由于numpy数组在内部保存为1d数组,因此可以简单地在C中重建2d形状。这是一个小型MWE:

 // libtest2d.c #include  // for malloc and free #include  // for printf // create a 2d array from the 1d one double ** convert2d(unsigned long len1, unsigned long len2, double * arr) { double ** ret_arr; // allocate the additional memory for the additional pointers ret_arr = (double **)malloc(sizeof(double*)*len1); // set the pointers to the correct address within the array for (int i = 0; i < len1; i++) { ret_arr[i] = &arr[i*len2]; } // return the 2d-array return ret_arr; } // print the 2d array void print_2d_list(unsigned long len1, unsigned long len2, double * list) { // call the 1d-to-2d-conversion function double ** list2d = convert2d(len1, len2, list); // print the array just to show it works for (unsigned long index1 = 0; index1 < len1; index1++) { for (unsigned long index2 = 0; index2 < len2; index2++) { printf("%1.1f ", list2d[index1][index2]); } printf("\n"); } // free the pointers (only) free(list2d); } 

 # test2d.py import ctypes as ct import numpy as np libtest2d = ct.cdll.LoadLibrary("./libtest2d.so") libtest2d.print_2d_list.argtypes = (ct.c_ulong, ct.c_ulong, np.ctypeslib.ndpointer(dtype=np.float64, ndim=2, flags='C_CONTIGUOUS' ) ) libtest2d.print_2d_list.restype = None arr2d = np.meshgrid(np.linspace(0, 1, 6), np.linspace(0, 1, 11))[0] libtest2d.print_2d_list(arr2d.shape[0], arr2d.shape[1], arr2d) 

如果用gcc -shared -fPIC libtest2d.c -o libtest2d.so编译代码,然后运行python test2d.py它应该打印数组。

我希望这个例子或多或少能够自我解释。 这个想法是,该形状也被赋予C-Code,然后创建一个double **指针,为其保留附加指针的空间。 然后将这些设置为指向原始数组的正确部分。

PS:我是C的初学者,所以如果有理由不这样做,请评论。