0

I would like to free memory allocated a variable that is a pointer-to-pointer (or a "double pointer" -- not to be confused with pointer to a double datatype.)

Suppose the pointer-to-pointer is **ptr and (for simplicity) it is a 10x10 array of integers. Following the documentation, I see that one way of allocating space is as follows.

from cpython.mem cimport PyMem_Malloc, PyMem_Free

## Allocate memory
cdef int **ptr = <int **>PyMem_Malloc(sizeof(int *) * 10)
cdef i;
for i in range(10):
    ptr[i] = <int *>PyMem_Malloc(sizeof(int) * 10)

## Free memory
for i in range(10):
    PyMem_Free(<void *>ptr[i])
PyMem_Free(<void *>ptr)

The documentation does not explicity mention what is the correct way to free a pointer-to-pointer. From my experience with programming in C, I guessed that this should be the recommended way. However, the free-memory syntax does not seem to work correctly, for when I compile (using distutils.core.setup), it seems to give me a familiar gcc-error -- indicating that I'm attempting to free unallocated memory.

python(4522,0x7fffd08143c0) malloc: *** error for object 0x1172c8054: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

This question is very much the Cython analogue of this question pertaining to C pointers.

Community
  • 1
  • 1
Pavithran Iyer
  • 402
  • 5
  • 14
  • What version of cython are you using? Your code runs just fine on my machine. – romeric May 01 '17 at 14:14
  • Thanks for the quick response. Interesting! My version of Cython is: Cython version 0.25.2 . That's pretty much the latest, isn't it? – Pavithran Iyer May 01 '17 at 14:24
  • Yes `0.25.2` is the recent release. Does the error go away if you cast to `` instead of `` while freeing the memory? Or not cast at all? – romeric May 01 '17 at 14:30
  • 1
    @PavithranIyer I can't see what's going wrong (although clearly it isn't working right). I wouldn't put too much weight to romeric saying to works for him - it's perfectly possible not to hit memory errors that do exist if you're lucky. My general advice is: avoid pointer-to-pointer for 2D arrays. It's generally more efficient to allocate a 1D array and calculate a position in it using strides/shape. – DavidW May 01 '17 at 14:32
  • @DavidW Oh ok I see. Glad to know it didn't work right for you, at least we're on the same page! Ok, if I understand you right, do you suggest *always* using 1D arrays or just (level-1) pointers? In my question, the 10x10 array was just to provide a code snippet. In my applications, I do need a multidimensional (jagged array) pointer-to-pointer-to-pointer-to... A very similar strategy in C seems to work, irrespective of the dimensions of the pointer. Cython should not be any harder than that, right? Maybe `PyMem_Malloc` and `PyMem_Free` are behaving weird? – Pavithran Iyer May 01 '17 at 15:59
  • @PavithranIyer I haven't actually tested it myself, just looked at the code - I was just saying that the fact it worked for someone doesn't prove it's bug free. For what you want ( jagged arrays) pointer-to-pointer-... sounds like the good solution. For the simple regular sized multi-D array I'd avoid it. But it's a matter of taste – DavidW May 01 '17 at 16:04
  • Another option to consider would be the Python approach to the same structure: list of (list of...?) numpy/`array` arrays. The speed probably won't be too bad and the memory is managed for you. – DavidW May 01 '17 at 16:06
  • @romeric No, unfortunately, the free method I have used is defined as `PyMem_Free(void *ptr)`. It throws a syntax error if the argument is not of type `void*`. – Pavithran Iyer May 01 '17 at 16:53
  • @DavidW Thanks a lot for suggesting numpy. I agree with you on numpy being a viable option. You're right, it is indeed a matter of taste... I was hoping to have minimum (close to no) Python interaction in some parts of my code. Hence, to avoid numpy objects like `cdef np.ndaray[...] ...`. I guess I've a few options at hand... – Pavithran Iyer May 01 '17 at 16:56
  • I totally get the fact that the code working for me does not prove anything, as memory problems are tricky that way. What I don't understand is the compile time error that you get and I don't. On my machine with `gcc-5.2` I can even compile while casting to `int*`. – romeric May 01 '17 at 16:57

0 Answers0