top | item 26911399

Beej’s Guide to C Programming [pdf]

507 points| tumblewit | 5 years ago |beej.us | reply

171 comments

order
[+] signa11|5 years ago|reply
Jens Gustedt's "Modern C" (https://modernc.gforge.inria.fr) is an excellent resource as well.
[+] k_sze|5 years ago|reply
Jens Gustedt is a co-editor of the ISO C standard, so he knows his shit. Modern C is probably the best book about modern C, short of reading the standard.
[+] gnuvince|5 years ago|reply
What does "modern" C imply? AFAIK, there are not very many new language features; is it about organizing code differently than what one would learn from K&R?
[+] potbelly83|5 years ago|reply
Nice book. As a C++ programmer how much of its discussion related to C's storage/memory model would carry over to C++?
[+] transient_47|5 years ago|reply
I stumbled upon this gem a while ago [0] while looking for a decent tutorial and reference to C:

Stuff that should be avoided: [...]

Beej's Guide to C: http://beej.us/guide/bgc/output/html/singlepage/bgc.html

Full of mistakes.

[...]

Could someone confirm this? I've seen a lot of threads here on HN praising beej's guides so I am somewhat confused.

[0] http://www.iso-9899.info/wiki/Main_Page

edit: Formatting

[+] determinateproc|5 years ago|reply
Beej himself lists this as an 'alpha-quality document' on the download page [0] and if I remember correctly, it has been so for years. Wonder why this is posted here on HN.

[0]: http://www.beej.us/guide/bgc/

[+] tom_mellior|5 years ago|reply
On a quick skim of some introductory parts I found:

> When you have a variable in C, the value of that variable is in memory somewhere, at some address. Of course. After all, where else would it be?

It would be in a register. Of course. Or it would be eliminated by a compiler optimization. Of course.

Same error later on:

> When you pass a value to a function,a copy of that value gets made in this magical mystery world known as the stack

No. In most common cases, arguments will not be passed via the stack. This goes on to clarify in a footnote that the implementation might not actually use a stack, and that the stack has something to do with recursion. That part is true, but the values saved on the stack for recursing are not the same as function arguments.

Neither in the Variadic Functions chapter nor anywhere else are the default argument promotions mentioned -- this will bite someone who tries to write a variadic function that gets floats out of the variadic argument list, which you cannot do, since passing a float to a variadic function promotes it to double.

Speaking of floats... This is one of those tutorials that are very confused regarding their target audience. For example, in the "Variables" section it goes out of its way to define: "A “byte” is an 8-bit binary number. Think of it as an integer that can only hold the values from 0 to 255, inclusive." (which isn't the C definition, but this really is nit-picking) but then happily goes on to talk about Booleans and floats without explaining what those are. What reader has a background that would make this useful?

Overall, from the little I've seen, I'd give this an initial rating of "broadly correct but with definite mistakes".

Even if it were fully correct, I dislike the verbose style, and I wouldn't recommend this tutorial. For example, in the Hello World chapter, we have the following "explanation" of the line "#include <stdio.h>":

> Now, what is this#include? GROSS! Well, it tells the C Preprocessor to pull the contents of another fileand insert it into the code rightthere.Wait—what’s a C Preprocessor? Good question. There are two stages (well, technically there are more thantwo, but hey, let’s pretend there are two and have a good laugh) to compilation: the preprocessor and thecompiler. Anything that starts with pound sign, or “octothorpe”, (#) is something the preprocessor operateson before the compiler even gets started. Commonpreprocessor directives, as they’re called, are#includeand#define. More on that later.Before we go on, why would I even begin to bother pointing out that a pound sign is called an octothorpe?The answer is simple: I think the word octothorpe is so excellently funny, I have to gratuitously spread itsname around whenever I get the opportunity. Octothorpe. Octothorpe, octothorpe, octothorpe.Soanyway. After the C preprocessor has finished preprocessing everything, the results are ready for thecompiler to take them and produceassembly code8,machine code9, or whatever it’s about to do. Don’t worryabout the technical details of compilation for now; just know that your source runs through the preprocessor,then the output of that runs through the compiler, then that produces an executable for you to run. Octothorpe.What about the rest of the line? What’s<stdio.h>? That is what is known as aheader file. It’s the dot-hat the end that gives it away. In fact it’s the “Standard I/O” (stdio) header file that you will grow to knowand love. It contains preprocessor directives and function prototypes (more on that later) for common inputand output needs. For our demo program, we’re outputting the string “Hello, World!”, so we in particularneed the function prototype for theprintf()function from this header file. Basically, if we tried to useprintf()without#include <stdio.h>, the compiler would have complained to us about it.How did I know I needed to#include <stdio.h>forprintf()? Answer: it’s in the documentation. Ifyou’re on a Unix system,man printfand it’ll tell you right at the top of the man page what header files are required. Or see the reference section in this book.:-)Holy moly. That was all to cover the first line! But, let’s face it, it has been completely dissected. No mysteryshall remain!

Only one sentence of this is relevant for an introductory Hello World chapter: "Basically, if we tried to use printf() without #include <stdio.h>, the compiler would have complained to us about it." None of the rest is relevant or helpful to a beginner who is just seeing their first ever C program. Also "completely dissected" isn't true either; there is a lot more to be said about headers.

[+] blunte|5 years ago|reply
IMO, pointers are less difficult to comprehend than other abstractions, like lambdas are.

If you know how to walk down a street and stop at the right street number, then you have used pointers. And if you've ever observed that one tall building may "cover" a range of street numbers, such as 200-220, then you should understand how to move from one 4-byte "value" to the next in an array in memory.

Anyway, many more analogies... probably better than this one.

Maybe unions could make using pointers a bit more challenging, but again, tall buildings next to short buildings and so on. We do this kind of pointer calculation in real life.

[+] atoav|5 years ago|reply
What pointers basically are is not particularly hard to grasp. What is harder to grasp it what can be done with them and how you can shoot yourself in the foot with them in non-obvious ways.

I think I only understood much of it once I learned Rust, because you realize: Ah, that thing I once did in C is something that maybe ahouldn't be possible at all without extra steps. Even if I were to nwver use Rust again, this definitly helped to understand how to use pointers more safely.

[+] qsort|5 years ago|reply
What's difficult to understand about pointers isn't the concept of a pointer itself, or even * and &, it's the fact that working with pointers requires you to simultaneously understand different abstraction levels. While it's not unique to pointers, and it's in fact the case for most nontrivial programming tasks, what's unique about C is that pointers are so pervasive you can't really do anything if you don't understand how to work with them.

IME languages like Python aren't any easier than C to work with (ignoring UB issues of course), but it's certainly the case that you can probably kinda sorta get your job done with Python even without understanding the first thing of what you're doing, and that's not happening if you write in C.

[+] cassepipe|5 years ago|reply
Pointers aren't that complicated but C syntax is misleading imho until someone comes along and tells you that the declaration syntax "follows use", which does not seem like the greatest idea. Then you get used to it and forget about it but when you don't know the principle behind declaration syntax, it does not help you reason about the language.
[+] chowells|5 years ago|reply
Well, you've demonstrated that memory addresses aren't that hard. But you've also demonstrated how easy it is to get undefined behavior in C programs.

C's pointers aren't memory addresses. Ok, they tend to be represented as such at run time, but that's not what the spec actually says the are. And as far as compiler authors are concerned, they can do anything they want as long as it's within spec. Further, the spec even requires some additional behaviors pure memory addresses aren't capable of. See https://www.ralfj.de/blog/2020/12/14/provenance.html for examples of the extra requirements.

Compared to that mess, lambdas are trivial. They're just functions.

[+] jhgb|5 years ago|reply
> If you know how to walk down a street and stop at the right street number, then you have used pointers. And if you've ever observed that one tall building may "cover" a range of street numbers, such as 200-220

I see that as a European, I have virtually no chance to understand pointers using street numbers. :)

(Fortunately I've never had problems either with lambdas or with pointers.)

[+] mytailorisrich|5 years ago|reply
C is an abstraction over assembly, really (benefits being that it is simpler by being more abstract and portable across CPU types).

I've always thought that an introduction to CPUs (can take a simpler one as example) and how they work, how memory is (usually) organised, and to assembly would go a long way in helping understand many programming issues and C.

My experience is that C or programming concepts are often taught in a very abstract/mathematical way, which can be hard to grasp compared to a more practical approach.

If you take a concrete example where memory is effectively an array and indices are addresses (which holds true for most cases and, in any case is a good example) then understanding pointers becomes basically common sense and notations are simply conventions of the language you're using.

[+] ricardobayes|5 years ago|reply
Like my professor used to say, if you ever saw a pidgeon, you know what vectors are.
[+] augustk|5 years ago|reply
For anyone who wants to learn about pointers I can recommend studying a language simpler than C like for instance Oberon where pointers are more restricted. Having a look at Oberon can also broaden your view even if you know pointers in C.

  https://www.miasap.se/obnc/oberon-report.html
  http://people.inf.ethz.ch/wirth/Oberon/PIO.pdf
[+] billfruit|5 years ago|reply
There was a "C Unleashed" book, a massive tome of 1000+ pages written by many famous programmers, many of them who where quite active in comp.lang.c, like Richard Heathfield and CB Falconer, had quite insightful material in it.

Any one remember the heyday of comp.lang.c? I wonder what goes on in there now.

[+] ben_pfaff|5 years ago|reply
I wasn't sure anyone but the authors remembered C Unleashed! I wrote the chapter on binary search trees and balanced trees.

Comp.lang.c was important to me for many years. I've met 5 or so of the regulars at least once. The most famous comp.lang.c regular is probably Tim Hockin of the Kubernetes project.

[+] beej71|5 years ago|reply
I bought that book ages ago. Good stuff. comp.lang.c still has a small group of knowledgeable regulars, but a lot of the "old guard" seems to have stepped away. And Usenet is a shadow of its former self, obviously.

Reddit has more traffic nowadays.

[+] mistertester|5 years ago|reply
Yes, usenet was huge for me back in the early 90s when I had questions on C programming. I would ask them on comp.programming.c and had some of the best programmers providing guidance. Of course they were strict with questions/discussions being specific to ANSI C.
[+] dang|5 years ago|reply
It doesn't do the brisk business of the networking one, but there have been at least a couple past threads:

Beej's Guide to C Programming - https://news.ycombinator.com/item?id=26100391 - Feb 2021 (1 comment)

Beej's Guide to C Programming (2007) - https://news.ycombinator.com/item?id=15198093 - Sept 2017 (79 comments)

As long as we're talking C programming, I'd single out this large thread with C Standards committee members from last year:

Tell HN: C Experts Panel – Ask us anything about C - https://news.ycombinator.com/item?id=22865357 - April 2020 (962 comments)

[+] caseyavila|5 years ago|reply
> It’s especially insidious because once you grok pointers, they’re suddenly easy. But up until that moment, they’re slippery eels.

I'm sort of a C beginner myself. I understand pointers, and I do remember they clicked in my mind suddenly. The moment before, I didn't understand at all. I also love the quirkiness of this guide. Definitely going to give this a read.

[+] andi999|5 years ago|reply
Do you mean the general concept or like: a is a pointer to an array of functions which return pointers to functions which return ints and take double arrays as parameters.

This somehow never really clicked (or actually it clicked and declicked somehow)

[+] rubicon33|5 years ago|reply
I love Beej’s guide to network programming. Back when I was just starting to learn to code, I wanted to get right down to the low level C stuff and his guide was what I used. It was simple and approachable and I had a running TCP client by the end of the day. It was a thrilling experience for a young novice.
[+] 3rly|5 years ago|reply
I see a lot of people making opinions that clearly shows that they have not audited the entire guide. For the intended audience that the author wanted to reach. I will say that he accomplished it.

For anything that one finds as mistakes, the author went out of his way (via references) for the reader to dig further.

[+] tumblewit|5 years ago|reply
From the creator of the famous Network programming in C guide.
[+] aphrax|5 years ago|reply
I've enjoyed this guide a number of times but each time I hit a brick wall trying to understand pointers. I'm still keen to learn but it just doesnt 'click' for me...

Edit: poor grammar

[+] DyslexicAtheist|5 years ago|reply
around 25 years ago I got so frustrated because I hit the same brick walls over and over especially with advanced pointer stuff. It sounds silly today but what helped me are some really basic books about C. iirc the "for dummies" series and others.

It took another couple of years until I understood what I lacked wasn't time spent reading another section on pointers but additional tooling. Using a debugger and stepping through programs was the next breakthrough.

Looking back today understanding my C (on UNIX) isn't just the language it's a whole ecosystem of tools to measure what is going on and manipulating state so that I can troubleshoot. After gdb came valgrind, strace, lsof, signal handling (kill), process control, gcov, the appropriate type of CFLAGS to use (e.g. the compiler itself) and how to stay sane using Make.

None of them have to do with pointers but they make life a lot easier. To become productive at this takes years but becoming good took me decades. C (imho) isn't just another language but a complete career path with dozens of branches into other areas.

If you stay patient with yourself and treat it as a journey instead of a milestone it can deepen your understanding of systems (nod to eBPF) in situations many others will bail out long before.

Don't give up and then not much will look scary any more.

[+] throws23577|5 years ago|reply
I haven't read these 2 books, but would like the opinion of someone who did.

[1] C Interfaces and Implementations: Techniques for Creating Reusable Software by David Hanson - HN's tptacek seemed to rave about this book, that's how I heard of it. Wonder what he thinks of it in 2021.

[2] C Programming: A Modern Approach by K. N. King - this one seems to be loved by many. Seems to be more 'beginner-friendly' than the 1st one I guess.

[+] Spivak|5 years ago|reply
Is there any guide that operates at the level of the C abstract machine and a real platform because it's always really jarring to have lots of hand-wavy statements like

> When compiling C,machine codeis generated. This is the 1s and 0s that can be executed directly by the CPU.

No! Tell me about how the code is translated into an ELF executable, linked, has its memory laid out by the OS and then executed.

> I’m seriously oversimplifying how modern memory works, here. But the mental model works, so please forgive me

No! Tell me about how memory works in the C abstract machine which is what you can actually program against and guaranteed by the compiler.

> Nothing of yours gets called before main(). In the case of our example, this works fine since all we want to do is print a line and exit

No! tell that main is special because it's mapped to the _start symbol or at least eventually jumped into by code at that symbol which has an address that's stored by the linker in e_entry.

Like I might be the weird one but this kind of writing (which is common to seemingly all C texts) confuses me more than if it had just been explained.

[+] DyslexicAtheist|5 years ago|reply
it actually has working examples for all of the C library calls even math routines. Not sure if it's complete but it seems so. This seriously helps bridging the gap between man (2) pages and putting things into working code and only beef I have is that I didn't have it 25 years ago. Very cool.
[+] beej71|5 years ago|reply
It's not complete... There are tons of functions in C11+. I'm whittling it away.

Putting in the examples for all the calls--I stole that idea from The Turbo C Bible, a book I really loved back in the day... because of the examples.

[+] saagarjha|5 years ago|reply
Nit: most of the C library calls are in section 3; section 2 is system calls.
[+] dcchambers|5 years ago|reply
Beej's Guide to Network Programming helped me survive a grad-level computer networking class as a naive undergrad in college.

If his guide to C is anywhere near as good it should be an awesome resource.

[+] beej71|5 years ago|reply
The C Guide is still rough around the edges (and even some in the center). But I'm working on it! :-)
[+] qwerty456127|5 years ago|reply
Again, the string chapter is telling us about zero-terminated char arrays/pointers and doesn't even mention Unicode/UTF-8 or safety :-(
[+] beej71|5 years ago|reply
I do have a chapter on Unicode and wide characters, but it's separate from the "classic" strings chapter. That said, I could certainly refer forward to it.

And C11 only has minimal portable UTF-8 support, but I do talk about it. I think C21 will improve on that a bit.

A note on safety would be well worth it. I'll do that. Good suggestion.

[+] emilengler|5 years ago|reply
A thing I really enjoy about this guide is that it’s close to common C paradigms and practices. Many guides lack this and only show outdated ones.
[+] enahs-sf|5 years ago|reply
I love C programming. Even though people say it's dangerous and easy to shoot yourself in the foot, It really is the simplest and most elegant way forward. That said, having to invent the wheel yourself so much, it is not as time efficient as some more modern languages.

I liken it to an artisanal craftsman's tool versus a modern multi-tool like a dremel which would be something like python.

[+] seibelj|5 years ago|reply
Totally agree - sometimes I solve small problems in C rather than a scripting language. It feels like freedom and the result is so damn fast.