Accessing an array with ctypes in Python
Question: I am writing a ode-solver in C, exported to a Windows DLL and a Python wrapper
for the DLL. I am very used to Python, but I'm a complete beginner with C and
ctypes too.

A modified solution inspired by the accepted answer
[here](http://stackoverflow.com/questions/18679264/how-to-use-malloc-and-free-
with-python-ctypes) looks like:

The C-code

    
    
    /* my_clib.c */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    struct data {
      int nr_steps;
      double dt;
      double* t;
      double* x;
      double t0, x0;
     };
    
    double fun_to_integrate(double t, double y){
        return (y - t);
     }
    
    double rk4(double t, double y, double dt){
        double  k1 = dt * fun_to_integrate(t, y),
                k2 = dt * fun_to_integrate(t + dt / 2, y + k1 / 2),
                k3 = dt * fun_to_integrate(t + dt / 2, y + k2 / 2),
                k4 = dt * fun_to_integrate(t + dt, y + k3);
        return y + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
    }
    
    __declspec(dllexport) void my_fun(struct data* pointer){
        int i;
        double dt;
        dt = pointer->dt;
        pointer->t[0] = pointer->t0;
        pointer->x[0] = pointer->x0;
        for(i = 1; i < pointer->nr_steps; i++){
            pointer->t[i] = dt*i + pointer->t0;
            pointer->x[i] = rk4(pointer->t[i-1], pointer->x[i-1], dt);
        }
     }
    

With the corresponding Python file

    
    
    # my_python.py
    import ctypes
    import numpy as np
    
    class DATA(ctypes.Structure):
        _fields_ = [
                    ('nr_steps', ctypes.c_int),
                    ('dt', ctypes.c_double),
                    ('t', ctypes.POINTER(ctypes.c_double)),
                    ('x', ctypes.POINTER(ctypes.c_double)),
                    ('t0', ctypes.c_double),
                    ('x0', ctypes.c_double)]
    
        def __init__(self):
            self.nr_steps = 1000
            self.dt = 0.00001
            self.t0 = 0.
            self.x0 = 2./3
            self.t = (ctypes.c_double * self.nr_steps)()
            self.x = (ctypes.c_double * self.nr_steps)()
    
    class SOLVER(object):
        def __init__(self):
            self.clib = ctypes.CDLL('rk4.dll')
            self.clib.my_fun.argtypes = [ctypes.POINTER(DATA)]
            self.clib.my_fun.restype = None
    
        def func(self, data_struc):
            self.clib.my_fun(ctypes.byref(data_struc))
    
    solver = SOLVER()
    data = DATA()
    solver.func(data)
    

Compiled with `gcc -o -c my_clib.o my_clib.c` \+ `gcc -o rk4.dll -shared
my_clib.o` using MinGW on Windows 8.

Everything runs fine and after the final line `solver.func()` the time data
and solution data are stored in `data.t` and `data.x`. Now I need to access
the calculated data from the pointers. It seems it cannot be done directly. If
you do `type(data.x)` you get `<class '__main__.LP_c_double'>`, but if you try
to access `type(data.x[i])` you get a standard `double`.

Every time I tried to for example `plot(data.t, data.x)` or cast it to
`np.array(data.t)`, the Python file crashes and the cmd freezes. However i
figured that `x_python = [data.x[i] for x i in range(*number_of_elements*)]`
works, but it is very slow if the arrays are long.

My question is: what is the correct/best way of accessing the data calculated
in the C-solver?

Also, if this is not the best way of passing an array from C to Python, what
other alternatives are suitable for this kind of application? I.e. for every
time step, or maybe after reaching some final time, passing the solution `(t,
x)` (tuple or two arrays) from C to Python?


Answer: To access values from ctypes objects that acts int, long, etc. use:

    
    
    x = ctypes.c_int(123)
    print x.value
    

So, you can iterate over them and make your array.

Also, you can pass a clear C static array to Python instead of using
structures, and use numpy's ctypes support to get the numpy.ndarray, or use
Python's array module.

But, I get your point using the structure. These are easy and clean ways to do
it.

