First as a disclaimer. I have ADD and will never be a great C programmer (I can hack, but my ADD makes it extremely difficult to get the consistency in results that C demands when doing bulk coding, but that's a topic for another time). I have done some C programming and I will do some more. However there are hard limits for me that a lot of other people don't have.
Now this being said, in the environments where I work, I have met a lot of top-notch programmers and a much larger number of mediocre programmers who crank out huge quantities of unmaintainable code. And of course unmaintainable code is contagious: if you work with it, the quality of your own code suffers.
And so I have come to a contrarian perspective on a lot of this.
The difference I think is that the top notch programmers tend to be interested in improving. There is nothing worse than reading through the SQL-Ledger codebase and realizing that despite some modest improvements in security over the years (though not enough IMO) the coding style has never improved (\%$form? Really? Still? And no 'use strict?' what will it take?). Instead they make up for a lack of self-improvement with extra brute force effort in things like testing and debugging.
So this leads me to conclude there are two fundamental types of programmers out there: brute force programmers (the majority), and those programmers who substitute quality of effort for quantity of effort.
The majority of programmers are mediocre and never hit high notes because they believe that what matters is how much time and effort they put into programming. The other programmers spend less time and effort coding, and more time and effort thinking about coding. They recognize that this is where the key investment lies, and that time spent here saves a lot of effort elsewhere.
One problem with programming is that you rarely get immediate feedback on the mistakes that matter---areas like style, clarity, maintainability, and elegance of design. It's only if you go back and question your ability in these areas can you improve. But time spent thinking about these things, going over past efforts and critiquing them, is time that is not spent programming.
I sometimes think programming should be learned first through an apprenticeship, then through journeyman programs where an individual learns from many accomplished programmers, and finally certified to take on students.