People talk about what the stack and heap are and the differences between them. But I am curious to know that if a CPU does not support stack and heap structure, then can C run properly without a stack and a heap?
No, it does not. Let's cover the heap first, that's easy.
An implementation that does not provide a heap of any sort just needs to return
NULL whenever you try to call
malloc (or any other memory allocation function). That's perfectly acceptable behaviour according to the standard.
In terms of the stack, it also doesn't need to provide one. ISO C11 mentions the word "stack" exactly zero times.
What an implementation does need to do is simply be a correct "virtual machine" for all the things specified in the standard. Granted that will be very difficult without a stack but it's not impossible. As an extreme case, there's nothing that says you can't simply inline every single function call recursively. That would use rather a large amount of code and function-specific data space, but it's certainly doable.
However, it's probably something that work convince me to move to another architecture, one that did have a stack (and heap, for that matter).
Having said that, even if an architecture provides neither a heap nor a stack, both of those can be built out of basic memory I/O operations. In fact, one of the earliest computers I ever had as a teen sported an RCA 1802 CPU which had no dedicated stack. It didn't even have a
Yet it could handle subroutines and a stack quite well (for some definition of the word "well") using its SCRT (standard call and return technique). See here for some more detail on how this thing of beauty (or monstrosity, depending on your viewpoint) worked, along with some other unusual architectures.
The IBM Z (a.k.a. System z, zSeries, whatever they're calling it this week) actually has a heap (of sorts, in that you can allocate memory from the OS) but no stack. It actually implements a linked-list stack by using this heap memory along with certain registers (similar to the RCA chip referenced in the above link), meaning that a function prolog allocates local function memory using
STORAGE OBTAIN and the epilog releases it with
Needless to say that puts quite a bit of extra code into the prolog and epilog for each function.