So C isn't perfect. The hardest types of errors to track down are compiler errors, and trust me, they do exist.
How do you get out of the aforementioned errors? Listen up:
Syntax:
  • = vs. ==: Common simple mistake. Hardly even worth making more than once, but it happens all the time, especially to people who type quickly. How do you get around it? Get in your head to think like this:
       if(0 == myVar)

    Get people to stick the number on the left. What happens when you put a single equals sign? "Invalid L-value", right there, in your face, in the compiler, problem squashed.


Binary:
  • Memory leaks: Perform memory sub allocation, or do your own memory management. Think of it like matter in chemical reactions: Memory can neither be created nor destroyed. You shouldn't have more than zero when you close down, and you shouldn't try to get rid of something that shouldn't be. Overload new (if you are a c++ junkie), or make a debugging malloc macro that writes down how much memory you are malloc-ing and add it to a global variable. If you end up with too much ( > 0)left over, get rid of it, or throw an assertion. Using a memory sub allocation library to do all of your memory allocation (like to do it in 4k chunks for performance on a paged system), would do you well, but it a little over the top for some applications.
  • Crashes: GDB, VS Debugger, WinDbg, these are all your friends. Set breakpoints, trace, watch your locals.
  • Buffer overflows: It's definately hard to spot a place where buffer overflows can happen. A lot of ways people check uncharted memory is to null it out with something first, something that would show up really well in a debugger. We used to try to come up with new and interesting ones, like DEADBEEF or BADF000D. All in all, you need to use some kind of protection on your input, and be dead careful. This is something that plagues the industry, because buffer overflows happen (it's a weakness in C, since it is compiled code, and doesn't have language support for flex buffering).


The worst errors you can run into are the compiler or API errors. For compilers, they are usually memory or optimization related, and have to do with when you have a massively complicated program you are writing. Why are they terrible? Because it's hard to prove it's the compiler. It's your code vs. theirs. API bugs are bad, because the point of most APIs is to keep the user away from the lower levels of the program. (Bummer, it died in WinExec? What the heck is that?!?).

C is as good as any other compiled language. It has it's ups and downs. When working at Microsoft, a friend of mine always complained in that he had to work with beta software, on a beta system, with a beta compiler. In those situations, every little line can send your program burning down in flames. Systems reach an entropy point, and sometimes I used to felt that we always teetered on the edge of that. If only "oh I forgot an equals sign", or "oh darn, off by one, forgot about the null terminator" was the cause of most of these problems