You've got it backwards. Yes, I do know x86 and the pertinent C implementations rather well. But no, since C abstracts those concepts away, there is a) no need to and b) it actually makes things less portable if you have implicit assumptions about what the machine has and does WHEN C ALLOWS YOU TO NOT CARE ABOUT IT.
So please tell me, given the code
int a, *b = malloc(sizeof *b);
What exactly is the advantage of thinking about `a` and `b` as "on the stack" and `*b` "on the heap"? I truly don't get it.
What is the problem with thinking about `a` and `b` as having automatic storage duration+block scope, and `*b` having allocated storage duration? It's THOSE TERMS that have well-defined semantics that EVERY C implementation (including those that put things "on the stack"/"on the heap") *has* to comply with. (That is apart from the fact that something you think is "on the stack" might well be NOT on the stack because it's "in a register", or got opimized out entirely, rendering your stack/heap categorization as a heuristic at best).
Learn some C. Make your programs more portable. You'll end up a better C programmer.