Skip to content
Advertisement

How to make c++ return 2d array to python

I find an example showing how to return a 1D array from c++ to python. Now I hope to return a 2D array from c++ to python. I imitate the code shown in the example and my code is as follows:

The file a.cpp:

#include <stdio.h>
#include <stdlib.h>

extern "C" int* ls1(){
    int *ls = new int[3];
    for (int i = 0; i < 3; ++i)
    {
        ls[i] = i;
    }
    return ls;
}
extern "C" int** ls2(){
    int** information = new int*[3];
    int count = 0;
    for (int i = 0; i < 3; ++i)
    {
        information[i] = new int[3];
    }
    for(int k=0;k<3;k++){
        for(int j=0;j<3;j++)
            information[k][j] = count++;
    }
    return information;
}

The file b.py:

import ctypes
from numpy.ctypeslib import ndpointer

lib = ctypes.CDLL('./library.so')
lib.ls1.restype = ndpointer(dtype=ctypes.c_int, shape=(3,))
res = lib.ls1()
print 'res of ls1:'
print res

lib.ls2.restype = ndpointer(dtype=ctypes.c_int, shape=(3,3))
res = lib.ls2()
print 'res of ls2:'
print res

I run the following commands:

g++ -c -fPIC *.cpp -o function.o
g++ -shared -Wl,-soname,library.so -o library.so function.o
python b.py

Then I get the following prints:

res of ls1:
[0 1 2]
res of ls2:
[[32370416        0 35329168]
 [       0 35329200        0]
 [     481        0 34748352]]

It seems I succeed in returning 1D array, just in the same way shown in the example. But I fail in returning 2D array. How can I get it work? Thank you all for helping me!!!

Advertisement

Answer

You are allocating your array incorrectly.

int* may point to a beginning of a 1D attay.

int** never points to a beginning of a 2D array. It may point to a beginning of 1D array of pointers, each of which in turn point to a beginning of a 1D array. This is a legitimate data structure, but it’s different from a 2D array and is not compatible with Python’s

ndpointer(dtype=ctypes.c_int, shape=(3,3))

To return a real 2D array, you can do this:

typedef int a3[3];
a3 array[3] = new a3[3];
// no more allocations
for(int k=0;k<3;k++){ ...

Note that in a 2D array in C++ all dimensions except one are fixed.

If you want to return something that Python can interpret as a 2D array, you can return a 1D array:

int* array = new int[9];
// initialize it

Python will use it as a 3×3 matrix just fine. This allows you to vary all array dimensions: C++ never knows it’s a 2D array, you just multiply all the dimensions together.

If you for some reason do need an array of pointers (not recommended), you need to use something like this on the Python side:

int3type = ndpointer(dtype=ctypes.c_int, shape=(3,))
lib.ls2.restype = ndpointer(dtype=int3type, shape=(3,))

(I’m not a ctypes guru so take this with the grain of salt).

Finally, consider using boost::python. With it you can use std::vector on the C++ side normally, without resorting to low level hackery.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement