The answer depends on which language (C++, Java, etc.) you're using, maybe on which compiler, and maybe on the compiler options too (debug versus release). Also the behaviour may not be guaranteed (allocated heap may be zero when you first allocate it, but later after your program has been running and you're starting to reuse heap you may find that you're [re]allocating non-zeroed memory).

If heap space is set to zero, it's probably because it has not been used before.
After you've allocated, freed, and reallocated plenty of things on the heap, you'll start to find bits of old data showing up in your uninitialised heap space.

The stack contains old local variables from other functions in your call stack. The stack is designed to be as efficient as possible, so no time is spent erasing old variables.

Also remember, 0 isn't necessarily the correct initialiser for anything... it's just a sensible choice; nothing makes it uniquely 'correct'. You should ALWAYS explicitly set initialiser values for local variables!

What you are seeing are artifacts of your environment, not givens. I'm going to assume you are talking about C.

But that said, when you allocate memory from the heap it may or may not be initialized to zero. In a language like C, malloc makes no guarantees about the memory being initialized to 0, but calloc does. However, that said, in practice, if you allocate a lot of stuff you'll tend to see it filled with 0s. Why? Because when your program runs out of room to give you memory it asks the operating system for more memory. When it does so, the operating system gives it the memory by mapping it a bunch of virtual pages that it'll actually materialize and fill with 0s on their first access. Now, if you free some values on the heap and allocate more with malloc you may be given back some of that 'dirtied' memory that you scribbed on earlier. If you assumed everything was going to be 0 initialized, this can lead to subtle bugs that only happen once the system has been running for a while, or after deletions have been made in a completely different part of the system!

So don't rely on fresg space off the heap being initialized to 0, unless you ask it for explicitly initialized memory.

As for why the stack is even worse, the same problem of reusing space on the heap causing random noise to be in the memory you just allocated happens on the stack, but the problem is worse because after you returned from a function call, your program just scribbled a bunch of stuff all over the stack above you and didn't bother to clean it up. So you are almost always in the 'dirty' case above.

In the end it is best to make sure that you ensure everything you plan to use is initialized to a known state before it is read from.