I've long had the strong belief that allocation and deallocation should be done by the same party.
Either the caller is responsible and the function just uses the provided buffers/structures, or there is a clear convention that the caller has to call a cleanup function on the returned buffers/structures.
Mixing allocation and deallocation responsibilities between caller and callee almost always leads to pain and sorrow, in my experience.
Of course, if you're using a shared library or similar which can be written in something else entirely, mixing is a complete no-go as GP mentions.
Either the caller is responsible and the function just uses the provided buffers/structures, or there is a clear convention that the caller has to call a cleanup function on the returned buffers/structures.
Mixing allocation and deallocation responsibilities between caller and callee almost always leads to pain and sorrow, in my experience.
Of course, if you're using a shared library or similar which can be written in something else entirely, mixing is a complete no-go as GP mentions.