It's 100% a key feature of Zig. Culturally, if it allocates, then it takes an allocator as an argument. C simply doesn't work that way. You could write C that way, but people don't.
I've written reasonable amounts of both, and it's just different. For instance, in Zig, you can create a HashMap using a FixedBufferAllocator, which is a region of memory (which can be stack allocated) dressed up as an allocator. You can also pass it an arena and free all at once, or any other allocator in the standard library, or implemented by you, or anyone else. Show me a C library with a HashMap which can do all three of these things. Everything which allocates takes an allocator, third-party libraries respect this convention or will quickly get an issue or PR either requesting or implementing this convention.
Ultimate solution? No, but also, sort of. The ability to idiomatically build a fine-grained memory policy is a large portion of what makes Zig so pleasant to use.
I've written reasonable amounts of both, and it's just different. For instance, in Zig, you can create a HashMap using a FixedBufferAllocator, which is a region of memory (which can be stack allocated) dressed up as an allocator. You can also pass it an arena and free all at once, or any other allocator in the standard library, or implemented by you, or anyone else. Show me a C library with a HashMap which can do all three of these things. Everything which allocates takes an allocator, third-party libraries respect this convention or will quickly get an issue or PR either requesting or implementing this convention.
Ultimate solution? No, but also, sort of. The ability to idiomatically build a fine-grained memory policy is a large portion of what makes Zig so pleasant to use.