In a response elsewhere, I found the following snippet:
In general it is nicer in C to have the caller allocate memory, not the callee - hence why str
Nicer as in Friendlier. Let the caller allocate the memory and the caller can decide HOW to allocate the memory. They can choose between stack and heap obviously. But also between multiple heaps in some cases. They can package up mulitiple allocations into a single malloc call (useful when you need to marshal the data into another address space).
In Win32, there is GlobalAlloc()
, which is the ONLY way to allocate memory that can be passed in DDE messages to other applications. (not that anyone cares anymore ;)
in Win32 we also have VirtualAlloc
which is not used very often, but has some properties that make it invaluable for some special cases. (you can change memory from read-write to read-only after you initialize it).
There's also CreateFileMapping/MapViewOfFile
, which gets you memory that is backed by a particular file - writes to the memory end up writing to the file.
I'm sure Unix has equivalent specialized memory allocation functions.
Either approach you post is good form; the former is closer to how C++ handles things, the latter is more Objective-C like. The important thing is to balance creation and destruction within a code block. This practice falls under the category of reducing coupling. What's bad practice is to have a function that creates something and performs additional tasks, as strdup
does, which makes it harder to know if the caller has to dispose of anything without consulting the documentation.
By allocating and deallocating memory in the same function (or source file), you'll have an easier time identifying potential memory leaks (or convincing yourself there are none) without having to hop around to different places in your program. If a callee allocates memory, it's ambiguous where the deallocation should take place. In contrast, by having the caller do it, that code is taking "full responsibility" for the memory.
Above all, though, consistency is the key. Pick one approach and stick with it.
Having the caller allocate memory is better, because you can save memory allocations by recycling old data structures manually. This is useful in mathy applications, when you have lots of N sized arrays lying around. Remember, memory allocation is quite slow.
On the other hand, if the size of the array can only be determined by the function (i.e. the size of the result is unknown) then the callee should allocate.
Whatever you do, use conventions to tell people what has happened. Big stupid names like pre_allocated_N_array
or new_result_array
(sorry, I'm not a C expert, there should be C conventions for this though) are very handy for people who are using your function without reading the docs. It all comes down to consistency.
The main advantage of having the caller allocate the memory is that it simplifies the interface, and it's completely unambiguous that the caller owns the memory. As your create/destroy example shows, the simplification is not very great.
I prefer the create/destroy convention established by Dave Hanson in C Interfaces and Implementations:
struct foo *foo_new(...); // returns result of malloc()
void foo_free(struct foo **foop); // free *foop's resources and set *foop = NULL
You follow the convention thus:
struct foo *a = foo_new();
...
foo_free(&a);
// now `a` is guaranteed to be NULL
This convention makes it a little less likely you will leave a dangling pointer.