2

(I think this question can easily be answered by an expert without an actual copy-paste-working-example, so I did not spent extra time on it…)

I have a C++ method, which returns an array of integers:

int* Narf::foo() {
    int bar[10];
    for (int i = 0; i < 10; i++) {
        bar[i] = i;
    }
    return bar;
}

I created the Cython stuff for its class:

cdef extern from "Narf" namespace "narf":
    cdef cppclass Narf:
        Narf() except +
        int* foo()

And these are my Python wrappers:

cdef class PyNarf:
    cdef Narf c_narf
    def __cinit__(self):
        self.c_narf = Narf()
    def foo(self):
        return self.c_narf.foo()

The problem is the foo method, with its int* return type (other methods which I did not list in this example work perfectly fine!). It does not compile and gives the following error:

    def foo(self):
        return self.c_narf.foo()
                             ^
------------------------------------------------------------

narf.pyx:39:37: Cannot convert 'int *' to Python object

Of course, it obviously does not accept int * as return type. How do I solve this problem? Is there an easy way of wrapping this int * into a numpy array (I'd prefer numpy), or how is this supposed to be handled?

I'm also not sure how to handle the memory here, since I'm reading in large files etc.

tamasgal
  • 24,826
  • 18
  • 96
  • 135
  • 1
    why are you returning a pointer to a local data? – jfs May 24 '16 at 12:26
  • That's a good question ;-) – tamasgal May 24 '16 at 12:37
  • I should go for an instance variable or maybe even for a pointer pass instead of… – tamasgal May 24 '16 at 12:40
  • you should accept the buffer instead: `foo(int*)` i.e., create a numpy array (that will manage the memory for you) and pass it to `foo()`. See [calling c from python with ctypes: passing vectors](http://stackoverflow.com/a/22685515/4279). Otherwise, see [How to convert pointer to c array to python array (`PyArray_SimpleNewFromData()`)](http://stackoverflow.com/q/7543675/4279) – jfs May 24 '16 at 12:43
  • I guess the buffer version is the better one, since numpy will manage malloc. – tamasgal May 24 '16 at 12:45
  • btw, if you are working with Cython, make sure to study [Typed Memoryviews](http://docs.cython.org/src/userguide/memoryviews.html) – jfs May 24 '16 at 12:51
  • Thanks, I just need to understand how I can pass a memory view of a numpy array to the C-function. – tamasgal May 24 '16 at 12:57
  • If you mean a Cython function that is declared to accept a memory view then it is handled automatically (if the shape, etc are compatible). – jfs May 24 '16 at 12:59

2 Answers2

2

To wrap it a numpy array, you need to know the size, then you can do it like this:

def foo(self):
    cdef int[::1] view = <int[:self.c_narf.size()]> self.c_narf.foo()
    return np.asarray(view)

The above code assumes that there exists a function self.c_narf.size() that returns the size of the array.

aldanor
  • 3,371
  • 2
  • 26
  • 26
  • This is basically what I want, now as J.F. Sebastian pointed out, I'm returning a pointer to local data, so even the first call works, I get a segmentation fault in the next calls… – tamasgal May 24 '16 at 12:37
  • @septi why not return an `std::vector`? – aldanor May 24 '16 at 12:58
1

This looks like it can be solved using the solution to this question: Have pointer to data. Need Numpy array in Fortran order. Want to use Cython

Community
  • 1
  • 1
mobiusklein
  • 1,403
  • 9
  • 12