Getting the Most Out of Reading Books on ProgrammingReading books is a great way to improve your programming, but reading alone is rarely enough. You have to be willing change the way you think, not just willing to learn a few new tricks or good anecdotes. It takes time and effort to learn how to program really well (though anyone can learn the basics quickly). As it is said, most of your learning will come at the end of a pencil (or sitting in front of a keyboard as you implement an algorithm).
A great way to learn is to take example code and play with it -- first, figure out what it does (or what you think it does). Test it. Now, how can you change it? What happens when you remove a semicolon from your first "Hello, world" program? Can you add strings together with the plus sign -- what happens when you try?
When you're just starting out, learning what kinds of questions to ask and experiment with is part of the intellectual process of learning to program. Curious minds that apply the scientific method of formulating a hypothesis and testing it don't need great textbooks to learn the basics. But once you've done so, don't stop there. Move on to books that don't just teach a programming language so much as they teach computer science and practices that help regardless of the language you ultimately use.
This is especially true of good books on programming, such as Knuth's seminal work The Art of Computer Programming or Structure and Interpretation of Computer Programs (also available online) used by MIT's introductory computer science class. Especially in cases like this, it's important to work the exercises: this is not because the text leaves something lacking, but because the exercises are well-planned to supplement the main work, and help solidify the knowledge gained. Moreover, the material is deep enough to nearly require working the exercises.
In computer science part of the difficulty is that the concepts are quite hard to visualize, and often very detailed. As a result, it's very important to trace through new algorithms a few times to get a complete sense of what is happening, and what each variable means. In other cases, the fundamental reason for some ideas is to deal with the enormous complexity of software (this is one of the reasons object oriented programming is popular). Without sitting down and trying to solve large problems, the reason behind these ideas will never be clear (even after reading such works as Frederick Brooks's classic collection of essays on software engineering, The Mythical Man-Month you will only have a shadow of an idea how complex some things can be).
Because of the value of working problems, some of the best books are those without a single focus, but lots of interesting challenges, such as Programming Pearls, which, by the way, is great -- not a book merely to be read, but to be savored. Many chapters begin with a challenge to be attempted before reading the article -- its solution. Every chapter ends with an excellent set of problems. All that can be said is do them. Books like this can really expand your horizons and help find solutions to all sorts of niggling problems.
Of course, books also have easily codified principles to draw from -- and these are important as a means of gaining experience without living through failed projects. Jon Bentley's followup to Programming Pearls, More Programming Pearls: Confessions of a Coder, contains several chapters of useful principles, including one on "bumper sticker programming", a chapter on programming advice that would fit onto a bumper sticker. The book includes some great war stories to illustrate practical points, such as the time one of his associates spent a week optimizing a section of code, only to learn years later, the first time that section of code was actually used, that the optimization had introduced a bug.
The trick is not to be swayed only by the slogans, but to grasp the deep reasons. Keep a collection of slogans with illustrative examples for practical advice. For algorithms and programming tricks, keep detailed notes on why they work (proofs of correctness, or at least a sketch of the underlying idea), and try to figure it out yourself before going to a reference.
Always keep in mind at all times is that books are not the master: read to learn or enjoy, not just to complete the book. But don't get bogged down with tedious exercises once you really do understand the idea -- don't be afraid to skip a few exercises if you understand the correct approach.
Finally, it never hurts to reread books on the basics. The C Programming Language (2nd Edition), for instance, is worth reading more than once -- think about the basic principles, the foundations, and how you can improve your understanding and your use of those principles. Think about the design choices for C. If you know C++, think about how they differ from C++. Think about how features are implemented and what kinds of potentially surprising effects this might have. In the long run, this approach will only make you a better thinker, and by extension, a better programmer.