To use ctypes with int** you can use POINTER(POINTER(c_int)) as the type and use slicing to access the elements of the array. To use ctypes with a C-contiguous 5x5 array using int* then numpy can be used efficiently.
test.c
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API int **function() {
int **information = malloc(5 * sizeof(int*)); // Note row element is int*
for (int k = 0; k < 5; k++) {
information[k] = malloc(5 * sizeof(int)); // Note col element is int
for (int j = 0; j < 5; j++) {
information[k][j] = k * 5 + j;
}
}
return information;
}
API int *function2() {
int *information = malloc(5 * 5 * sizeof(int)); // 5 x 5 C contiguous shape
for (int k = 0; k < 5; k++) {
for (int j = 0; j < 5; j++) {
information[k * 5 + j] = k * 5 + j;
}
}
return information;
}
test.py
import ctypes as ct
import numpy as np
from pprint import pprint
lib = ct.CDLL('./test')
lib.function.argtypes = ()
lib.function.restype = ct.POINTER(ct.POINTER(ct.c_int))
lib.function2.argtypes = ()
lib.function2.restype = np.ctypeslib.ndpointer(dtype=ct.c_int, shape=(5, 5), flags='C')
def function():
res = lib.function()
# slicing used to extract the correct number of items
return [row[:5] for row in res[:5]]
pprint(function())
pprint(lib.function2())
Output:
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]]
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
In both cases the memory is leaked for the mallocs. Ideally, let Python manage the memory and let C know the shape. Using np.empty below allocates memory without initialization then C initializes it. This is more flexible and can be used with different-sized arrays:
test.c
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API void function3(int* information, int row, int col) {
for (int k = 0; k < row; k++) {
for (int j = 0; j < col; j++) {
information[k * row + j] = k * 5 + j;
}
}
}
test.py
import ctypes as ct
import numpy as np
lib = ct.CDLL('./test')
lib.function3.argtypes = np.ctypeslib.ndpointer(dtype=ct.c_int),
lib.function3.restype = None
info = np.empty(dtype=ct.c_int,shape=(5,5))
lib.function3(info,5,5)
print(info)
Output:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]]