What do you want to see in Learn C The Hard Way?

53 points by alnayyir ↗ HN
I bought the domain to force myself to do something with the free time I'll soon have an abundance of.

I want to see more young programmers doing systems programming and making cool things with the language that forms the basis of almost everything we use.

What do you want to see covered in a 'book' that purports to teach C the hard way? :)

I will be following Zed's example, although I'll be influenced by my learning under K&R. I really do want to be demonstrating proper, modern C.

126 comments

[ 2.4 ms ] story [ 205 ms ] thread
One important thing I would like to see in such a book is one or more chapters devoted to memory management best practices.
100% agreed, I see way too many people struggling with realloc/calloc in ##C, let along comprehending heap fragmentation.
A good solution for this would be to make one of the exercises to be building your own heap allocator.
I don't know if this is outside of the scope of your plans, but threading issues are a big one that jump out for me. POSIX threads can cause all kinds of wonderful headaches, it would be nice to see some solid advice on the does and dont's.
I plan to follow Zed's model for 52 exercises, I don't see any reason why I shouldn't cover multi-threading and a perhaps a few different concurrency models in the latter half.
I think your goal will be more easily and better achieved by writing a "So You Found Python Easy?" book. C is not (IMO) a good language to teach people that are just starting to program.

However, if you wish to try anyway, I recommend looking at "Assembly Language Step-by-Step: Programming with Linux" by Jeff Duntemann. It aims to teach people assembly language as their first language, so you may find it useful.

I'm doing this book precisely because programmers who already know a language aren't ever getting around to learning systems programming or how things work.
I hear you, I voted a few days ago for the C book and this is why I did (and I'm primarily a Python guy).
I am doing this precisely for you and everyone like you.

I'm a professional python dev :)

Thanks, I will be checking it out and definitely using the final product.
Ok, that's fantastic! I hope you succeed.

But it's a bit misleading to call it "Learn C The Hard Way" after LPTHW, if your intended audience is experienced programmers. The whole point of LPTHW was that it was for beginners.

Top of their website: "The book is a very beginner book for people who want to learn to code. If you can already code then the book will probably drive you insane. It's intended for people who have no coding chops to build up their skills before starting a more detailed book."

As Zed stated, his concept of LCTHW isn't for beginners to programming.

K&R has sated that need.

It's easier to understand what I'm aiming for when you've already gone through the rigamarole of learning C from the existing texts.

Make sure you explain pointers well, the additional level of indirection introduced by them is usually hard to grasp for beginners.

Show the relation between pointers and arrays. Offer some best practices on using pointers. Explain the most common caveats like buffer overflows, problems with null terminated strings or off by one errors.

Even better, make sure you explain function pointers well.
Even better, I'll explain when and why to use function pointers (finite state automata are a common use case)
I think a more common and more important use is callback functions.
Some years ago, I ran across and saved off a copy of a some-dozen page reference, in PDF format, titled something along the lines of 'everything you (will) ever need to know about pointers (in C)'. It appeared to be quite well regarded.

But, that laptop was ripped off and the particular file appears not to have made it into backups.

Does this description happen to ring a bell? Any references?

I second the proper teaching of pointers. However, make sure you explain variables just as well, for they too introduce a level of indirection¹, which is almost always overlooked.

C doesn't syntactically distinguish rvalues and lvalues, so this level of indirection often goes unnoticed. I strongly suspect this is why learning pointers is often hard: trying to grasp an additional level of indirection before having comprehended the first one is nearly hopeless.

[1] Variables are containers for values. This is isomorphic to a constant pointer to a mutable cell.

Other than K&R (which everyone knows about), what is the current CW on best C books?
You usually have to get pretty implementation/purpose specific beyond that. More often than not, the next step is APUE, which is dissatisfactory for what I have in mind.
C Interfaces and Implementations is really good: http://www.amazon.com/Interfaces-Implementations-Techniques-...
Different books work for different folks, and lots of people seem to love this one. I however love C and found this book to be an abomination. K&R is brilliant. Given an opportunity, I would eradicate this book from the face of the earth lamenting only the damage it has already done.

Examples provided here: http://news.ycombinator.com/item?id=1705332

What would be the scope of the book?

I saw Zed mention the same title on his blog once. His idea was to provide something for programmers with experience in other languages and some basic knowledge of C. As I fit in that category, I'd like to see something beyond K&R. Especially some stuff on organizing modern projects written in C, makefiles etc.

Just one request: Would you be able to release individual chapters as you are done with them instead of waiting to finish the whole book? Thanks!
Plan on it, I'll be working on a tight feedback loop since I'm not even remotely qualified enough to be doing this.
Lots of segmentation fault diagnosis
I know a lot of new people run into perpetual segfault, but I don't think that's really a HUGE hang-up once you get past the basics.

I'll consider some "break it and fix it" exercises for diagnosing these kinds of problems though.

Honestly the closer you stay to the spirit of K&R the better the site would be. I've looked at a lot of C books over the years and K&R is the only one I thought was even decent.
I'm not trying to replace K&R, but I'll be inspired by it since I grew up with it.
Yeah I know but if you bring something in the same spirit to the web it might be good.

I grew up as a programmer reading it too so I appreciate what you're saying.

whatever you do, make your examples bulletproof. even if it's not how you would normally write the code and it seems overly cautious, do your audience a favor and write the example that way anyway.

if there are any buffer overflows, integer overflows, off-by-one's, signedness issues, failure to check return values of everything, use of typically insecure things like sprintf instead of snprintf, all of these problems will just carry over into your readers' code. please do us all a favor and stress the importance of writing secure code from the ground up and not as an afterthought or something only done just before releasing it.

I don't think the learner would appreciate the subtleties, and I don't agree that they'll learn anything from it.

I can reinforce each lesson/problem you're describing one by one through the exercises, but a new person simply wouldn't know good code if it slapped them in the face.

Confer with Learn Python the Hard Way to get a feel for the aesthetic and technique I'm working towards.

I don't want to write bulletproof code, I want to teach them how and why to write bulletproof code.

I'm not qualified to meet that kind of lofty standard anyway.

I don't think the learner would appreciate the subtleties, and I don't agree that they'll learn anything from it.

I can reinforce each lesson/problem you're describing one by one through the exercises, but a new person simply wouldn't know good code if it slapped them in the face.

that is my point: your readers might not understand everything you're doing, so they're just going to copy and paste parts of it into their new projects. if you give them sloppy code to learn from, they're going to copy that sloppiness into their code that makes its way into the real world.

there are a lot of things in c that new programmers have to be especially careful about that aren't relevant to python.

(comment deleted)
Actually you're the one who's out of line here, for attacking someone on the assumption that they downvoted you.
You are omniscient lately.

Retracted.

Agreed. I was littering code with schoolboy mistakes for a couple of years because of this. The complex stuff was great (heh) but some of the absolute basics were braindead because I thought I knew it. I'd been doing that stuff from day one and never had a problem... Until I did.
> I don't want to write bulletproof code, I want to teach them how and why to write bulletproof code.

This confuses me. How can you teach someone to do something if you won't do it yourself? Reading your statement literally, you are effectively going to say, "This is how and why to write bulletproof code, but I'm not going to." The whole point of LxTHW is to learn by doing. If you're doing it wrong, they're learning it wrong.

> I'm not qualified to meet that kind of lofty standard anyway.

Then you shouldn't write the book. Honestly. I know you intend to do some good and to be productive, but serving as a teacher and a reference point in an area that you're not qualified in is actually counterproductive.

I'm not saying don't write the book. Get qualified first.

Nobody's qualified to run a company when they do their first startup either.
That's a pretty dishonest analogy. Your first startup will succeed or fail based on its merits. If you write a book for beginners that is inaccurate, those inaccuracies will be spread in spite of their lack of merit.
If you're not qualified to meet that standard then don't write a C book (or learn more before you do). C programs are either bulletproof or they are a hazard.
On the bright side, forcing yourself to write bulletproof code for the book may well be the best way to become qualified.
If I understood him correctly he said that he didn't want to try to do that.
Sort of, I'm not going to try to write perfect code, but I will make myself a better programmer by doing this.

Further, the aim is to teach people how and why to write bulletproof code, not to demonstrate bulletproof CString tutorials.

The unwillingness to do for fear of violating some perfect model leads to never making progress at all.

No such thing as a perfect program, startup, relationship, or book.

I'm not saying you shouldn't write the book because it might not be perfect. I just disagree with your concept for the book. I think readers must see good code even if they don't understand immediately why it is good code. C programs that aren't really good tend to be really bad because they crash or worse.

Not being perfect is not the same as going in the wrong direction.

I disagree. If I'm learning a new language, I'm too busy worrying about the commas and semi-colons, not whether or not I'm using strcat or strncat. Worrying about overflows, signedness, etc. is something you do once you're more comfortable with the language.

It would be nice to provide links to articles and books on why one should use snprintf instead of sprintf or what is integer overflow and how do you deal with it and other topics for writing secure code.

However, as a beginner, it will simply not register since I'm more worried about having used a period instead of an arrow to access a struct member.

Perhaps, instead of writing a beginner C book, an advanced C book is needed more.

paging tom ptacek... tom ptacek to the white courtesy phone...
On the other hand, not all C code have to be secure. If I'm building a game for the Wii, don't bother me with stack overflows. The same goes for all the simulations out there (C is used about as much as Fortran in research). That's a lot of code.
Not going to bother demonstrating perfect tutorial code. All they'll learn from that is to write flawless tutorial code.

Might as well put Lance Armstrong on a bicycle in front of a 5 year old and expect them to learn how to ride a bicycle by watching Lance go in a circle.

Or as a compromise, start with simple, easy-to-read examples teaching basic principles. Give them datasets that will cause the program to blow up, and then explore both the causes and solutions to failure. Ideally, work back from the failures and encourage the reader to try out solutions that don't work so as to develop rigorous problem-solving skills.

I've always felt that teaching 'don't do that, cause it's bad' sticks rather poorly - unless something that obviously dangerous is involved, making your own mistakes is much more educational than memorizing a set of best practices and never even peeking into those blind alleys or pitfalls. You can do that and have good habits, but you'll have a dogmatic rather than a fundamental grasp of the knowledge, and this will constrict further development.

You've more or less described what I plan to do and why.
Presenting insecure source code in a beginner tutorial would actually be a great way of introducing an introductory software security book. Do the exploits on the into security book on the code examples from the beginner programming book.
One of the things that I admire most about W. Richard Stevens's books is that he checked the return value of everything, even printfs. Anal, sure, but that's what you're supposed to do in C and when you write demo code that doesn't, even if you surround it with warnings like "DO NOT DO THIS", beginners will still do it. Better to get the habits in right from the start.
(comment deleted)
What I really miss is some C book that teaches the modern approach to "object-oriented" C (as done in Gtk, Apache, CPython etc.). Actually many programmers (presumably with only passing knowledge of C programming) even actively proclaim that you cannot program in C in this style.
I'll teach function pointers, and might expose them to some style of OO C, but I haven't made any decisions on it.

My approach is going to be relatively unflavored by the Macro Hell of other projects. I'd rather not instill those habits. They can learn that on their own time.

I want the learner prepared to write clean sysprog code. That's it, the rest they can learn having been taught proper C and make their own stylistic decisions.

Why would you shy away from macros? Yes they are ugly, but they are an integral part of C and any system programming will rely quite heavily on macros, whether we like it or not.

If you're going to cover macros, please make sure to explain how they work and the multitude of pitfalls as well as how to deal with them; which is to wrap each macro in parenthesis.

There are as many potential problems with macros as there are grains of sand in Saudi Arabia.

Best not to go there beyond explaining how and why not to, and leave it at that.

Order of operations is an example of something that bites people with macros. (ref/deref + macro has nailed a lot of professionals I know)

Well, function pointers are only one aspect of this. Suprisingly many experienced C programmers I've met don't know that you can safely cast pointer to struct to pointer to it's first field, which is pretty important trick to achieve reasonable OO (with real inheritance) in C.
I know a line cook that codes C on his free time that would strangle someone who was paid to code that couldn't make a fake object + method calls out of a struct and function pointers.
And what comes almost directly from this is using (and writing) libraries and not programming everything yourself from scratch. NIH syndrome is particularly strong in many C programmers.
What about Learn C++ The Hard Way ? Anyone ?
we don't have 15 years sorry!
You can do that yourself, if you want. :p
Why not base it on a project? If you want more people to do systems programming (I am assuming kernel and driver development), why not take something from http://kernelnewbies.org/ and turn it into a simple project or write a character driver. People will learn how to write code for the Linux Kernel, learn how to interact with that community and perhaps become more interested in systems development as a result, if that is your goal.

In the context of writing a driver, you will have to cover concurrency, multi-threading, semaphores/mutexes, function pointers (callbacks), memory management, etc.

One personal side note, would be nice if you integrate TTD into the projects. The number of C developers that I deal with who do not understand the concept of a unit test is amazing.

Also, please cover C99 and talk a little about compilers, linkers and assemblers. You can concentrate only on one binary format (doesn't matter which one) as long as you explain a little bit about how your C code gets converted into machine format and what does that mean.

I would ask myself: "What makes my book on C different from all the other ones?"

Why should I spend my time on reading your book instead of any number of other tutorials or K&R?

EDIT:

Forgot to add, please provide a public repository for your code examples and start using something like Git right away. That's one thing I really enjoy from all the Rails books, they push you into using an RCS immediately.

>Why not base it on a project?

There might be a project. I'm modeling it after Zed's approach to some degree regardless.

>(I am assuming kernel and driver development)

Not particularly.

>turn it into a simple project or write a character driver

Nah.

>People will learn how to write code for the Linux Kernel

That is in fact, the opposite of what I'm trying to do.

I want to teach C, not Linux.

>would be nice if you integrate TTD into the projects

I'll demonstrate how/why, it won't be an integral part of it. TTD is use-case specific, not a universal benefit.

>The number of C developers that I deal with who do not understand the concept of a unit test is amazing.

That's a cultural problem, not a pedagogical one.

>Also, please cover C99 and talk a little about compilers, linkers and assemblers.

I'm going to aim for implementation agnostic insofar as it's possible while keeping them aware of the caveats.

What you're advocating is a significant departure from Zed's example. Not my goal.

>explain a little bit about how your C code gets converted into machine format

Implementation specific, outside scope.

>"What makes my book on C different from all the other ones?"

Out of scope of what I'm worrying about, it's a book, not a startup.

>Why should I spend my time on reading your book instead of any number of other tutorials or K&R?

Pretty sure you're not the crowd I'm aiming for, but I'll be happy if you can glean value from it.

Most C books are provincial or overly prosaic. I'm not interested in explaining, I'm interested in whipping people into coders. They can get their compiler and language implementation from a Comp Sci program.

No, I disagree with most of this. A LTHW book covers just enough of the language that someone could then go learn the things you mention from another book. At the end you could lightly cover testing, but most people can barely get an editor installed. No way they can learn multi-threading, TDD, an entire project, and an RCS.

It'd also dilute the focus of the book.

Worded better than I did, agreed.
I am not sure how applicable it is to an introductory text, but I would be interested in learning more about the internals of compilation and linking. What is the minimal necessary amount of work that needs to be done to interact with existing C libraries (header files, ELF format, and how that all fits together).
Rather avoid imp specific like ELF.

I'll encourage reusing existing code/libraries.

My plan was to make people use valgrind all the time after about lesson 10. Rather than you having to teach them all the various errors, you just let valgrind teach them by telling them their stuff must be valgrind pure.

Other than that, pretty much the same style as I did LPTHW.

Also, read:

http://sheddingbikes.com/posts/1288945508.html

There's more advice there.

I sent an email after reading that post, was inspired to do this because of it. I planned on having them use valgrind as well.
Teach how to implement a couple of data structures more complex than linked list and binary trees (maybe hash table).

Teach how to implement a couple of non-trivial algorithms (e.g., quicksort, topological sort).

The how isn't much use without the why.

Planned on it.

You want to target young programmers. Talk to those, and make them come with feedback as you write the book.
I have a split-test/feedback group prepared.
You probably want to make sure you know C, first.
About 10 years worth, I'm unqualified anyway.
10 years suggests nothing, really. If "int x; What type is &x", "int x[5]; What type is x? What type is &x?" manages to confuse you, I suggest you re-learn C, before authoring this book of yours.
I think it would be cool to see any of the following:

Learn Haskell the Hard Way

Learn Erlang the Hard Way

Learn Common Lisp the Hard Way

Learn R the Hard Way

Besides a "Learn X the Hard Way", I would actually like to see more people try to recreate the style of "The Little Scheme", which uses the socratic method to teach the learner. I think the socratic method requires the user to rack their brain a bit more, but results in much greater enjoyment and retention.

I would much prefer to see these two:

"The Little Haskeller"

"The Little Erlanger"

For example, it would be brilliant if someone can explain monads and list comprehension with the same eloquence as The Little Schemer explains currying and YCombinator.

There _is_ a Little MLer (with examples in Caml and Standard ML), which teaches type-based programming very well, and would be worth reading for anyone setting out to learn Haskell, I imagine (I respect Haskell's purity, but program in ML and Scala, the same way I respect Ada's safety, but program in C, so a better Haskeller than myself may disagree. :-)).

However, none of the Little ___er books are, of themselves, good ways to learn to use the language they are in; they're more like finger exercises when learning piano -- they reinforce your mental muscles to make thinking in the right way for those languages feel more natural.

I agree that "The Little ____er" books aren't the best to learn how to apply a language in the real world. I also agree with your "piano finger lesson" analogy.

However, where "The Little _____er" books excel and overcome all other teaching formats I've seen is in introducing complex paradigm-shifting concepts in a way that is digestable in tiny chunks.

Concepts such as monads, zippers and list comprehension are exactly the the type of concepts that are very difficult to teach/explain using common teaching approaches that "tell, but do not show"

The socratic method used in "The Little Schemer" makes sure to dismantle these extremely abstract concepts into atoms '(pun intended). You really need to understand each atomic piece before you move on.

In most explanations of monads the teacher rattles off a long run-on sentence that touches on several facets of a concept such as monads, making it all that much harder to digest. In fact, most sentences/paragraphs attempting to explaining monads just cause the learner to choke on the terseness and density of information being communicated in one utterance.

The way I see it, both types of books are very valuable. The Little Schemer teaches recursion as a concept better than any other text I've seen. I've never seen anything else that come close. In fact, most texts that touch on recursion quickly move into comparing it to iteration both in form and performance. SICP is an example of a teaching resource that does this. If I remember correctly, the first time you really see recursion in SICP is when the book discusses Ackermann's function and the pros and cons of recursion versus iteration.

Reading through Zed's tutorial reminded me of some Pascal and C tutorials I downloaded in the old BBS days. They were a great introduction to both languages when I was just learning to program.

I just had a look on simtel but I couldn't find them. Maybe you should put some effort into scanning old software archives and seeing if you can unearth them. C is pretty old - you wouldn't be the first one that had this idea.

I'll be referencing a lot of material, not all of them programming related. I'll try to dig up some old text files I liked as a kid per your recommendation.
I understood K&R years ago, but somehow I feel completely inadequate to being a C programmer. I think there is some kind of black art involved in memory management. I checked recently and it seems K&R doesn't even talk much about memory management.

I just wish to learn the current state of the art - what are best practices that have evolved since K&R?

That feeling of inadequacy and incompleteness post-K&R is something I experienced too and is something I'm hoping to address.
There's a chapter on memory management* in Hanson's _C Interfaces and Implementations_ (http://sites.google.com/site/cinterfacesimplementations/), which is one of the better advanced C books I've read.

* Mostly, arena-based allocators.

Paul Wilson's "Uniprocessor Garbage Collection Techniques" (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.47.2...) is an excellent overview, as is Jones and Lins's _Garbage Collection: Algorithms for Automatic Dynamic Memory Management_.

Interested parties can also look into "Memory as a Programming Concept in C and C++".
Illustrate the differences between IDB and UB early on.
Beg your pardon?
If you don't know what UB or IDB is, you probably don't want to write a book pertaining to C, :)
Context specific.

Could be intel debugger, could be undefined behavior, could be implementation defined behavior. I tested them on a group of about 15 C devs, mixture of embedded, linux, DSP, and other volken.

Got the same guesses I made and a lot of question marks.

It's easy to run your mouth but not actually contribute, you might consider your role in this process before commenting again.

(comment deleted)
I don't think C defines an intel debugger.
So, contextually, we're referring to C here, wherein these terms refer to Implementation Defined Behaviour, and Undefined Behaviour. Allowing beginners to understand such terms early on would help, immensely.
Sure, if they have a copy of the standard sitting on their desk.
I can see that this book is going to be a great success, already. :)
Just because you're working in C doesn't mean you need to handle every detail yourself. In fact, please don't handle every detail yourself. Show your readers how to use some of the great libraries C has to offer. Not just system-level abstraction layers, either.

You need to go get libraries for a lot of the stuff you'd normally use the standard library for in a more modern language. These libraries exist, and many of them are excellent, but because they're not built-in, people are less likely to use them. This is especially dangerous in C, because it requires so much work to do anything even vaguely complex.

edit: That came off as saying "Teach some libraries". What I really mean is "Teach people to go find libraries."

I really like the __attribute__ mechanism that GCC has, something covering that will be really nice.
Not likely to happen, outside scope.