- Get the `cdecl` tool to build intuition about function signatures. What does "int( * ( *foo)(void))[3]" mean?
- Write it yourself.
- Be disciplined. Develop good hygiene with compiler flags, memory/address checks, and even fuzzing.
- Read good source code such as the linux kernel. This is an amusing header file from the git source code that defines some banned functions. This is wisdom if you choose to follow it: https://github.com/git/git/blob/master/banned.h
- Push the language to its limits. Play with memory and data structures. Inspect everything. This book "Data-Oriented Design" by Richard Fabien is a great to explore as well. It's about organizing your data for efficient processing.
¹https://www.amazon.com/Programming-Language-2nd-Brian-Kernig...
That book is legendary only in the magnitude of financial damages it (directly and indirectly) enabled, caused by people who read it and thought that they could now write C.
I worked through this and felt well-prepared to actually use C in anger when I had to.
The last bit is also true for K&R The C Programming Language (avoid at all costs).
You're better off with:
- Modern C (whatever edition is current)
- Seacord's Effective C: Introduction to professional C programming
- C Programming: Modern Approach 2nd edition (bible)