StackOverflow is the de facto standard place to go when you need to figure out how to do something as a programmer. A web search for information about how to check the number of lines in a file using the C programming language will probably give you StackOverflow questions as the most relevant search results. Unfortunately, while writing good, clean, reliable C does not need to be difficult, it is certainly difficult to find information about how to do it well, and the people answering these questions on StackOverflow are not filtered by their skills or knowledge of good practices. From time to time, the top-rated answer or the accepted answer is even the worst answer that addresses the question.
The best example I have seen of a straightforward line count algorithm is in a place that might seem obvious after the fact: the source code of the
wc command line utility. Figure out how the
-l option is handled in a good implementation of
wc, and all that's left is to adapt it to your needs. Ideally, the solution you find should be short, simple, careful (e.g. checking for error conditions), robust, well-worn, and well-formatted.
The C coding standards of the OpenBSD community are among the highest and most pragmatic you'll ever find, and when someone makes a decision about implementation whose reasoning is not pretty obvious in the code itself you're almost certain to see that reasoning clearly documented in code comments, which can also teach you something about being a good programmer in general. The OpenBSD source tree is the best place to start for such questions, in my experience, and it's where I went to check my own thinking about how to count lines recently.
OpenBSD is a great place to start when all you need is some guidance on what function to use for something, as well. You may have heard
atoi() is not a function you should use. If you haven't heard before, you have now. There are some great resources on the internet that describe why it's a terrible idea to use
atoi(), and a plethora of other deprecated functions in good C programming. What should you use instead?
That's a good question, and it turns out OpenBSD has the answer, in almost every case, in a manpage. Use the
man atoi command on an OpenBSD system, and you'll find a caveats section of the file that talks about
strtonum() as alternatives; check their manpages for more details. (Spoiler:
strtonum() is almost always what you want.) The same applies to things like why you should generally use
snprintf() instead of
sprintf() (explained in the caveats section for both functions and a bunch of related functions),
strlcat() instead of
strcat() (in the description section of
man strcat), and
strncmp() instead of
strcmp() (they share a manpage, which includes information about why to choose one over the other). If you don't have easy access to an OpenBSD system, you can always check OpenBSD manpages online, too.
The "check OpenBSD" technique is not perfect for finding the best ways to do things in all cases, but it's the quickest, easiest way to get a better idiom or function choice than you would likely have found otherwise. In the majority of cases when something is in the OpenBSD codebase or OpenBSD's manpages it's about the best you're likely to get. An example of a slight shortcoming is that, while the manpage for
calloc() does give good guidance for reasons to prefer
calloc() most of the time in the caveats section, it is not explicit about one of the most important reasons: zeroing out the memory you just allocated, automatically, to protect leftover data from software previously running on the system (for instance). That manpage also talks about initialization overhead for
calloc(), but it turns out
calloc() is often faster than
malloc() for reasons of arcane implementation details.
That, however, is not something you will likely find in a web search for the best way to allocate memory in C at all, possibly excepting specific searches for all the gory details about how
calloc() work under the hood. The fact that StackOverflow answers will give
malloc() solutions where
calloc() would be better, as often as not, helps make my point. There's a lot of information on StackOverflow, but let the reader beware. Sanity-check the answers against OpenBSD source code and documentation.
In short, when you need to write C, OpenBSD is excellent C documentation.