2. Programming Building Blocks


"Where do these stairs go?"
"They go up."
--Ray Stantz and Peter Venkman, Ghostbusters

What is programming, anyway? I mean, you're learning how to do it, but what is it? Well, it's, umm, kind of like, well, say you have this multilayered chocolate and vanilla cake sitting on top of an internal combustion engine and the gearbox is connected to the coil with a banana. Now, if you're eating the cake a la mode, that means... Wait. Scratch that analogy. I'll start again.

What is programming, anyway? It's telling the computer how to perform a task. So you need two things (besides your own self and a computer) to get going. One thing you need is the task the computer is to perform. This is easy to get as a student because the teacher will hand you a sheet of paper with an assignment on it that describes exactly what the computer is to do for you to get a good grade.

If you don't want a good grade, the computer can do that without your intervention. But I digress.

The second thing you need to get started is the knowledge of how to tell the computer to do these things. It turns out there are lots of ways to get the computer to do a particular task...just like there are lots of ways to ask someone to please obtain for me my fluffy foot covering devices in order to prevent chilliness. Many of these ways are right, and a few of them are best.

What you can do as a programmer, though, is get through the assignments doing something that works, and then look back at it and see how you could have made it better or faster or more concise. This is one thing that seriously differentiates programmers from excellent programmers.

Eventually what you'll find is that the stuff you wrote back in college (e.g. The Internet Pizza Server, or, say, my entire Masters project) is a horridly embarrassing steaming pile of code that was quite possibly the worst thing you've ever written.

The only way to go is up.

2.1. The Specification

In the beginning was the plan
And then came the assumptions
And the assumptions were without form
And the plan was completely without substance
And the darkness was upon the face of workers
--Excerpt from The Plan, early Internet folklore

Ooooo! Prostrate yourself, mortal, in the face of The Specification!

Ok, maybe I'm being a little too overdramatic here. But I wanted to stress just mildly and subtly, if you might indulge me, that The Specification BWHAHAHA *THUNDERCLAP* (Sorry! Sorry!) is something you should spend time absorbing before your fingers touch the keyboard. Except for checking your mail and reading Slashdot, obviously. That goes without saying.

So what do you do with this specification? It's a description of what the program is going to do, right? But where to begin? What you need to do is this: break down the design into handy bite-sized pieces that you can implement using techniques you know work in those situations.

As you learn C, those bite-sized pieces will correspond to function calls or statements that you will have learned. As you learn to program in general, those bite-sized pieces will start corresponding to larger algorithms that you know (or can easily look up.)

Right now, you might not know any of the pieces that you have at your disposal. That's ok. The fastest way to learn them is to, right now, press the mouse to your forehead and say the password, "K&R2".

That didn't work? Hmmm. There must be a problem with the system somewhere. Ok, we'll do it the old-school way: learning stuff by hand.

Let's have an example:

Assignment: Implement a program that will calculate the sum of all numbers between 1 and the number the user enters. The program shall output the result.

Ok, well, that summary is pretty high level and doesn't lend itself to bite-sized pieces, so it's up to us to split it up.

There are several places that are good to break up pieces to be more bite-sized. Input is one thing to break out, output is another. If you need to input something, or output something, each of those is a handy bite-sized piece. If you need to calculate something, that can be another bite-sized piece (though the more difficult calculations can be made up of many pieces themselves!)

So, moving forward through a sample run of the program:

  1. We need the program to read a number from the keyboard.
  2. We need the program to compute a result using that number.
  3. We need the program to output the result.

This is good! We've identified the parts of the assignment that need to be worked on.

"Wait! Stop!" I hear you. You're wondering how we knew it was broken down into enough bite-sized pieces, and, in fact, how we even know those are bite-sized pieces, anyhow! For all you know, reading a number from the keyboard could be a hugely involved task!

The short of it is, well, you caught me trying to pull a fast one on you. I know these are bite-sized because in my head I can correspond them to simple C function calls or statements. Outputting the result, for instance, is one line of code (very bite-sized). But that's me and we're talking about you. In your case, I have a little bit of a chicken-and-egg problem: you need to know what the bite-sized pieces of the program are so you can use the right functions and statements, and you need to know what the functions and statements are in order to know how to split the project up into bite-sized pieces! Hell's bells!

So we're compromising a bit. I agree to tell you what the statements and functions are if you agree to keep this stuff about bite-sized pieces in the back of your head while we progress. Ok?

...I said, "Ok?" And you answer... "Ok, I promise to keep this bite-sized pieces stuff in mind." Excellent!

2.2. The Implementation

Right! Let's take that example from the previous section and see how we're going to actually implement it. Remember that once you have the specification (or assignment, or whatever you're going to call it) broken up into handy bite-sized pieces, then you can start writing the instuctions to make that happen. Some bite-sized pieces might only have one statement; others might be pages of code.

Now here we're going to cheat a little bit again, and I'm going to tell you what you'll need to call to implement our sample program. I know this because I've done it all before and looked it all up. You, too, will soon know it for the same reasons. It just takes time and a lot of reading what's in the reference section of your C books.

So, let's take our steps, except this time, we'll write them with a little more information. Just bear with me through the syntax here and try to make the correlation between this and the bite-sized pieces mentioned earlier. All the weird parentheses and squirrely braces will make sense in later sections of the guide. Right now what's important is the steps and the translation of those steps to computer code.

The steps, partially translated:

  1. Read the number from the keyboard using scanf().
  2. Compute the sum of the numbers between one and the entered number using a for-loop and the addition operator.
  3. Print the result using printf().

Normally, this partial translation would just take place in your head. You need to output to the console? You know that the printf() function is one way to do it.

And as the partial translation takes place in your head, what better time than that to actually code it up using your favorite editor:

#include <stdio.h>

int main(void)
{
    int num, result = 0;

    scanf("%d", &num); // read the number from the keyboard

    for(i = 1; i <= num; i++) { // compute the result
        result += i;
    }

    printf("%d\n", result); // output the result

    return 0;
}

Remember how I said there were multiple ways to do things? Well, I didn't have to use scanf(), I didn't have to use a for-loop, and I didn't have to use printf(). But they were the best for this example. :-)

2.3. So Much To Do, So Little Time

Another name for this section might have been, "Why can't I write a Photoshop clone in half an hour?"

Lots of people when they first start programming become disheartened because they've just spent all this effort to learn this whole programming business and what do they have to show for it: a little text-based program that prints a string that looks like it's some prehistoric throwback to 1979.

Well, I wish I could sugarcoat this a little bit more, but that is unfortunately the way it tends to go when you're starting out. Your first assignment is unlikely to be DOOM III, and is more likely to be something similar to:

Hello, I am the computer and I know that 2+2 =   4!

You elite coder, you.

Remember, though, how I said that eventually you'll learn to recognize larger and larger bite-sized pieces? What you'll eventually built up is a set of libraries (collections of reusable code) that you can use as building blocks for other programs.

For example, when I want to draw a bitmap on the screen, do I write a system to read the bytes of the file, decode the JPEG image format, detect video hardware, determine video memory layout, and copy the results onto the display? Well do I, punk? No. I call loadJPEG(). I call displayImage(). These are examples of functions that have already been written for my use. That makes it easy!

So you can plan ahead and figure out which components can be built up and reused, or you can use components that other people have built for you.

Examples pre-built components are: the standard C library (printf(), which we'll be using a lot of in this guide), the GTK+ library (a GUI library used with GNOME), the Qt toolkit (a GUI library used with the K Desktop), libSDL (a library for doing graphics), OpenGL (a library for doing 3D graphics), and so on, and so on. You can use all these to your own devious ends and you don't have to write them again!

2.4. Hello, World!

This is the canonical example of a C program. Everyone uses it:

/* helloworld program */

#include <stdio.h>

int main(void)
{
    printf("Hello, World!\n");

    return 0;
}

We're going to don our long-sleeved heavy-duty rubber gloves, grab a scapel, and rip into this thing to see what makes it tick. So, scrub up, because here we go. Cutting very gently...

Let's get the easy thing out of the way: anything between the digraphs /* and */ is a comment and will be completely ignored by the compiler. This allows you to leave messages to yourself and others, so that when you come back and read your code in the distant future, you'll know what the heck it was you were trying to do. Believe me, you will forget; it happens.

(Modern C compilers also treat anything after a // as a comment. GCC will obey it, as will VC++. However, if you are using an old compiler like Turbo C, well, the // construct was a little bit before its time. So I'll try to keep it happy and use the old-style /*comments*/ in my code. But everyone uses // these days when adding a comment to the end of a line, and you should feel free to, as well.)

Now, what is this #include? GROSS! Well, it tells the C Preprocessor to pull the contents of another file and insert it into the code right there.

Wait--what's a C Preprocessor? Good question. There are two stages (well, technically there are more than two, but hey, let's pretend there are two and have a good laugh) to compilation: the preprocessor and the compiler. Anything that starts with pound sign, or "octothorpe", (#) is something the preprocessor operates on before the compiler even gets started. Common preprocessor directives, as they're called, are #include and #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 gratuitiously spread its name around whenever I get the opportunity. Octothorpe. Octothorpe, octothorpe, octothorpe.

So anyway. After the C preprocessor has finished preprocessing everything, the results are ready for the compiler to take them and produce assembly code, machine code, or whatever it's about to do. Don't worry about 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. Octothorp.

What about the rest of the line? What's <stdio.h>? That is what is known as a header file. It's the dot-h at the end that gives it away. In fact it's the "Standard IO" (stdio) header file that you will grow to know and love. It contains preprocessor directives and function prototypes (more on that later) for common input and output needs. For our demo program, we're outputting the string "Hello, World!", so we in particular need the function prototype for the printf() function from this header file.

How did I know I needed to #include <stdio.h> for printf()? Answer: it's in the documentation. If you're on a Unix system, man printf and 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 mystery shall remain!

So take a breather...look back over the sample code. Only a couple easy lines to go.

Welcome back from your break! I know you didn't really take a break; I was just humoring you.

The next line is main(). This is the definition of the function main(); everything between the squirrely braces ({ and }) is part of the function definition.

A function. "Great! More terminology I don't know!" I feel your pain, but can only offer you the cold heartless comfort of more words: a function is a collection of code that is to be executed as a group when the function is called. You can think of it as, "When I call main(), all the stuff in the squirrley braces will be executed, and not a moment before."

How do you call a function, anyway? The answer lies in the printf() line, but we'll get to that in a minute.

Now, the main function is a special one in many ways, but one way stands above the rest: it is the function that will be called automatically when your program starts executing. 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.

Oh, that's another thing: once the program executes past the end of main(), down there at the closing squirrley brace, the program will exit, and you'll be back at your command prompt.

So now we know that that program has brought in a header file, stdio.h, and declared a main() function that will execute when the program is started. What are the goodies in main()?

I am so happy you asked. Really. We only have the one goodie: a call to the function printf(). You can tell this is a function call and not a function definition in a number of ways, but one indicator is the lack of squirrely braces after it. And you end the function call with a semicolon so the compiler knows it's the end of the expression. You'll be putting semicolons after most everything, as you'll see.

You're passing one parameter to the function printf(): a string to be printed when you call it. Oh, yeah--we're calling a function! We rock! Wait, wait--don't get cocky. What's that crazy \n at the end of the string? Well, most characters in the string look just like they are stored. But there are certain characters that you can't print on screen well that are embedded as two-character backslash codes. One of the most popular is \n (read "backslash-N") that corresponds to the newline character. This is the character that causing further printing to continue on the next line instead of the current. It's like hitting return at the end of the line.

So copy that code into a file, build it, and run it--see what happens:

Hello, World!

It's done and tested! Ship it!