Pass multidimensional array (matrix) to c function using ctypes


D

Daniel Platz

Hello,

I would like to pass a two dimensional array to C function in a dll. I
use ctypes to call the function.

I compile the dll with visual studio 2008 express and my C source code
looks like this.

#include <stdio.h>
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
using namespace std;
#endif


__declspec(dllexport) int print(double** ptr, int ny, int nx)
{
int i, j;
for(i=0; i<ny; i++)
{
for(j=0; j<nx; j++)
{
printf("%.3f \t", *(*(ptr+i)+j));
}
printf("\n");
}
return 0;
}

#ifdef __cplusplus
}
#endif

As you can see the function expects a doube** variable. I tried to
call this function from Python with this code.

import ctypes as ct

matrix = ct.cdll.LoadLibrary('matrix.dll')
getattr(matrix, 'print_matrix')

ptr_type = ct.c_double * 5 * 4
ptr = ptr_type()
matrix.print_matrix(ptr, ct.c_int(4), ct.c_int(5))

I expected to see a matrix showing only zeros since I can address the
single entries in Python by ptr[j]. Instead the interpreter returns
with the error message

WindowsError: exception: access violation reading 0x000000
WARNING: Failure executing file: <ctypes_matrix.py>

Furthermore, I am wondering if there is a fast way to use a numpy 2D
array instead or alternatively to cast the ctypes array into a numpy
array.

Has someone an idea to help me?

Thank you very much

Daniel
 
Ad

Advertisements

M

Mark Tolonen

Daniel Platz said:
Hello,

I would like to pass a two dimensional array to C function in a dll. I
use ctypes to call the function.

I compile the dll with visual studio 2008 express and my C source code
looks like this.

#include <stdio.h>
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
using namespace std;
#endif


__declspec(dllexport) int print(double** ptr, int ny, int nx)
{
int i, j;
for(i=0; i<ny; i++)
{
for(j=0; j<nx; j++)
{
printf("%.3f \t", *(*(ptr+i)+j));
}
printf("\n");
}
return 0;
}

#ifdef __cplusplus
}
#endif

As you can see the function expects a doube** variable. I tried to
call this function from Python with this code.

import ctypes as ct

matrix = ct.cdll.LoadLibrary('matrix.dll')
getattr(matrix, 'print_matrix')

ptr_type = ct.c_double * 5 * 4
ptr = ptr_type()
matrix.print_matrix(ptr, ct.c_int(4), ct.c_int(5))

I expected to see a matrix showing only zeros since I can address the
single entries in Python by ptr[j]. Instead the interpreter returns
with the error message

WindowsError: exception: access violation reading 0x000000
WARNING: Failure executing file: <ctypes_matrix.py>

Furthermore, I am wondering if there is a fast way to use a numpy 2D
array instead or alternatively to cast the ctypes array into a numpy
array.

Has someone an idea to help me?


A two-dimentional array is not equivalent to a double**, so depending on
what your requirements are there are two solutions.

1. To work with your original matrix.c code above, some Python code that
works is:

-------------------------------------
import ctypes as ct

# I like C types in caps
DOUBLE = ct.c_double
PDOUBLE = ct.POINTER(DOUBLE)
PPDOUBLE = ct.POINTER(PDOUBLE)
INT = ct.c_int

matrix = ct.cdll.LoadLibrary('matrix.dll')
print_matrix = getattr(matrix,'print')

# An array of doubles can be passed to a function that takes double*.
DBL5ARR = DOUBLE * 5
# An array of double* can be passed to your function as double**.
PDBL4ARR = PDOUBLE * 4

# Declare double* array.
ptr = PDBL4ARR()
for i in range(4):
# fill out each pointer with an array of doubles.
ptr = DBL5ARR()
for j in range(5):
ptr[j] = i + j # just to initialize the actual doubles.

print_matrix(ptr,4,5)
-----------------------------------------------


2. In C, multidimensional arrays are really just single dimentional arrays
where the compiler does the math for you, so if you declare your matrix
print function like this:

----- matrix2.c ---------------------------
#include <stdio.h>
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif

__declspec(dllexport) int print(double* ptr, int ny, int nx)
{
int i, j;
for(i=0; i<ny; i++)
{
for(j=0; j<nx; j++)
{
printf("%.3f \t", ptr[i*nx + j]);
}
printf("\n");
}
return 0;
}

#ifdef __cplusplus
}
#endif
-------------------------------------------------

Then the Python code simplifies a bit to:

------------------------------------------
import ctypes as ct

DOUBLE = ct.c_double
PDOUBLE = ct.POINTER(DOUBLE)
INT = ct.c_int

matrix = ct.cdll.LoadLibrary('matrix2.dll')
print_matrix = getattr(matrix,'print')

ptr = (DOUBLE*5*4)()
for i in range(4):
for j in range(5):
ptr[j] = i + j

print_matrix(ptr,4,5)
----------------------------------------------

OUTPUT in both cases:
0.000 1.000 2.000 3.000 4.000
1.000 2.000 3.000 4.000 5.000
2.000 3.000 4.000 5.000 6.000
3.000 4.000 5.000 6.000 7.000

HTH,
Mark
 
Ad

Advertisements

D

Daniel Platz

Thanks a lot. This solves my problem and I understand now much better
what is going on.

Best regards,

Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top