C doesn't necessarily teach you how computers work. But it does teach you how software works. Our modern software empire is built on mountains of C, and deference to C is pervasive throughout higher-level software design. >You may have heard another slogan when talking about C: “C is portable assembler.” If you think about this slogan for a minute, you’ll also find that if it’s true, C cannot be how the computer work…
C at the very least teaches the difference between stack and heap memory, a crucial concept obscured by most higher-level languages.
For convenience, many architectures have a single assembly instruction for taking one register (called the "stack pointer"), adjusting it by a word, and moving a register to the address at that word, and a corresponding instruction to move data back to a register and adjust it in the other direction. That's the extent of the abstraction. You can implement it with two instructions instead of one, and then you get as many stack pointers as you want. Zero, if you want.
There is no "heap" on modern OSes. There used to be a thing called the program break, beyond which was the heap. It's almost meaningless now. You ask for an area of virtual memory via mmap or equivalent; it is now one of several heaps you have.
And you can pass around pointers from all your stacks and all your heaps in the same ways, as long as they remain valid.
You need to understand this in order to understand how thread stacks work (you typically allocate them via mmap or from "the heap"); how sigaltstack works and why you need it to catch SIGSEGV from stack oveflows; how segmented stacks (as previously used in Go and Rust) work; how Stackless Python works; how to share data structures between processes; etc.