If, on the other hand, you’re in the habit of shotgun debugging, where you make repeated changes to the problem code until it appears to work, you’re quite likely to leave behind various problems that will be hard to figure out.
Often, experience is the best teacher. If you’re not exposing your program to malicious users (aka. the public at large), the most serious issue you’re likely to run into is either a program crash or data corruption— nothing that will really harm your computer, but may cause you grief as you try to figure it out. In that process, though, you’ll learn an awful lot about how everything works. So, go write some programs for your own use and see how they crash and burn so that the next thing you make is more stable. Eventually you’ll start to intuitively spot trouble before it actually happens.
Writing Secure Code
https://www.amazon.com/Writing-Secure-Second-Developer-Pract...
Secure Programming Cookbook for C and C++
http://shop.oreilly.com/product/9780596003944.do
SEI CERT C Coding Standard
If you are interested in learning more about writing complex software in C consider checking out HandmadeHero.
Sadly there need to be more good resources on learning how to write good C and low level software. I am hoping my article can be a starting point for people who wish to learn about library design for example.
While UB quirks exist, they are WAY off the beaten path and it takes an effort to run into them. Doubly so if you are just starting with the language.
Just treat C as a thin convenient layer over the hardware that expects you to think and act responsibly in exchange for this nearly raw access.
Not to mention compilers make fun-times out of this by sometimes zeroing memory in debug and then not doing so for release builds (Hi MSVC!)..
The "thin layer over hardware" idea is a thing of the past as soon as optimizations come into the picture, and even then.