C is a low-level language.
It didn’t use to be. Back in the day when people carved punch cards out of granite, C was an incredible way to be free of the drudgery of lower-level languages like assembly.
But now in these modern times, current-generation languages offer all kinds of features that didn’t exist in 1972 when C was invented. This means C is a pretty basic language with not a lot of features. It can do anything, but it can make you work for it.
So why would we even use it today?
• As a learning tool: not only is C a venerable piece of computing history, but it is connected to the bare metal2 in a way that present-day languages are not. When you learn C, you learn about how software interfaces with computer memory at a low level. There are no seatbelts. You’ll write software that crashes, I assure you. And that’s all part of the fun!
• As a useful tool: C still is used for certain applications, such as building operating systems3 or in embedded systems. (Though the Rust5 programming language is eyeing both these fields!)
If you’re familiar with another language, a lot of things about C are easy. C inspired many other languages, and you’ll see bits of it in Go, Rust, Swift, Python, JavaScript, Java, and all kinds of other languages. Those parts will be familiar.
The one thing about C that hangs people up is pointers. Virtually everything else is familiar, but pointers are the weird one. The concept behind pointers is likely one you already know, but C forces you to be explicit about it, using operators you’ve likely never seen before.
It’s especially insidious because once you grok pointers, they’re suddenly easy. But up until that moment, they’re slippery eels.