I am working with ctypes to expose some C functions from a DLL to a Python script. One of the functions returns a dynamically sized character array, and I would like to be able to read the contents of this array in Python, but also property handle freeing the memory of the array when I am done with it.
Example C code:
...
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) char * WINAPI get_str()
{
int str_len = ... // figure out how long it is gonna be and set it here
char *ary = (char *)malloc(sizeof(char) * str_len);
// populate the array
...
ary[str_len - 1] = '\0';
return ary;
}
#ifdef __cplusplus
}
#endif
I build my DLL, copy it over to a location it will be found, and then have this Python code:
import ctypes
my_dll = ctypes.WinDLL("MyDLLName.dll")
some_str = ctypes.string_at(my_dll.get_str())
print some_str
This code all works correctly as you would expect. My question is: because ctypes.string_at creates a string at the specified memory location, when some_str goes out of scope in the Python interpreter, will that memory be garbage collected, or do I need to free it manually?
string_at
creates a new Python string, in a new memory location, completly independent of the memory location it was called with.
Python or ctypes can't guess about what your native code returned it - as far as it is concerned, it is just a number (which happens to be a valid pointer in this case).
So, the rule of thumb is: if you write C code that allocates memory, you should also write equivalent C code to de-allocate it - and call that freeing C code from your ctypes-using Python code.
For quick scripts and examples like this, since you know it is a simple allocated string, you can free it straight from Python side by using ctypes to call the system free
function.
That is, store the returned pointer in a Python var: (you may or may not cat it to a proper ctypes pointer type), and after running string_at, use:
pointer = my_dll.get_str()
some_str = ctypes.string_at(pointer)
# This is windows specific -
# on Posix, one have to load "libc.so" and use "free" from there:
ctypes.cdll.msvcrt.free(pointer)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With