Skip to the content of the web site.

Lesson 1.2: Anatomy of a program

Previous lesson Next lesson


Up to this point, you have compiled and executed a very small program, but before we can start talking about programming in general, we need to get some basic terms down.

First, for refresh your memory, this was our program:

#include <iostream>

int main();

int main() {
	std::cout << "Hello world!";
	std::cout << std::endl;

	return 0;
}

We will now describe the different components of this program.

Pre-processor directives

Any line that begins with a # is a pre-processor directive. For the majority of this course, you will only ever see one pre-processor directive, that which includes a file or standard library of functions and objects that you will use. In Lesson XXX, we will begin to look into detail how the pre-processor actually works.

For now, however, just read this line as "Include the eye-oh stream library in this program." Just like a physical library is a collection of books which you can reference for information you don't currently have, C++ libraries are collections of objects and functions that perform common operations. The io is short for input-output, so this library deals with getting data to the program and allowing the program to output data to the user.

Definition: pre-processor include directive
An instruction or directive that the compiler should use information found in the given file or standard library. The most common library is that used for input and output is the iostream library.

Statements

Next, between two braces ({})are three statements. Each statement describes instruction that the executing program must perform. Each statement has alphabetic names and various symbols, and each statement is terminated by a semicolon (;).

Statements are executed one at a time in the order in which they appear between the braces, where one statement must finish execution before the program starts to execute the next.

Definition: statement
A statement is a description of instructions that are to be executed when the program is run. Statements are executed in the order in which they are listed, and each statement finishes execution before the next one begins execution. A statement always includes names and operations and is always terminated by a semicolon (;).

Blocks of statements

Any collection of statements that appear between an opening brace ({) and a closing brace (}) is said to be a block of statements. It is possible to have an empty collection of statements that does nothing: {}.

Definition: a block of statements
A block of statements is any pair of matching opening and closing braces ({ and }) surrounding zero or more statements. When the block of code is executed, the statements in that block of code are executed one at a time.

There is one other place where braces are used; however, in that case, the source code between the braces are not full statements (no terminating semi-colon).

Function declarations and function definitions

Finally, there is something that looks similar to functions that you may have seen in secondary school, like $\sin(x)$ which has one parameter $x$, or $\gcd(m, n)$ which has two parameters $m$ and $n$. In this case, the function main(), and without seeing any symbols between the parentheses, this suggests that this is a function that does not take any parameters. The first place you see a reference to main() is in the function declaration:

int main();

This declares the function to the compiler: "We will be using a function main() that takes no arguments and returns an integer." We will see how this is done later, but if we were to write a greatest-common divisor function, its declaration would be

int gcd( int m, int n );

which says "The function gcd takes two integers $m$ and $n$ as parameters and returns an integer."

Immediately after the function declaration is a description of what the function does; that is, this is the function definition:

int main() {
	std::cout << "Hello world!";
	std::cout << std::endl;

	return 0;
}

You will note that the function definition is the function declaration immediately followed by a block of statements. When we call the main() function, the statements in that block are the ones that will be executed. We will, in general, refer to the block of statements associated with a function as the body of the function.

Definition: function declaration
A statement that tells the computer that a function with a specific name will be used. The compiler will use this information to ensure that the function is properly defined and used.

Definition: function definition
The description of what a function is to do, usually including the function declaration without the semicolon followed by a block of statements. When the function is called, it is the block of statements following the function definition that will be executed in the given order.

Definition: body of a function
The block of statements that are associated with a function. This is the block of statements to be executed when the function is called.

You may be wondering why we must both declare and define a function, especially when the second has all the information in the first:


int main();                                // function declaration

int main() {                               // function definition
	// Zero or more statements...
}

This is because the function may not be declared in the same place that it is defined. In some respects, this is a consequence that C++ is based on the C programming language, which itself was designed back in 1970.

Flow chart

Another way of looking at this program is a flow chart:

The rounded boxes at the top and bottom represent the start and the end of the main() function. The first box states in English what the first statement is to do. The first statement must be completed before the next statement is performed. Next, a new line is printed to the console, and once this is completed, the function returns. The value the function returns is 0.

Review

In your own words, describe each of these concepts:

Important concept:
In programming, there are often more than one word to describe various components of a computer program: a function declaration may be called a prototype or signature. In this course we will be entirely consistent with respect to our terminology; however, when you read any other literature, you will fall upon words that appear to mean the same or similar concepts. In some cases, they are identical; while in others, there may be very subtle differences, and to emphasize those differences, a different name was chosen. For example, functions may also be called procedures, routines, subroutines or even subprograms. If you see a new term when you are reading literature or documentation, first try to determine whether or not within the given context it seems to suggest something with which you are already familiar.

Questions and practice:

1. The following statement contains braces, but those braces do not represent a block of statements. Why?

       int i{3};

Answer: A statement is terminated by a semicolon, but that is not the case here.

2. In the following source code that implements the fast-Fourier transform and its inverse transform, count the number of pre-processor directives, statements, blocks of statements, function declarations and function definitions. Do not count anything between a 'for (' and its matching ')' as a statement.

#include <cassert>
#include <iostream>
#include <cmath>
#include <complex>

void  FFT( std::complex<double> *array, int n );
void iFFT( std::complex<double> *array, int n );

void FFT( std::complex<double> *array, int n ) {
    assert( n > 0 && (n & (~n + 1)) == n );

    double const PI{4.0*std::atan( 1.0 )};

    for ( int i{n/2}; i >= 1; i /= 2 ) {
	std::complex<double> w{1.0};
	std::complex<double> wn{
	    std::exp( std::complex<double>( 0.0, -PI/i ) )
	};

	for ( int j{0}; j < i; ++j ) {
	    for ( int k{j}; k < n; k += 2*i ) {
		int m{k + i};

		std::complex<double> tmp{array[k] + array[m]};
                array[m] = (array[k] - array[m])*w;
                array[k] = tmp;
            }

            w *= wn;
        }
    }

    for ( int i{0}, j{0}; i < (n - 1); ++i ) {
        if ( i < j ) {
	    std::complex<double> tmp{array[j]};
            array[j] = array[i];
            array[i] = tmp;
        }

        int k;

	for ( k{n/2}; k <= j; k /= 2 ) {
            j = j - k;
        }

        j += k;
    }
}

void iFFT( std::complex<double> *array, int n ) {
    for ( int i = 0; i < n; ++i ) {
        array[i] = std::conj( array[i] );
    }

    FFT( array, n );

    for ( int i = 0; i < n; ++i ) {
        array[i] = std::conj( array[i] )/double( n );
    }
}

3. As you know from your mathematics courses, $sin(3$ is an invalid mathematical statement, as there is no matching closing parenthesis. Similarly, in mathematics very often you will have different parentheses, so you may write $3 + 7{4(3 + y) + x + x[2 + x(5 - x) + y(1 - z)]}$ instead of $3 + 7(4(3 + y) + x + x(2 + x(5 - x) + y(1 - z)))$. In either case, however, each opening delimiter has a matching closing delimiter. The following would not be valid mathematical expressions, as there are opening delimiters that do not have matching closing delimiters or vice versa

$3 + 7{4(3 + y) + x + x[2 + x(5 - x) + y(1 - z)]}$
$3 + 7{4 \times 3 + y) + x + x[2 + x(5 - x) + y(1 - z)]}$
$3 + 7{4(3 + y) + x + x[2 + x(5 - x + y(1 - z)]}$
$3 + 7{4(3 + y) + x + x(2 + x[5 - x) + y(1 - z)]}$
$3 + 7{4(3 + y) + x + x[2 + x(5 - x) + y(1 - z)}$
$3 + 7{4(3 + y) + x + x[2 + x(5 - x + y(1 - z)]}$

In the following examples, there are opening parentheses without matching closing parentheses, or vice versa.

$3 + 7(4(3 + y) + x + x(2 + x \times 5 - x) + y(1 - z)))$
$3 + 7(4(3 + y) + x + x(2 + x(5 - x) + y(1 - z))$
$3 + 7(4(3 + y) + x + x)2 + x(5 - x) + y(1 - z)))$

4. For each of the opening delimiters, find the matching closing delimiter.

       ([()[]]{}) [{[]}[]()] ({[]}()) {()[{[]}]} {{[]}([])}
       { { } { } { { } } { } { { } } { } { { } } { } { { } } } { { } } { { } }

Previous lesson Next lesson