2

I want to pass a 2d numpy array to a function written in C using ctypes. When I try to access the data in the C function I get: Segmentation fault (core dumped). The code is:

code in C

#include <stdio.h>

void np_array_complex_shape(double ** data, int * shape){
  printf("%d\n", shape[0]);
  printf("%d\n", shape[1]);  // These print ok.
  printf("%f", data[0][0]);  // This one throws: Segmentation fault (core dumped)
}

code in python:

import os
import ctypes
import numpy as np
import numpy.ctypeslib as npct

test_library_file_location = "library.so"

array_2d_double = npct.ndpointer(dtype=np.double, ndim=2, flags='CONTIGUOUS')
array_1d_int = npct.ndpointer(dtype=np.int32, ndim=1, flags='CONTIGUOUS')

LIBC = ctypes.CDLL(test_library_file_location)
LIBC.np_array_complex_shape.restype = None
LIBC.np_array_complex_shape.argtypes = [array_2d_double, array_1d_int]

x = np.array([[1,2,3],[4,5,6],[7,8,9]], dtype=np.float64)
s = np.array(x.shape, dtype=np.int32)

c = LIBC.np_array_complex_shape(x, s)

I've tried different solutions I found on line, but non work. Could someone help me?

I am using linux and gcc compilers.

1
  • numpy arrays use direct memory layout, i.e. its data is stored in a double *. double ** corresponds to indirect memory layout which is not supported by numpy. For more information see buffer-protocol: docs.python.org/3/c-api/buffer.html#buffer-structure Commented Nov 13, 2020 at 7:15

1 Answer 1

1

While you can often get away with mixing up arrays with pointers to some extent, mixing up 2D arrays with pointers to pointers will never work right. If you know that the second dimension will always be 3, then you can change double ** data to double (*data)[3] in your C code, and then everything will work. If it's not always a constant, but Python will always know what it is and you're okay with using VLAs, then you can redeclare your function as void np_array_complex_shape(int cols, double (*data)[cols], int *shape) and pass the appropriate value for cols. Otherwise, you need to change it to double *data, and then manually calculate indices as if it were flattened into a 1D array (which is just changing data[0][0] to data[0] in your simple example).

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

6 Comments

Thanks ! This is very useful. But how do you extend this logic to numpy arrays of 3 or 4 dimensions?
@mm_ If data were a 3x4x5x6 array, you'd declare it as double (*data)[4][5][6]. The general rule is you can replace the first dimension of the array with a pointer, but the rest stay as-is.
Sorry, How do you pass the value 'cols' in python?
@mm_ rows, cols = x.shape, then just pass it like any other number.
in C I declare void np_array_complex_shape(int cols, double (*data)[cols], int *shape) In python I call it LIBC.np_array_complex_shape(??, x.shape). How do I pass cols to the first argument? Thanks so much for your time !
|

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.