
Where to begin when learning C? Start by making lots of errors - morganwilde
http://morganwilde.svbtle.com/where-to-begin
======
tptacek
This situation is why there is "hello world"; that program seems trivial but
actually has important implications; for instance, that your environment
works, that you know how to feed programs to the compiler, that you can
actually run the output.

I never took "hello world" seriously until I started doing embedded systems
work; it's now an extraordinarily important tool for me (I work an anomalously
weird number of different environments).

~~~
mrmekon
I once had a particularly slow week at work, and decided to write an article
about how "Hello World" works in C. How it _really_ works -- including
compiling, linking, system calls, operating system involvement, hardware I/O,
communication between ICs, etc. The path from the block of text to photons
emitting from the screen, with fairly detailed explanations at every level.

I ended up with a 50 page LaTeX document that barely even scratched the
surface, and then work picked up and I never finished it. A "full" explanation
would probably be a 600+ page book.

I still think it would be a neat resource to have. We kind of take for granted
that the simple "Hello World" is built on 60 years of research, and is
anything but simple.

~~~
oftenwrong
I have been looking for a guide like that. I would also appreciate a release
of the unfinished version.

~~~
sanoli
This book and its companion (free) online course are great:
[http://mitpress.mit.edu/books/elements-computing-
systems](http://mitpress.mit.edu/books/elements-computing-systems)
[http://www.nand2tetris.org](http://www.nand2tetris.org)

~~~
pjmlp
Very good indeed. The Google Tech-Talk presentation is worth watching.

------
kabdib
I learned C by reading K and R and doing the book's exercises . . . on paper.
At the time I didn't have access to a C compiler, so I wrote them all out in a
notebook. A month later I got a job at a shop that was running Unix, and got
the chance to type my programs in and try them.

I had a lot of things wrong. It took me a while to understand the difference
between control-D and EOF, for instance (how embarrassing). But the 30 days I
spent without a compiler made me _think_ about program behavior.

I'm not saying this is a great way to learn a language, but it can be done.

I keep hearing people complain about K and R being "a terrible book." For me
it was perfect: pragmatic, succinct, with great examples and good exercises.

~~~
gits1225
"Programming is learned by writing programs"

\- Brain Kernighan

And that is what anyone who goes through K&R will do: Reading and writing lots
of _real_ programs. A simple program is worth a thousand words!

Which unfortunately the majority of technical books just can't get right.
Explain the concepts in 5 full dull pages, and then at the end "Hey, checkout
this little snippet of code, which by the way does nothing really interesting,
but is here to illustrate what the author was talking about :)"

~~~
clarry
I'd like to add some emphasis on _reading_. For a beginner, writing is
obviously very very important as the way to get to the point where he can just
sit down and solve a given task.

But reading lots and _lots_ of code (from many different sources) will help
him pick up idioms and find common & good solutions to specific problems. Even
for a smart person, I think it'll take a lot of time and effort to arrive to
the cleanest way of doing things.

Of course there's a risk of picking up bad habits, but if you read lots of
code, you should eventually develop a feel for what's clean and readable and
easy to understand, and what's messy and wrong. This sadly doesn't help with
issues like undefined behavior, but you don't learn these just by writing
either. For that you need to look into the spec or some other text that'll
cover these.

EDIT: I like to think that I'm a fairly good C programmer (having coded nearly
all my life, with C mostly), but I still peek into others code all the time to
find out how they've solved some things I'm about to do.

~~~
HCIdivision17
I'll second this notion. I no longer write C, but it is what I learned in high
school. My teacher had an interesting class requirement: we needed to review
one C/C++ Users Journal article. Length, difficulty, or topic didn't matter -
just read a trade article and write about it. We also had to code a lot, and
we had to write code by hand on paper tests, and we had some fun competing,
but the journals let me know what the Real World was doing.

It takes a large volume of work to really get into programming, and I think
that reading is easier than writing, so it's a fast way to dig in (keeping in
mind that feedback is critical - so reading without writing has severe
diminishing returns)!

------
pjmlp
By making sure to _enable all warnings_ , _enable warnings as errors_ and use
a compiler that integrates static analysis like clang.

~~~
morganwilde
I am using the default `cc` compiler on Mac OS X for this without any flags,
are you saying I should something non-stock in this case?

~~~
enqk
Try passing at least the -Wall and -Wextra flags.

For learning, you could also add -ansi, as it will make your compiler be
stricter about standards.

~~~
e12e
And probably -Werror (all warnings become errors, breaking compilation).

Fun post. Now I know why everyone was raving about the clang error-messages:

    
    
        echo "void main() {}" > main.c
    
    
        gcc -Wall -Werror --std=c99 main.c 
        main.c:1:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
        cc1: all warnings being treated as errors
    
    
        clang -Wall -Werror --std=c99 main.c 
        main.c:1:1: error: 'main' must return 'int'
        void main() {}
        ^
        1 error generated.
    
        (not showing clangs pretty colours)

~~~
morganwilde
Nice suggestion. Although I can't seem where one would have to look for those
"pretty colours" you mentioned, I certainly can't see any of them on my Mac
terminal...

~~~
e12e
Can't help you there -- but I don't think I've set any exotic terminal
variables or anything like that, and I get this:

[http://i.imgur.com/BjWj7h6.png](http://i.imgur.com/BjWj7h6.png)

FWIW, I have:

    
    
        COLORTERM=gnome-terminal
        TERM=screen
    

and Debian takes care of my termcap etc, afaik.

~~~
mitchty
Think its his TERM env most likely being straight xterm (no color ansi escapes
in the termcap iirc).

[http://i.imgur.com/0Hzze9G.png](http://i.imgur.com/0Hzze9G.png)

Thats me on osx running tmux with TERM=xterm-256color.

------
foster1890
Where to begin when learning C? Start at
[http://c.learncodethehardway.org/](http://c.learncodethehardway.org/). It's
going to be tough to top Zed Shaw's approach. The best way to learn code is by
writing code.

~~~
NAFV_P
Zed hasn't finished it yet. I'm dying to see this virtual machine of his.

------
yetanotherphd
I think I have some ingrained fear of making errors, from the days where a
simple error might cause your program to chew through your whole hard drive.
Actually I don't know if that was ever the case, but that's how I felt.

Anyway, the hardest step for me in learning a language is when I take some
running code and make one change to see what happens. Once I get in the swing
of it, it gets much easier, but that first step is still hard to do.

------
vparikh
In order to for people to really understand C and be proficient in it very
clearly, I always recommend that they learn the basics of programming (memory,
basic types, looping structures and array manipulation) in a simple assembly
language such as 6502. This helps immensely with understanding pointers and
deciphering the many cryptic C compiler messages.

------
b0rsuk
Install Valgrind. It makes error messages a lot less cryptic (my #1 problem
with C... not that's it's limited to C). If you don't get proper feedback,
it's not learning, just banging your head against the wall.

~~~
adregan
I've had a heck of a time getting Valgrind working on a mac (especially since
Mavericks), hardly finding any resources about it. Is there an alternative, or
do you have any advice on getting it to work?

~~~
mtdewcmu
XCode comes with profiling tools. It's not easy to stray outside of Apple's
own development tools.

------
idoescompooters
Currently, I'm learning Python and have been learning it for over a year now.
I've been thinking about moving to C as my next language. Is this a good idea?
I'm eventually going to want to learn C++, but I'm not going to learn Java
until I have to. Also, what are some really good C learning resources? I know
there's K&R and learncthehardway.org

------
eonil
I thinks this is a good approach. Checking most of possible exceptional cases
while following regular learning course.

Errors = safety nets are usually the main reason to make stiff learning curve.
This would be a great help for them.

------
agumonkey
As other people said earlier, reading existing code is great, when you have
good sources. I'm an almost noob in C, and currently reading Ian Piumarta
sources[1], I find they're superb in presentation and design.

[http://piumarta.com/software/](http://piumarta.com/software/)

[1] mostly for maru, his lisp system, but even tty2html (ascii control ->
html) is very clean and elegant.

------
mtdewcmu
A minor point, but important to understand: the error came from the linker,
not the compiler. It compiled just fine.

~~~
joshguthrie
Regarding that: >an empty file is not a valid C program, and the compiler will
not hesitate to tell that to you with a big, fat error message.

Didn't someone win a IOCCC some years ago by providing an empty file that got
compiled successfully?

~~~
mtdewcmu
Well, compiling an empty file is a piece of cake. An empty file is valid C,
just not a complete program.

------
morganwilde
By the way, I would love any feedback on this approach and where I should take
this further.

~~~
e12e
As for going further staying with the bare-bones approach, I suppose you'd
have to start looking at assembly output and how that fits with what the
c-code does. I don't know anything about OSX x86_64 calling conventions etc --
but at least under Linux (and afaik windows) 64bits is a lot more friendly and
fun than the mess that was 32bit (and 16bit) x86.

There are a couple of great (free) resources on 32bit x86 assembly I'm aware
of:

[http://www.drpaulcarter.com/pcasm/](http://www.drpaulcarter.com/pcasm/)
[http://www.plantation-
productions.com/Webster/HighLevelAsm/i...](http://www.plantation-
productions.com/Webster/HighLevelAsm/index.html)

There's apparently some plans on upgrading HLA to x86_64 -- I don't know of
any good tutorials or guides on working on 64bit assembly specifically I'm
afraid.

Just adding "-S" and looking at the source can be helpful of course, although
I much prefer nasm/intel syntax, for clang/gcc that should require:

    
    
       clang -S -mllvm --x86-asm-syntax=intel main.c
       gcc -S -masm=intel main.c
    

Note that gas syntax is the "default" in the gnu-world, so it might be easier
to just go with that if you're just starting out.

It looks like clang might be generating less "noise" for tiny trivial
programs, here's a side by-side-diff (in intel syntax) of int main{} vs int
main { return 0;} (slightly reformatted):

    
    
        diff --side-by-side main.s main.no-ret 
          .file   "main.c"                          .file   "main.c"
          .text                                     .text
          .globl  main                              .globl  main
          .align  16, 0x90                          .align  16, 0x90
          .type   main,@function                    .type   main,@function
        main:                       # @main       main:          # @main
          .cfi_startproc                            .cfi_startproc
        # BB#0:                     # %entry      # BB#0:        # %entry
          mov     EAX, 0                             mov     EAX, 0
          mov     DWORD PTR [RSP - 4], 0         <
          ret                                        ret
        .Ltmp0:                                   .Ltmp0:
          .size   main, .Ltmp0-main                 .size   main, .Ltmp0-main
          .cfi_endproc                              .cfi_endproc
    
          .section ".note.GNU-stack","",@progbits   .section ".note.GNU-stack","",@progbits
    

It can be fun to do this with stuff like hello world (and contrast
puts("Hello, world!"); with printf("Hello world!\n);).

~~~
pjmlp
Intel x86 assemblers family are so much nice that whatever any UNIX system
has.

------
laveur
This all of this!

------
lhgaghl
This is stupid. You should learn C properly (know how to avoid undefined
behavior) or not at all. Exception if you're doing something that can tolerate
remote code execution.

------
passfree
You should learn go instead of C.

~~~
morganwilde
A valid point longterm, but for different reasons that I have for discussing
C.

------
mbq
Actually the message quoted complains about the lack of _main not main, so the
rest of this post is a huge overinterpretation. _main is IMO some windoizm
connected to the use of WinMain for GUI apps.

~~~
deletes
-1, Learn don't guess.

[http://stackoverflow.com/questions/2627511/why-do-c-
compiler...](http://stackoverflow.com/questions/2627511/why-do-c-compilers-
prepend-underscores-to-external-names)

~~~
mbq
Yeah, got me making the same error as I was complaining about. Thanks for the
link though.

