If you want to keep your sanity, you don't want to be manually mallocing and freeing all over the place.
The most common patterns I often see are a "context" object of some kind (typically used by libraries) which handles all memory management internally and must be passed to every API call. So you only ever allocate and free that one object. (Internally they might be doing all sorts of crazy things, I've even seen a basic tracing GC!)
Applications typically use some combination of bump allocators (aka arenas) and pools. You put temporary allocations in a dedicated temp arena and clear it out when appropriate for the application (i.e. every frame)
The most common patterns I often see are a "context" object of some kind (typically used by libraries) which handles all memory management internally and must be passed to every API call. So you only ever allocate and free that one object. (Internally they might be doing all sorts of crazy things, I've even seen a basic tracing GC!)
Applications typically use some combination of bump allocators (aka arenas) and pools. You put temporary allocations in a dedicated temp arena and clear it out when appropriate for the application (i.e. every frame)