I program in C and I believe I know the language well. I understand all the concepts and my problems never come from misuse of the language.

I have problems because I always forget or oversee things. Setting a variable to zero, or generating a particular test case. I keep finding bugs in my code due to conditions I could not foresee or forgot.

Any idea how to fix this? I have been programming in C for some years, but as a job only during the last year and a half. I have problems when systems become complex, and forget/oversee the small details.

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

Maybe you are not meant to be a C programmer. Why do you have to work in C, if low level programming is not your thing? Why not try Python?
–
Warren PJun 11 '13 at 22:25

7

Alternatively are you sure you are incompetent? Many C programmers make mistakes. Me for instance. But I do not consider myself incompetent, merely human.
–
Warren PJun 11 '13 at 22:31

Thanks for your answer. I have to work in C because I work in embedded, at the application level.
–
Pedro PerezJun 11 '13 at 23:03

4

This may sound pedantic, but for your particular set of issues, try a checklist. Before you "finish" anything, check your checklist for that thing. Whenever you encounter something you missed, figure out the checklist item that would have caught it, and add that to the list.
–
NarfanatorJun 11 '13 at 23:24

12

You are too humble to be a proper developer, work on your ego and preferably start some blog too.
–
JubbatJun 12 '13 at 0:16

4 Answers
4

The Devil is in the Details

You're not incompetent. You just lack a bit of attention to details and aren't demanding enough.

Let the Compiler be your Guide

You say you're a C programmer. Let the compiler be demanding of you, and compile (for gcc) with at least: -Wall -Werror -ansi -pendantic -Wstrict-prototypes.

... and Invite its Helpers to the Party!

Make sure to run some code quality tools on your code on top of that. Use the plethora of linters, static code analyzers and others that you have at hand to try to detect possible bugs. Use Valgrind.

Add Constraints to the Mix

Force yourself to write code that targets different operating systems and architectures. Some are way less forgiving than others when it comes to screwing up your memory allocations, and you'll see various results in the way they handle their threading models. As you'll work through these differences, you'll learn to iron out problematic points.

Develop a Keen Eye for Testing

That's not everything though, and they cannot guess what you are trying to do. So get into the habit of thinking of edge cases and good tests for you code. Ultimately, these things will come naturally to you, and writing more robust code becomes a habit. You just don't have the habit yet.

Fail Early, and Fail Hard

Write code that really fails. Meaning that when someone's wrong, it should really fail hard and crash, so the issue is notable and needs to be addressed, instead of weaseling your way out by trying to handle errors and staying alive for as long as you can.

There are different schools of thought, and both have advantages. Defensive Programming is great to write software that is somewhat fault-tolerant and doesn't crash by compromising security of the platform. However sometimes you want to use a design-by-contract approach and enforce these contracts (and the developers know when things would go wrong early on in the dev cycle).

Practice, Practice, Practice

Of course, all of the above is already about that. But maybe what you lack is an incentive to do it and do something great. You mention having issues as soon as things get complex. Then get out of your comfort zone and build something complex. What do you miss in your virtual life, on a regular basis? If you can think of something, can you build it? Start simple, and build something bigger and bigger as you go. See it through, and improve its overall design as you go. Then maybe throw it out and do a full rewrite: now that you have a better insight, you should be able to rebuild this complex system faster, and with a better design not suffering from its initial flaws.

I've been a dev and done a good deal of developer support for years and I'd like to share three good pieces of advice that have helped me in my time.

1. Write code to fail first

Stop writing code with the intention of making it work - doing that is for amateurs and students. Code that only works is in many respects a single use case with failure always an option. Instead write code with the expectation that any actions that can fail will at some point. Only when every possible failure condition has been exhausted can you be reasonably sure your code will work. What if that memory isn't allocated, file isn't available, data is corrupted or that stack under/overflows?

2. Accept that as a programmer you are not as good as you think you are

...and you never will be. When we programmers accept that we will all make mistakes then will we apply ourselves to be thorough. Each mistake is a learning opportunity and each bug is not a bug, it is a class of bugs - if you don't validate input in one place and your code barfs, fix it and then consider where else that might be the case in your code.

3. Use the resources available to you

There are so many resources open to devs now, fix compiler warnings if you can. Code quality tools available, some for free - in C# I like to take code and throw Pex at it and see what failure points it found that I had missed... an exercise like that is a real eye opener! Refactor some old code as a mental exercise, set yourself a time limit so as not to spend all day on it. There are people around you who can do peer reviews use them. Learn a different language - not because you specifically intend to use it, but because it will exercise your thought paths and ways of thinking about things in your chosen language.

Use a strongly-typed language with some ceremony, like C#. C# will force you to write your code in a more structured, object-oriented way, but it still looks like C. The strong typing will ferret out some of the errors you described, at compile time.

@Lundin sure, we will just ignore the fact that it can be used for websites, web services, windows phone programming, windows surface programming, hell there is even a smart watch that you can program apps for with c#, not to mention that with the xna framework it also sits on xbox's too.
–
RhysWJun 12 '13 at 8:52

1

@RhysW How about the 50 CPUs in your car? How about all the hundreds of CPUs in your home, controlling your washing machine, your TV, DVD, heat? Airplanes? Space shuttles? How about all the internal hardware in your PC such as hard drives, GFX card, DVD etc? Or the CPU in said Xbox? How about anything outside the narrow branch of Windows desktop programming?
–
user29079Jun 12 '13 at 11:15

1

@Lundin i never said it was used for everything, just that it wasnt restricted solely to desktop apps
–
RhysWJun 12 '13 at 11:21

1

I'm sorry, I think this is a pretty terrible answer. C# looks like C?!?! As in, it has curly braces? It's a totally different language with a totally different design philosophy and use case. Sure, learning more stuff will always make you a better programer, but this is neither relevant to the OP's question nor does it have any truly interesting insights. Also, why stop at C#, what about Haskell or D?
–
MrFoxJun 12 '13 at 17:16

The only way to attain it is to learn from your mistakes and take steps to not make them. It's unfortunate that you haven't learned this after a few years. Turn on all compiler warnings, treat warnings as compiler errors and see what that turns up.

Static analysis can also be of help here in showing you flawed code paths.