Day 1 Class Notes

Compiling “Hello, World!”

Brian Kernighan and Dennis Ritchie started off The C Programming Language, the book that defined and introduced the language, with this example, and it's traditional to follow in their footsteps. [download]

#include <stdio.h>

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

}

On Athena, you can compile this with the following commands:

athena% gcc -o hello hello.c
athena% hello
Hello world!
athena% 

You'll need an editor in which to type the program. On Athena, a good editor is GEdit, which you can run by typing gedit & or gedit filename &. If you're logged in remotely, try joe (or joe filename), a simple text editor. (Ctrl-K X saves and exits; more commands are available via help.) Of course, if you're a fan of vim or Emacs, go ahead and use them. Both have excellent support for syntax highlighting, code navigation, and other tools to make editing large programs easier, although they do have a bit of a learning curve.

C programs consist of functions, which contain statements. (The first line in this program is a preproccessor directive, which we haven't talked about yet. Briefly, its purpose is to include the file stdio.h from the standard library of C functions, which allows us to use printf(), scanf(), etc.) Every application must contain a function main, which is called when the application starts. This program's main contains one statement, which is a function call to printf(). The argument (or parameter) passed to printf is the string (group of characters in quotes) "Hello, world!\n". The \n at the end tells the program to display a newline (line break) before exiting and printing the athena% prompt.

Modify the program so it has a few more lines, as follows:

#include <stdio.h>

int main(void) {
    double f, c;

    scanf("%lf", &f);
    c = (f-32) * 5/9;

    printf("Temperature in Celsius = %f", c);
    return 0;
}

This program does several things. The first line inside main declares two variables f and c, which are of type double. It then uses scanf with the format specifier "%lf" to read a value into the variable f. (We will see Friday why we need to write &f. For now, just remember that variables that are modified function a function need an ampersand.) The third line is an arithmetic expression that calculates the Celsius temperature and stores the result into c. The fourth line displays the resulting calulation, using the format specifier "%f" to display the second argument. (I have not figured out why the format specifiers differ for scanf and printf; usually they don't.) printf is a special function that takes at least one argument, and displays any following arguments in order when you give a format specifier. If we compile and run this program, we get:

athena% gcc -o hello hello.c
athena% hello
212
Temperature in Celsius = 100.000000
athena% 

We can make this program a bit more modular by breaking off some of the major functionality into separate functions. This lets us reuse the code if we need it more than once, and modify it in isolation from the rest of the program. [download]

#include <stdio.h>

double f2c(double f);

double input_double(void);

int main(void) {

    printf("Enter Fahrenheit temperature: ");

    double f;
    f = input_double();

    printf("Celsius is %f\n", f2c(f));
    printf("For reference: \n");

    printf("Boiling is %f and freezing is %f\n",
            f2c(212), f2c(32));

    return 0;
}

double f2c(double f) {

    return (f-32) * 5/9;
}

double input_double(void) {
    double x;
    scanf("%lf", &x);

    return x;
}

The top of this program contains two function declarations, letting us reference the names of the functions before their definitions at the bottom of the page. Here you can see that we have called the f2c function several times from main, each time supplying a different actual parameter (f, 212, and 32) to serve as the formal parameter f in the body of f2c.

Notice that each function has its own set of variable names. This is because every code block (series of statements between curly braces) has its own scope. A scope can be loosely defined as a lifetime for variables. For example, any code inside input_double can refer to x. Once the flow of control leaves input_double, the variable x has gone out of scope, and it cannot be accessed from main. If the function were called again, the old value for x is not guaranteed to be kept around. On the flip side, code inside input_double cannot access any variables in the scope of main, because the functions do not overlap. The only way main can pass data is by providing them as parameters to function calls. Of course, if you want, you can declare variables outside of any function (just as you declare functions). However, as any function can modify this data at any time, it is a major debugging headache and generally poor programming style to use global variables.

The in-class assignment was to write a program to calculate the area of a circle given its radius, and to calculate the area of a ring (the space between two concentric circles) given the inner and outer radii. Here is my version of the solution: [download]

/* Program to calculate
   - the area of a circle with a given radius
   - the area of a ring with the given radii
   Geoffrey Thomas, 2008-01-23, SIPB IAP C
 */
#include <stdio.h>
#include <math.h>

//Reads in a double value from the keyboard.
double input_double(void);

//Calculates the area of a circle.
// r - radius of circle
// returns: area of circle with radius r
double area(double r);

int main(void) {

    double r1, r2, a, r;

    // Part 1: ask for radius and compute area of circle

    printf("Enter radius: ");
    r1 = input_double();
    printf("Area of circle with radius %f is %f.\n", r1, area(r1));

    // Part 2: ask for two radii and compute area of ring
    printf("Enter first radius: ");
    r1 = input_double();

    printf("Enter second radius: ");
    r2 = input_double();
    if (r1 > r2)

        a = area(r1) - area(r2);

    else
        a = area(r2) - area(r1);

    printf("Area of ring between these is %f.\n", a);

    return 0;

}

double area(double r) {
    return M_PI * r * r;

}

double input_double(void) {
    double x;

    scanf("%lf", &x);
    return x;
}

My solution moves both the area-calculating logic and value-input routine to a separate, simple functions to avoid duplicating code. I can, for example, add error-checking to my input routine once and have it take effect everywhere in my code. This program also uses the constant M_PI from the standard library header math.h. (It also demonstrates the use of /* ... */ and // comments, which are ignored by the compiler.)

One new type of statement used here is the conditional, if. An if statement evaluates an expression in parentheses that follows it, and if that result (as an integer) is nonzero, it runs the statement or block of statements following it. If not, it will run an else clause immediately following it if one exists.

Finally, we looked briefly at looping constructs:

while (condition)
    body;

A while loop resembles an if statement, except that it keeps on executing its body until the condition is zero (false). More precisely, before it executes the body, it tests the condition; if the condition fails, it exits the loop, otherwise it runs the body and repeats. It resembles an infinite sequence of if (condition) body; if (condition) body;...

do {
  body;
} while (condition);

A do loop always executes its body at least once, but otherwise works just like a while loop. (It also requires using braces around its body.) It is just syntactic sugar for body; while (condition) body; — its functionality is entirely equivalent, but it is in the language because it makes programs easier to write and read.

for (init; cond; next)
    body;

The for loop is the most involved of the three. First, it runs init. Then it tests cond, and if that succeeds, runs the body. Before testing cond again, though, it runs next. This loop is also syntactic sugar, as it is equivalent to init; while (cond) {body; next;}; however, the for form is much easier to read for most common loops. Consider the following version of our radius program, which displays the areas of circles with radii 1 through 5 [download]:

#include <stdio.h>
#include <math.h>

//Calculates the area of a circle.
// r - radius of circle
// returns: area of circle with radius r
double area(double r);

int main(void) {

    double r;

    for (r = 1; r <= 5; r++)

        printf("Area of circle with radius %f is %f\n",
                r,
                area(r));

    return 0;
}

double area(double r) {

    return M_PI * r * r;
}

This program starts by setting r to 1. It then displays output and increments r (the notation r++ is more-or-less syntactic sugar for r=r+1) until r is no longer 5 or smaller.

These are almost all of the basic statement types in C. On Friday, we will pick up from loops and continue by looking at the remaining statment types, as well as arrays, strings, and pointers.

Code colorization from CodeColorizer. Copyright © 2008 Geoffrey Thomas. All class notes and example files for this course are available under the Creative Commons Attribution-Share Alike license.