Malloc() and free() are a bad API
foonathan.net
foonathan.net
void* calloc(size_t num, size_t size);
Its interface is different because, historically, it was (more or less; prototypes didn’t exist yet and I’m not sure they used unsigned, for example): void* alloc(unsigned int num);
void* calloc(unsigned int num, unsigned int size);
and ‘int’ was 16-bits, but pointers 32 bits. So, alloc could only allocate up to 65,535 bytes, calloc up to 65,535 items of size up to 65,535. So, it allowed you to allocate much larger arrays.With respect to your explanation, I imagine there are some cases (maybe something older?), but in my experience the norm for an int on a system with 32-bit pointers is also 32-bits.
PDP-11, where calloc most likely originated, had 16-bit integers and 16-bit pointers. Apparently, later PDP-11s could be split into 64k of code space and 64k of data space (like the Harvard architecture) but that would still use 16-bit pointers.
Also, throwing C++ code in when he's showing C is wrong on so many levels.
(I just remembered a similar discussion by Richard Heathfield in C Unleashed. I looked it up and it's on pages 285-286. He sets out to improve upon the design of realloc(). He concludes "that whoever designed realloc did know what they were doing, after all. There's a lesson there somewhere for overzealous wheel inventors.")
I think a big flaw with malloc is that the returned values are memory addresses and not just handles. That means objects can't be moved around in memory once allocated. There's also no notion of types with malloc, just memory sizes in bytes. That makes heap fragmentation more of a problem. Plus if you have an allocated object containing a pointer to another allocated object there's no easy way to free all the memory allocated by the entire structure.
Finally, I think better support for putting data on the stack instead of the heap from the beginnings of unix with alloca would also have prevented memory leaks somewhat.
I never understood why C never got an higher level memory allocation API, after all, it isn't as if the 10 years of systems programming languages that preceeded it didn't had already NEW(type) as primitive.
The problem with alloca() is that C isn't Ada, so instead of an allocation error if the stack isn't big enough, you get a corrupted stack.
Fundamentally, though, I don't think that "malloc() and free() are missing some features that might improve them for my use case" is the same as "malloc() and free() are bad APIs." They're okay APIs, and they're like anything. Once you know what to expect, you barely think about it anymore.
I do think it would be interesting to hear more about the logic that inspired the original C developers to design the APIs as they did.
In my mind, a far more common use case calls for memory pools, where memory can be allocated and not explicitly tracked by the application. The memory pool gets freed at the end of some unit of computation. This interface is already nicely supplied by an Apache memory pool library.