I'm trying to execute a C function using Python ctypes, but I'm doing something wrong.
The C function was originally converted from MATLAB to C code using MATLAB coder. The function gives as output an array of undefined length, which depends on the input.
This is the MATLAB code:
function a = array_output(n)
%$codegen
if n > 2*pi
a = 1:n;
else
a = [1,2,3];
end
end
And this is the obtained C code:
void array_output(double n, emxArray_real_T *a)
{
int i;
int loop_ub;
if (n > 6.2831853071795862) {
i = a->size[0] * a->size[1];
a->size[0] = 1;
loop_ub = (int)floor(n - 1.0);
a->size[1] = loop_ub + 1;
emxEnsureCapacity_real_T(a, i);
for (i = 0; i <= loop_ub; i++) {
a->data[i] = (double)i + 1.0;
}
} else {
i = a->size[0] * a->size[1];
a->size[0] = 1;
a->size[1] = 3;
emxEnsureCapacity_real_T(a, i);
a->data[0] = 1.0;
a->data[1] = 2.0;
a->data[2] = 3.0;
}
}
struct emxArray_real_T
{
double *data;
int *size;
int allocatedSize;
int numDimensions;
boolean_T canFreeData;
};
Please, find at the end of my question an example implementation they provide.
I am trying to execute it using Python's ctype using the following code:
dll = ctypes.cdll.LoadLibrary(dll_path)
class DataStruct(ctypes.Structure):
_fields_ = [
('data', ctypes.POINTER(ctypes.c_double)),
('size', ctypes.POINTER(ctypes.c_int)),
('allocatedSize', ctypes.c_int),
('numDimensions', ctypes.c_int),
('canFreeData', ctypes.c_bool)
]
array = ctypes.POINTER(ctypes.c_double)()
size = numpy.array([0, 0]).ctypes.data_as(ctypes.POINTER(ctypes.c_int))
allocatedSize = 0
numDimensions = 2
canFreeData = True
data_struct = DataStruct(array, size, allocatedSize, numDimensions, canFreeData)
dll.array_output.argtypes = [ctypes.c_double, DataStruct]
dll.array_output.restype = None
dll.array_output(50, data_struct)
The output data_struct contains the right size field (data_struct.size[1] is 50), but when I try to access data_struct.data[0], I get the following error:
ValueError: NULL pointer access
Can anyone help me understanding what I'm doing wrong here?
--
Example implementation (code snippets):
void main(){
// pseudo-code here
emxArray_real_T *a;
emxInitArray_real_T(&a, 2);
/* Initialize function 'array_output' input arguments. */
/* Call the entry-point 'array_output'. */
array_output(5.0, a);
}
void emxInitArray_real_T(emxArray_real_T **pEmxArray, int numDimensions)
{
emxInit_real_T(pEmxArray, numDimensions);
}
void emxInit_real_T(emxArray_real_T **pEmxArray, int numDimensions)
{
emxArray_real_T *emxArray;
int i;
*pEmxArray = (emxArray_real_T *)malloc(sizeof(emxArray_real_T));
emxArray = *pEmxArray;
emxArray->data = (double *)NULL;
emxArray->numDimensions = numDimensions;
emxArray->size = (int *)malloc(sizeof(int) * numDimensions);
emxArray->allocatedSize = 0;
emxArray->canFreeData = true;
for (i = 0; i < numDimensions; i++) {
emxArray->size[i] = 0;
}
}
void emxEnsureCapacity_real_T(emxArray_real_T *emxArray, int oldNumel)
{
int newNumel;
int i;
void *newData;
if (oldNumel < 0) {
oldNumel = 0;
}
newNumel = 1;
for (i = 0; i < emxArray->numDimensions; i++) {
newNumel *= emxArray->size[i];
}
if (newNumel > emxArray->allocatedSize) {
i = emxArray->allocatedSize;
if (i < 16) {
i = 16;
}
while (i < newNumel) {
if (i > 1073741823) {
i = MAX_int32_T;
} else {
i *= 2;
}
}
newData = calloc((unsigned int)i, sizeof(double));
if (emxArray->data != NULL) {
memcpy(newData, emxArray->data, sizeof(double) * oldNumel);
if (emxArray->canFreeData) {
free(emxArray->data);
}
}
emxArray->data = (double *)newData;
emxArray->allocatedSize = i;
emxArray->canFreeData = true;
}
}
emxEnsureCapacity_real_Tis missing.emxInitArray_real_Tfunction written in C, why are you trying to rewrite it in Python instead of just calling it?emxInitArray_real_TI honestly only want to use the main functionarray_outputand do the remaining in Python.