0

I have a problem with my python code. I have a function in c that return an array of int. As following :

int* prochepoints_tabu (Client* points, int size, int distmax){
          //instructions
          int* path;
          for (int i = 1; i < nsize; i++){
             path[i] = res[i].number;
        
           }
    return path;
}

Then I called this function in python as following :

class CA(Structure):
    _fields_ = [('number', c_int),
                ('x',c_int),
                ('y',c_int)]

ca_list = []
newlist = nodes.copy()
newlist.pop('0')
for key, el in newlist.items():
    ca = CA()
    ca.number = int(key)
    ca.x = el[0]
    ca.y = el[1]
    ca_list.append(ca)

ca_array = (CA * len(ca_list))(*ca_list)
distmax = c_int(vehicles[8]['charged'])
cap = c_int(vehicles[8]['capacity'])
res =(CA * len(vehicles))()
dll = CDLL('./functions.so')
dll.prochepoints_tabu.argtypes = [POINTER(CA), c_int, c_int]
dll.prochepoints_tabu.restype = POINTER(c_int)
path = dll.prochepoints_tabu(ca_array, len(ca_array), vehicles[1]['charged'])

And when I compile this program I've this message of error : " path = dll.prochepoints_tabu(ca_array, len(ca_array), vehicles[1]['charged']) OSError: exception: access violation writing 0x0000000000000004"

Thus, how can I return an array in python from C without knowing his size, because I want to store this array in python

Thank you very much for your help

VoidAlpha
  • 1
  • 1
  • `path` is _uninitialized_. Try: `int *path = malloc(sizeof(*path) * nsize);` But python will have to do a `free` on this pointer when done with it and I don't know how to get it to do this. You may have to have python pass `path` as an arg with sufficient space. You'll have to look deeper into the python docs for calling C functions – Craig Estey Jun 10 '22 at 01:14
  • Thanks for your answer. I've changed this, but it seems not work too. I modified my parameter in the aim to be able to communicate with the variable in python, but i'm not sure that it works – VoidAlpha Jun 10 '22 at 01:33
  • I've got this new error : argument 4: : expected LP_c_long instance instead of _ctypes.PyCPointerType – VoidAlpha Jun 10 '22 at 01:36
  • I think I've a problem with the initialisation of pls variable (pls = POINTER(c_int) that I've added to the parameter), but I don't know – VoidAlpha Jun 10 '22 at 01:36
  • Okay, some progress. Original error was probably a segfault due to null pointer dereference, fixed(?) with the malloc. I'm proficient in C but a python noob, so a guess... In your python code path is ordinary scalar(?) and not expecting a C pointer return. Does it want a return type of int/long instead of array/pointer of/to int? That is, it wants `int` return instead of `int *`??? Do you need to declare path in some special way? – Craig Estey Jun 10 '22 at 01:57
  • In my python code, I defined the path as a pointer of int, I don't know why he don't understand that. Maybe the path = POINTER(c_int) doesn't work. – VoidAlpha Jun 10 '22 at 02:08
  • From https://docs.python.org/3/library/ctypes.html I was going to suggest `path = POINTER(c_int)` If that doesn't work for the return it may be you can pass it to C as an output arg. But you'd need to ensure it has N elements. – Craig Estey Jun 10 '22 at 02:34
  • That link appears to cover a lot and some of it looked similar to what you want to do. From the "Arrays" and "Pointers" sections, a guess: `path = c_int * len(ca_array) ; dll.prochepoints_tabu.argtypes = [POINTER(CA), c_int, c_int, POINTER(path)] ; dll.prochepoints_tabu(ca_array, len(ca_array), vehicles[1]['charged'], pointer(path))` In the C function, add a new last arg: `int *path` and forget the return and the malloc. You may need to pass just `path` in the call [just like you do for `ca_array`]. I'd add `printf` to the C func and verify that you see the values you want. – Craig Estey Jun 10 '22 at 03:07
  • I've got this error now : dll.prochepoints_tabu(ca_array, len(ca_array), vehicles[1]['charged'], pls) ctypes.ArgumentError: argument 4: : expected LP_LP_c_long_Array_26 instance instead of _ctypes.PyCArrayType – VoidAlpha Jun 10 '22 at 06:29
  • wirh this in python : pls = c_int * len(ca_array) dll.prochepoints_tabu.argtypes = [POINTER(CA), c_int, c_int, POINTER(pls)] dll.prochepoints_tabu.restype = None dll.prochepoints_tabu(ca_array, len(ca_array), vehicles[1]['charged'], pls) print(pls[0]) – VoidAlpha Jun 10 '22 at 06:30
  • In c, I've changed my function to void, and delete the return – VoidAlpha Jun 10 '22 at 06:32
  • 1
    If you return a pointer (containing a number of records) with unknown size how would you know how to interpret it afterwards? Seems like a design flaw here. There are many examples how to pass pointers back and forth, here's one: https://stackoverflow.com/questions/58226790/c-python-pass-and-return-a-2d-double-pointer-array-from-python-to-c. Plus, there's a lot of follow up info in the comments, add it to the question instead. – CristiFati Jun 11 '22 at 17:00
  • You can't return an array of unknown size. Either allocate the array and pass its pointer and number of elements to the function to be filled out, or allocate the array in C and return the pointer and the number of elements in a structure or output parameter. In the latter case you then have to deal with freeing the memory as well. – Mark Tolonen Jun 13 '22 at 01:27

0 Answers0