4

I have a ctypes Structure with dynamic allocated arrays i.e.:

array_1d_double=npct.ndpointer(dtype=np.double,ndim=1,
                               flags='CONTIGUOUS')
class Test(Structure):
    _fields_ = ("x", array_1d_double, ..)

test = Test()
do_some_init_in_c(  for example malloc)

If I print test.x I get the following output:

<ndpointer_<f8_1d_CONTIGUOUS object at 0x7f104dc0c3b0>

The c structure looks roughly like this,

structure Test_s{
    double *x;....
};

How is it possible to access this element like an numpy array? Is it maybe necessary to allocate the arrays as np.arrays instead of using malloc? What would be the proper way to do this ?

1
  • Why did you include the 'c' tag? Commented Apr 27, 2014 at 22:47

1 Answer 1

7

One way to do what you are talking about would be to just straight up allocate the numpy array on the python side and behave like it is a straight forward double array on the C side.

import numpy as np
import ctypes as C

# allocate this as a normal numpy array with specified dtype
array_1d_double = np.array([1,2,3,4,5],dtype="float64")

# set the structure to contain a C double pointer
class Test(C.Structure):
    _fields_ = [("x", C.POINTER(C.c_double))]

# Instantiate the structure so it can be passed to the C code
test = Test(np.ctypeslib.as_ctypes(array_1d_double))

# You can also do:
# test = Test()
# test.x = np.ctypeslib.as_ctypes(array_1d_double)

print test.x
# outputs: <__main__.LP_c_double object at 0x1014aa320>

You should now be able to use the struct's x member as a normal double array in the C code.

EDIT:

To clarify: If you instantiate a Structure with no arguments, it provides NULL pointers for all its members.

class Test(C.Structure):
    _fields_ = [("x", C.POINTER(C.c_double)),
                ("y", C.POINTER(C.c_int))]

test = Test()
print test.x
# outputs: <__main__.LP_c_double object at 0x1014aa320>

print test.y
# outputs: <__main__.LP_c_int object at 0x101429320>

print test.x[0]
# raises ValueError: NULL pointer access

print test.y[0]
# raises ValueError: NULL pointer access

If you instantiate the Structure with N arguments, those arguments will be assigned to the first N members of the Structure.

test = Test(np.ctypeslib.as_ctypes(array_1d_double))

print text.x[0]
# outputs: 1.0

print test.y[0]
# raises ValueError: NULL pointer access

EDIT2

If you want to tie the numpy arrays to your struct permanently, you can override the __init__ method:

class MyDualArrayStruct(C.Structure):
    _fields_ = [("c_x", C.POINTER(C.c_double)),
                ("c_y", C.POINTER(C.c_int))]

    def __init__(self,*args,**kwargs):
        super(MyDualArrayStruct,self).__init__(*args,**kwargs)
        self.np_x = np.array([1,2,3,4,5],dtype="float64")
        self.c_x = np.ctypeslib.as_ctypes(self.np_x)
        self.np_y = np.array([5,4,3,2,1],dtype="int32")
        self.c_y = np.ctypeslib.as_ctypes(self.np_y)

test = MyDualArrayStruct()

print test.np_x
print test.c_x[:5]

# Note that here c_x and np_x both contain the same data. Thus modifying one of them
# (inplace) modifies the other. You can use this to do easy inplace modification of 
# numpy arrays in C functions.
# This implies that test.np_x.sum() is also the sum of test.c_x
test.np_x[:] = 1

print test.np_x
print test.c_x[:5]

This outputs:

[ 1.  2.  3.  4.  5.]
[1.0, 2.0, 3.0, 4.0, 5.0]
[ 1.  1.  1.  1.  1.]
[1.0, 1.0, 1.0, 1.0, 1.0]
Sign up to request clarification or add additional context in comments.

14 Comments

Thank You, unfortunately my Structure contains around 100 elements does this still work? I'm suprised that my code works if i dont have the pointer inside the structure any idea why ?
The number of elements in your structure is irrelevant. You just need to set them python side if they are python-side values (like your numpy array) or set them C side if they are C-side values. As to your question, you do have the pointer inside your structure. The structure is created with pointers (which may not point to valid memory), you are just updating those pointers to be valid.
Does this mean test = Test(np.ctypeslib.as_ctypes(array_1d_double)) creates a copy of array_1d_double for each element inside the structure?
Nope, test = Test(np.ctypeslib.as_ctypes(array_1d_double)) just allocates a pointer to the array to the first element in the struct
But how does this work if i have more then element in the struct?
|

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.