> an imperative language procedural language with a clean mapping to ASM

C really isn't as great for this as is often suggested either, not for decades at least

K&R's original compiler on an actual Digital machine from that era makes the case best, but remember this is the era when if you hot loop over modifying a variable your compiler is going to emit memory stores for each iteration - because that's what you wrote, isn't it? No modern C compiler would do this because it's awfully slow.

Likewise that iteration of C doesn't have what you'd recognise as function prototypes, it doesn't care whether your function takes six arguments, here are six arguments the first two are integers, good luck with that. In assembler that makes sense, but you don't do that in modern C either.

C is still a close-to-the-metal language, but it is programming an abstract machine and it is important that the programmer knows that's not really how the machine works, if you want to learn about the machine you will need to write at least assembler and possibly just go learn electronics. Good luck.

> C really isn't as great for this as is often suggested either, not for decades at least

It's good enough for undergraduate teaching. In C, you can easily explain the relation between a struct definition and its layout in memory. It's much more difficult in Caml (what's the relation between an algebraic datatype and its layout in memory?) or Java (which introduces pointers that you never asked for).

We (University of Paris-Cité) are teaching Java in first year, then C and Caml in second year, with seemingly good results.