- You want an allocation to live beyond a function invocation
- You want to conserve stack space (which is typically limited to a few MBs)
- You're working with re-locatable memory (Win16, databases, etc.), or want to recover from allocation failures.
- Variable length anything. You can fake around this, but your code will be really nasty.
The big one is #1. As soon as you get into any sort of concurrency or IPC #1 is everywhere. Even most non-trivial single threaded applications are tricky to devise without some heap allocation. That'd practically be faking a functional language in C/C++.