The C standard makes no mention of a stack or stack frames it just describes the behaviour of various types of variable as Don has already stated.
However enough platforms implement stacks and stack frames that they are worth understanding. Generally speaking a stack frame contains everything required to let a function execute. That would normally be interpreted as space for the function parameters (or a pointer to them), space for all the local variables and all the data required to return from the function. The data required to return from the function is at a minimum the return address for the instruction pointer but often includes other processor registers, may be even all of them and the address of the previous stack frame.
In some micro-controllers, in my experience mainly low power self-contained ones, the return address stack is sometimes implemented as a separate hardware stack. This is finite in size and if used limits the number of function calls that can be made.
One of the differences between C and C++ is who has the responsibility for unwinding the stack, removing the stack frame. IIRC in C it is the called function, in C++ it is the calling function. This change was required in C++ to allow exceptions to work properly since an exception can cause a function to exit on any line of code.
So (in C) when a function is called the calling function does something like
- pushes the processor state (registers) onto the stack
- pushes the return address onto the stack
- pushes the size of the current stack frame or an end of stack frame pointer onto the stack leaving space for the local variables of the called function
- pushes the function parameters onto the stack
Note that this is very generalised, different platforms will push slightly different things and in a different order, this is just the sort of things that get pushed.
On return the called function restores the processor state from the calling function and jumps to the return address.
Many processors have a register dedicated to storing the current stack frame.
The return value of a function might be passed via the stack or again might be passed in a register.
Once you have a handle on how a stack frame is used to facilitate a function call then you are at least half way to understanding how interrupts and multi-threading is often implemented in an embedded environment.
When an interrupt occurs the process pushes an interrupt frame onto the stack. This is akin to a stack frame but contains no space for parameters, local data or return value because execution is not jumping to a function but rather a completely different context. The the processor jumps to the relevant interrupt handler, note in the case of an interrupt the processor may also change some processor registers or flags in indicate that it is running an interrupt routine. It may even have a separate interrupt stack that it uses while processing a interrupt routine. Once the interrupt finishes the processor pops its original state from the stack and continues executing the normal code where it left off.
Multi-threading operates similarly often. Every thread has its own stack, when a task-switch happens the processor stores a task switching frame (similar in contents to an interrupt frame) on the stack of the current thread. Switches stack to the new threads stack and pops its state from that stack to continue running the new task from where it was last running it.
Assuming that any given platform you use has a stack then
Details of the stack frame and interrupt frame can be found in the platform (processor) documentation.
Details of the task switching frame might possibly be in the platform specific documentation for the OS that you are using but more often than not is not documented (at least in publicly available documentation).