Hacker News new | comments | ask | show | jobs | submit login
Essential C (2003) [pdf] (stanford.edu)
228 points by kercker on May 11, 2016 | hide | past | web | favorite | 89 comments

I've gone through a lot of exercises[0][1] from this site especially on how to implement a linked list in C. The time spent from the tutorial was absolutely worth while. I feel happy and satisfied with my self after solving one problem at a time.

For those who already know the syntax of C but wanted to learn more, the links I mentioned is a good exercise and opens up a lot of possibilities on what you can implement. You'll soon be able to realize the importance of linked list and why you'll want to use a linked list instead of just plain arrays.

[0] - http://cslibrary.stanford.edu/103/LinkedListBasics.pdf

[1] - http://cslibrary.stanford.edu/105/LinkedListProblems.pdf

My favourite language is Lisp, in which I use "linked" lists all the time, but I never use them in C. Use of lists without a garbage collector and either dynamic typing (as in Lisp) or strong static typing (as in Haskell) is a pain, and C has none of these built in. This means that, in C, you need to allocate memory every time you add something to your list, and hold the pointer to it in order to free it later. You also need to keep track of which types are stored, and where.

If your problem requires a lot of list processing, use a language more suitable for it. Otherwise, use extensible arrays, which are easy to implement in C.

conceit also pointed out that lists also increase the likelihood of cache misses, which slows down the program a little bit. Many C programmers care about that. I don't share their priorities - it is important to me, but less so than correctness, ease of programming (allowing more time for exploration and finding a more efficient algorithm), and response times.

Meh, sometimes there are easier ways than GC.

Just allocate all the list items from a big pool of memory that you own. When you're done, throw the whole lot away in one go. Languages like C++ tend to encourage micromanagement of data but it's not the only way to do things.

To the contrary, linked lists are cache killers and hardly used nowadays. Or so they say on here, if I understand correctly.

Some operations are faster on linked list than on vectors (insert on beginning, or on specified iterator position, delete iterator position). They also use less memory in some use cases. I was once optimizing transactional tree structure which internally used std::vector in each node. In most real use cases there was just one item in each vector, but vector preallocated 16 items. So changing to linked list lowered memory consumption significantly without measurable performance impact. The same applied for hash table vs. RB tree. All basic data structures can be useful, you just have to choose proper one.

Sweeping statements like this are almost always unilaterally false.

The best data structure or algorithm to use is usually problem-dependent.

Do you mean mine or the OP's, which evoked my response?

> ... why you'll want to use a linked list instead of just plain arrays

Linked lists are the default "goto" data structures for Haskell and many other functional languages, such as Lisp.

Storing strings as a linked list of characters in Haskell was a design mistakes imho, which lead to the proliferation of various efficient string types implemented in libraries.

IMHO, linked lists can be useful in conjunction with other data structures without hurting performance too much. An open hash table with a linked list in each bucket need only involve pointer chasing in case of collisions, which can be made arbitrarily rare by making the number of buckets large enough. In this way, there's a graceful performance degradation under unexpectedly heavy loads rather than hard limitations. I would be interested to read well informed contrasting opinions.

> hardly used nowadays


That's unbearable. They should just redo this in JavaScript. That's what everyone uses nowadays. Or so they say on here, if I understand correctly.

I tried to appreciate your response, but I cannot fairly judge the code. For example, those could be performance uncritical parts of code or remnants of 20 year old code where the cache was less effective than now. Are 2000 search results a lot in a source of this size?

Cache, as opposed to 20+ years ago, or whenever the pattern was developed, is indeed a thing that everyone is using just now.

How on earth can you make such a statement about a fundamental data structure? Please, take CS101 before you you start throwing these kind of assertions around.

Don't use this. It's really rusty and teaches bad habits superseded by C99.

Here's a proper reference on C99 and C11:


And see also reallocarray.

Out of interest can you be more specific about the bad habits it teaches?

And is there a similar resource for current C standards?

For many of these examples, there's a debugger called "ddd" that can graph structures and can be useful.

I want to love ddd, really I do, conceptually it is awesome and beautiful. In practice it is (IME) buggy (almost) to the point of uselessness. It's been a couple of years since I last used it, but it was last updated around 2009 :-(

I'm in the same boat. I've tried it out a few times and it's always a crashy mess. I want to like it, but the project seems to have been abandoned in a barely usable state.

ddd isn't my day-to-day debugger but I sometimes break it out when I need to visualize a data structure or keep track of multiple values when doing some more difficult debugging tasks.

It's far from perfect but still a useful tool.

Oh for sure, I've used it a fair bit, it can be an absolute lifesaver for RE work or building simple VMs, for instance where you need to grok a structure in its fullness.

This is an enjoyable comment section (rare to say). The arguments about the pronunciation of the char keyword is all part of being C programmers. This is great. :-)

This and "C traps and pitfalls" [1] were my favorites back to the days.

[1] http://www.literateprogramming.com/ctraps.pdf

Nice to see strlcpy in there. How do we get it into glibc?

strlcpy returns offset of dst + len of src which requires strlen(src) which isn't optional and sort of sucks imo. Something very similar but that doesn't do strlen(src) such as https://godbolt.org/g/Etpuhz would be better.

Well one could argue that in C a string is not a string unless it's NUL terminated...

It's a choice they made to make it easy to detect truncation. If you don't care about the return value of strlcpy you can modify it to skip that part (which IMO will make it worse) but get rid of traversing src until \0 is found.

If you know you're working with non-terminated "strings" then just use memcpy instead.

If you're using proper functions you shouldn't end up with a non NUL-terminated string in the first place, although there are shortcomings in the commonly used libraries here unfortunately yes. It's hard to create a function that solves all problems.

(Side note: IMO The return value of latest OpenBSD version of strlcat (cat not cpy) is a bit weird when size is smaller than strlen(dst))

My issue isn't that src is or isn't NUL terminated (strings in c absolutely must be NUL terminated) its that strlcpy requires a call to strlen (probably inlineable with lto) which is going to be a lot slower than not. Also there is a bug in my 'strmcpy' in the last for loop it should be n && *s

Even nicer to see that it warns users away from strncpy.

The "C Programming Cleverness and Ego Issues" is a good bit of advice:

> Build programs that do something cool rather than programs which flex the language's syntax. Syntax -- who cares?

Otherwise, I'd never heard of/seen the `#pragma once` preprocessor directive. (Not that I do that much C programming!) How common is it to use this over include guards?

> How common is it to use this over include guards?

Not very. It works in Microsoft's C compiler but can't be relied on elsewhere.

It depends. Clang, GCC and the Intel C++ compiler all support #pragma once perfectly. Personally, I prefer it, as it is only one line rather than three and I don’t have to think of a unique name for the header guard. Supposedly it breaks if you play weird tricks with the filesystem (s.t. the compiler thinks two identical files are actually different), but I have never encountered such breakage.

Then why mention it over include guards, which are not discussed. Is Stanford a Microsoft shop, so to speak?

They might have used MSVC for their exercises on this course. They're not using some C99 features such as stdint.h, which were not available in MSVC when this article was written.

'char ASCII character -- at least 8 bits. Pronounced "car".'

Pronounced 'car'? Bollocks. Pronounced char as in charred.

I've always pronounced it as 'care', not because of how the identifier is spelled but because it's the first syllable of the word 'character'.

I don't think there's a consensus between car/char/care, though, even among C's creators. But if there was, I would vote for 'care'.

I always thought SQL was another weird one. When discussing the language itself, you can say 'sequel' or 'ess queue ell' interchangeably, but when referring to a database that has "SQL" in its name, there is a DB-specific one true pronunciation:

* SQL Server: 'sequel server'

* PostgreSQL: 'post gress queue ell'

* SQLite: 'sequel light'

* MySQL: 'my ess queue ell'

There's no complete consensus on any of those- just a preponderance of one, or an officially endorsed pronunciation in a FAQ someplace.

I've also heard 'my squeal' for MySQL, breaking out of the 'sequel'/'ess queue ell' duopoly altogether.

In my youth, I pronounced SQL as "squall". Quickly changed to "ess queue ell" when starting out professionally...

> because it's the first syllable of the word 'character'.

Except the first syllable of 'character' is neither 'car' nor 'care', unless you have a really weird accent or are intentionally making fun of the English upper class.

PS: I always liked "squirrel" for SQL but sadly that one never got much traction.

What's going here is that most Americans have what's known as the marry-merry-Mary merger[1]. Virtually all English speakers outside of North America, as well as some Americans, mostly on the East Coast, pronounce the vowels in these three words differently -- marry is pronounced /mæri/ (/æ/ is the vowel in "cat"), merry is /mɛri/ (/ɛ/ is the vowel in "pet"), and Mary is /meri/ (/e/ is the vowel in "bait"). In those dialects, any vowel can proceed an /r/ that's intervocalic (i.e., both preceded and followed by another vowel), so /r/ acts like any other consonant in that sense.

However, in most American dialects, marry-merry-Mary are all merged and pronounced identically (IPA: /mɛɹi/, though the exact vowel isn't important here, and all three vowels generally sound the same to merged speakers). Furthermore, the first syllable of all these words is usually pronounced the same as the vowel in mare (/mɛɹ/).

So let's put this together. The word "care" is pronounced /kɛr/ in both merged and unmerged dialects (or /kɛː/ if you don't pronounce the /r/ there). In unmerged dialects, the word "character" is pronounced /kærəktər/, so it doesn't make sense that you'd truncate it to /kær/, because /ær/ (or /æː/) at the end of a syllable doesn't occur in any English dialect[2]. In merged dialects, however, "character" is pronounced /kɛrəktər/, so it makes sense to truncate it to /kɛr/, which is a homophone of "care".

[1]: https://en.wikipedia.org/wiki/English-language_vowel_changes...

[2]: Except Irish English, see https://news.ycombinator.com/item?id=11673067.

[3]: I speak a merged dialect, and pronounce "char" as /kɛr/ when I'm reading C code.

Your post looks interesting and might well be 100% correct but I don't know - nor do I know anyone who knows - what the various little pronunciation guides or whatever they're called mean. It's why people tend to say "car as in carpet".

It's IPA. It's the closest thing we have to an actual way to write down how people pronounce things which has any chance at all of being useful.

This "'foo' as in 'bar'" stuff is worse than useless most of the time, as you've just been shown.

No, "car as in character" is still. Car as in carpet, char as in chart - simple and doesn't require a course in IPA, which may I remind you precisely nobody understands.

> a course in IPA, which may I remind you precisely nobody understands.

Plenty of people understand IPA.

> No, "car as in character" is still.

It's still completely incomprehensible unless you know which vowel sound is meant, which is the whole point of this sub-thread.

I don't know what happened to my post but i meant "car as in character is stupid/ambiguous". But it's perfectly possible to understand "car as in carpet" and it's generally possible to find a similar pronunciation of a sound.

"Plenty of people" is misleading. Plenty as in thousands, millions of people worldwide, possibly, not not plenty as a percentage of the english people world. I'd be surprised if more than 5% of english speakers look at an IPA description of a sound and do anything other than go "what the fuck does that mean?".

That was a surprisingly detailed and well-informed reply. I wish there was some kind of super-upvote for comments like this.

Alright, I'll bite. How is 'care' not phonetically the first syllable of 'character'? And if it's not, then what is?

'Care' rhymes with 'bear', 'share', 'fair'; 'car' rhymes with 'bar', 'far', 'mar'. 'Character', to me, is pronounced 'car-ack-ter' with the emphasis on the first syllable. It doesn't sound anything like 'care'.

Conversations like this are hard because accent doesn't transmit through text. I'm Irish.

Ohhhh, that's where the discrepancy is coming from. I didn't know it was pronounced 'car-ack-ter' with an Irish accent. I was thinking in terms of an American accent which is where the confusion came from.

The "listen" button here pronounces the words with an American accent:


> The "listen" button here pronounces the words with an American accent

I think that feature must be localised -- here it gives me a (female) voice with an English accent, and the two words sound quite different.

Oops, I was afraid of that. I was hoping the .com domain would have an influence on which voices were picked. I can hear the difference by going to https://translate.google.co.uk/ though

Forvo is a great site for this kind of stuff http://forvo.com/search/char/en/

> Conversations like this are hard because accent doesn't transmit through text.

It does if you use IPA.

To my Irish ears, 'car' and 'char' in 'character' sound almost identical. (I pronounce it 'car'.)

The only way I could pronounce it 'care' is if I were from the southern hemisphere.

Surely if there was consensus, you wouldn't get to vote.

Me good no words. :) At least not right now apparently...

PostgreSQL: "postgres"

Kernighan pronounces it care as in how you say character.


Thank you for that link.

I remember reading the "care as in character" thing years ago and just boggling at it -- who on earth makes character start with care? (As a British person, I think the first syllable of character rhymes with cat. There isn't a word that sounds like that but ending in r.) So rather than settle the question for me, it just dug the hole deeper.

Listening to Kernighan, I can just about hear what that remark meant.

(I say char myself, like the fish)

Makes sense, as it's clearly an abbreviation for "character."

"Like the first word of "char *". The accent is generally on the first syllable."

C Infrequently Asked Questions #19.26, https://www.seebs.net/faqs/c-iaq.html

Bollocks, pronounced char as in "char". I did not know this was even in dispute. Not that i care how anyone else pronounces it, i just thought it was blindingly obvious since we already have an English word spelled exactly the same as what we use in code to declare the thing.

Quite. Char as in 'nice cup of'.[0] Possibly delivered by a char lady. (Note, not a char woman, which is one's housekeeper).

[0] https://m.youtube.com/watch?v=eELH0ivexKA

Well yes, but saying pronounced char as in char doesn't really get the pronunciation across unambiguously, especially when half the world seems to pronounce it something else and Irishmen have their own spin ;)

Yup. It's [chahr] as in "I charred the steak.", not [kahr] because it doesn't have a horn and 4 wheels.

I used to say "car", but it's definitely inferior to "char", since you can refer to char * as "char star" which is a lot of fun to say.

Make a variable that stores an ASCII character. Make it happy. Use it wrongly.

char grinned;

I always have fun with char , I have a very specific cadence and melody I say it with (internally and externally). It's just such a fun phrase

How about varchar in sql land? Is that var-charr, or var-car ?

  char *var = "varchar";

That's gotta be var-car. I guess to get a definitive answer, you need to poll database authors who deal with both :)

And how do you pronounce "varchar"?

I've always pronounced "char" as "car". Dunno why, I learned C from a book, so no one got to tell me I was wrong.

Variable Character = Vare-care

Not that I say it that way, I've always heard and said var-char

Well, it's wrong; varchar is pronounced [var-chahr].

I too pronounce it that way, since I learned C from books and just read it as it was printed.

I later noticed some people do pronounce it "car" which just seems odd. Why change it, if it doesn't save a syllable? It's not a truncation of how "character" is said either, because that's a different vowel sound.

Saying 'car' causes problems when learning C++, because all OOP examples on composition start "Car has-an Engine".

Pronounced char as in care

Nope; it's not [care] and it's not [kahr], it's [chahr].

It's as noob as when someone pronounces nginx [njinkx] instead of [engin-x], or linux as [li-nux] instead of [lin-ux].

You calling Brian Kernighan a noob?

I actually pronounce Linux as [lin-ix].


> char: /keir/, /char/, /kar/, n.

as in "carred" you mean? :P

Argument over GHif vs Jif in 3, 2, 1...

Pronounced care as in the first syllable of character.

The first syllable of character sounds nothing like "care"...

Had I written it in IPA, people would be complaining about that, too...

It's /kɛər/, as you can see here: https://en.wikipedia.org/wiki/Help:IPA_for_English

And, for the record, I have the Mary-marry-merry merger: https://en.wikipedia.org/wiki/English-language_vowel_changes...

It does to a lot of Americans.

Why? It's from "character", you do not want it charred.

This predates the stdint.h header, which gives you int32_t and so on.

Sort of. The copyright is 1996-2003. <stdint.h> was introduced in the 1999 ISO C standard.

But as of 2003, support for C99 wasn't very widespread, so omitting <stdint.h> was understandable.

Yeah, that was my first thought after a cursory reading, y u no <stdint.h>? There seems to be a lot of great content regardless.

I'd love to see an updated version.

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact