Excised content

From Language Elements

Includes

Pre-processor directive—tells the compiler to insert code from another file (typically declarations of other functions).

  #include <iostream> 

Code from the iostream file is inserted exactly as if you had typed it in yourself.

using namespace

tells the compiler where to look for definitions that aren't defined in our program.

using namespace std;

main function definition

Every program must have a main function. It is the starting point of program execution. This is what it looks like

int main() {
     // the function body goes here
  }

When execution reaches the end of main, the program terminates.

We're going to introduce our first syntax definition here:

Function returning value:

Form:
returnType Identifier ( ParameterList ) {
    Statement
}
Example:
int square(int num){
    return num * num;
}

Interpretation: the square of num is computed and the int result returned.

 

main is actually a function returning value, which means it fits this form.

Both main and square return an integer value (int). In the case of square the value returned (the output) represents the square of num, the value input.

In the case of main, the return value is actually passed to the operating system after the program is run. Normally it will be zero, meaning your program ran successfully. Other numbers represent codes for various kinds of errors. In this course we will generally return just 0;


This drawing looks at just the pre-compile / compile process.

The two work invisibly as a pair. It looks like one process to the programmer.

Any instruction that begins with a hash mark (#) is actually an instruction to the pre-compiler, the programmer's automated administrative assistant.

Here the assistant strips out all the comments and fetches the code from the iostream header file

The resulting code the compiler gets is much reduced except thatall code from the header file has been added. We don't show it because it's too complex.

The compiler checks the reultant code for syntax errors. If it finds any it will generate a report

Only if the code is grammatically correct will an output file be generated.


Output: Stream Insertion Operator

cout << expression; —output the value of expression to the standard output (screen) stream.

cout << "Hello world!" << endl;

<< is a left associative operator -- expressions are ouput left-to-right.

endl causes an newline ('\n') character to be output.


Input: Stream Extraction Operator

cin >> x; —Read a value from the standard input stream (usually the keyboard) and store it in the variable named x.

cin is an identifier for the standard input stream (keyboard) .

  1. Assigns to variables left to right order.
  2. What can be input depends on the data type of the variable.
  3. whitespace (tab, space, newline) is skipped.
  4. The reading marker keeps track of the next character to be read.

String Expressions

Objects of class string store sequences of characters:

string bookTitle;
bookTitle = "Programming in C++";

Strings can be joined with '+'.


from Variables

Input and Output

C++ treats inputs and outputs as streams of data—that is piece of data after piece of data after piece of data, flowing one after another as if in a stream.

There are three standard streams, only two of which we need to be concerned with (the third is an error stream, used for reporting errors, and works just like the output stream).

cout

The standard output stream. Data is inserted into the standard output stream using the insertion operator, << , for example,

cout << "The value of x is " << x << endl;

This means that the string literal "The value of x is " is first inserted into cout, then the current value of x is inserted and finally a special token endl is tossed in which tells the cout stream that the line has ended.

In this course the standard output stream will almost always be attached to the console window. Assuming x is currently 3.76, you would see

The value of x is 3.76

displayed on a console window on your computer screen.

cout is a pretty smart object and knows how to display data of almost any type properly.

cin

The standard input stream. Data is extracted from it using the standard extraction operator, >> , for example

double x;
int i;
cin >> x >> i;

declares a double variable x, an int variable i and then extracts values for them from the input stream, cin. cin will almost always be connected to the keyboard in this course.

Formatting Input

It's hard for a user to enter data into a program unless the programmer tells the user what is wanted. That is your program must prompt the user for input. Do this by mixing input and output commands as follows.

double cost;
int quantity;
cout << "Please input the unit cost: ";
cin >> cost;
cout << endl << "And now the number of items: ";
cin >> quantity;
cout << endl;

Note that by not inserting an endl at the end of the first cout statement we leave the cursor at the end of the prompt. Then we start the next cout with an endl moving the second prompt (and input) onto its own line.

From pass-by-reference

Side Effects

Arguments in the original C language were always passed by value. This was done to avoid side effects. Consider a little different version of the factorial function:


Code Notes

1. Don't forget that, as the expression engine will show you, the line result *= n-- is equivalent to result = result * n--

2. As usual, to evaluate n the TM looks the value of n up in memory. The effect of the post decrement is to decrement n after it has fetched the value. To see it in detail, step through the expression in the expression engine and watch the fetch-execute cycle closely.


The line

result *= n--; 

actually contains two potential side effects. Let's focus first on the one caused by decrementing in the middle of an expression.

The line is equivalent to the following two lines

result *= n;
 n--;

That is the original, in one line, both

  1. computes the next value of result (the main effect) as well as
  2. decrements n (the side effect).

But when are we decrementing n? Notice in this second version it is very clear that n is decremented after we used its previous value.

Post- and Pre- Increment and Decrement

When we increment or decrement, there are actually two forms of the operators, known as post-decrement (or post-increment) and pre-decrement (or pre--increment). In the example above the decrement operator is said to be in the post position (it comes after the variable being decremented).

It is perfectly grammatically correct to put the decrement operator before the variable as:

result *= --n; 

but now it means something different. Again, writing it as two lines we would need to write it this way—

n--;
result *= n;

Putting an increment/decrement operator in the pre- position means that the increment/decrement operation is carried out before the value of the variable is used.

Here is the same program ammended to use pre-decrement. Step through both versions in the teaching machine to see the difference


Code Notes

1. As usual, to evaluate n the TM looks the value of n up in memory. The effect of the pre-decrement is to decrement n before it fetches the value. Thus the value fetched is the new value. To see it in detail, step through the expression in the expression engine and watch the fetch-execute cycle closely.

2. To deal with the differences we had to preset result to n because the very first time we multiply we will actually be using n-1

We also changed the test to n > 2 because by the time we carry out the test the multiplication has already been done. The answer would still have been correct but we would have passed through the loop an extra time unnecessarily.

You might consider how you could re-write the first (post-decrement) version to have one less passes through the loop.


While this second version works it is far less understandable than the first.

In fact, in general we regard incorporating incrementing into expressions as a side effect to be quite advanced programming

  1. We recommend you not use the technique yourself. Instead, increment separately.
  2. However, it is a sufficiently common part of the standard C++ idiom that we do expect you to be able to read and understand code that does use it.

Final Caveat

increment/decrement operators should never be incorporated into expressions on variables that are used more than once in the expression.

For example

y = ++n * log(n);

should never be used. The n is incremented on the memory fetch part of the evaluation cycle and there is no way to predict which n optimizing compilers will decide to fetch first.


From Arrays

Median Problem

Problem: Find the median grade for a class.

Analysis:

1. We're going to need an array to hold the grades. How big should it be?

If we want to handle different classes, we won't know the class size until we read the data in from the file (which is when we run the program). But we have to size the array when we build the program.

One approach is to create an array large enough to handle any reasonable class size and then only use part of it. We'll also have to watch out for a class bigger than we planned for.

So we'll pick a MAX_CLASS_SIZE and declare a float grades[MAX_CLASS_SIZE]

2. Clearly we're going to have to read the data in from a file. That should probably be done by a function.

We should give the function the array and tell it about MAX_CLASS_SIZE and then let it tell us the actual size

3. In order to find the median we're going to have to sort the file into either ascending or descending order. Another funtion. It will need the grades array and the actual class size.

4. compute the median.

Major Data:

int MAX_CLASS_SIZE
float grades[MAX_CLASS_SIZE]

Headers:

int getGrades(float gradeData[], int maxSize) // return actual size
void sort(float gradeData[], int size)

Algorithm:

Read values into grades[0..N-1]

Sort grades in increasing order

if N is even

median = (vals[N/2-1] + vals[N/2]) / 2

else

median = vals[N/2]

Final Comment:

Why N/2 in the last line?

If N is odd, for example 5

 

Here is the example we worked out in class, recut for the Teaching Machine. The sort routine is shown here.


Code Notes

1. This sort function is a classic example of a double loop. The way to understand it is to focus on the inner loop.

2. What the inner loop does is to compare the i'th element of the array with every element that comes after it. If any element is bigger than the i'th one it is swapped with it. Thus, at the end of a pass through the inner loop, the largest element after the i'th one has replaced it, like the largest bubble floating to the top.

3. The function of the outer loop, then, is to pick i. Start with element 0 (theTable[0]) and use the inner loop to "bubble" the largest element in the whole array to position 0. Then go to position 1 and "bubble" the next largest element into that position. And so on, to the third largest in the position 2, 4'th largest in 3, until we finally reach the second last position in the array.

4. When the outer loop gets i to the second last position, the inner loop only has to check the last position. Either the last element is bigger than the second last (in which case they are swapped) or it isn't. Either way, we're done. There's no reason to set i to the last postion because there's nothing that comes after it for the inner loop to work on.


Of course it uses the swap routine we developed earlier.

Then the median is computed by putting it all together as shown here.

From Strings

Const References

(Copied in from pass-by-reference)

The display above doesn't actually show the getFloat function implementation or declaration. If you've run the example in the TM already you may have noticed something strange about them. Here's the implementation.

What's up with the const keyword in the function prototype

double getDouble( const string& what)

In the first place why not just pass the string by value as we would normally do? After all we don't want to change it. It's just input for the function.

Remember that pass-by-value means a copy gets made. In this case a full copy of the string object (although you won't see it reflected in your simple memory model on the TM—it's done behind the scenes in another part of memory called the heap that we won't talk about until the advanced course). Making such a copy is potentially very expensive because strings can be very large.

  1. It's expensive because it takes time to make the full copy.
  2. It's expensive because it takes extra memory to hold the copy.

Passing-by-reference suppresses copying. The only thing passed into the function is the reference to the original object (which is about the size of an int or long).

However, there is an implication when we pass by reference that the variable will be modified.

The const tells the compiler (and more importantly, any clients who are going to use our function) that although prompt is being passed by reference it will not be modified. In other words, it is read-only.


From Files and Streams

Class Examples

Here are the examples shown in class;

gradeEntry.cpp
the original gradeEntry program, with no arrays or files
studentGradeArray.cpp
the program with parallel data arrays added, as developed by Li Cheng in class
studentGradeArray2.cpp
an ammended version with an additional parallel data array to handle the names of the course components. Partially developed in class then finished off properly.
studentGradeFileSimple.cpp
student marks are now read in from an input file, courses.txt and results written to an output file, results.txt.
studentGradeFileFull.cpp
student data and course data are read in from the input file. The output file also includes course statistics.
courses.txt
a simple input data file for studentGradeFileSimple
coursesFull.txt
a simple input data file for studentGradeFileFull
matrices.cpp
The last example done, whereby a pair of 2-D matrices are read in from a file and then some simple calculations performed on them
arrays.xls
the excel file used to generate data for the matrices example
arrays.txt
the tab separated text file generated form the above excel file (using File-SaveAs) used as the actual input to the matrices program.

The Build Process

Computer programs have to be built. We use a number of processes (computer programs) to build a program

An editor is a specialized word processor used to prepare source modules in the language of choice (e.g. C++, Java, Fortran, Basic)

The precompiler adds in standard pre-written code (boilerplate) from include files you specify to produce a complete source module.

The precompiler is like a secretary that helps you pull together a full source document.

The compiler produces object code for the target computer/operating system.

The compiler is like a translator that converts your module from the language of your choice (C++) to language the computer (PC, MAC, Sun) understands.

The linker ties multiple modules together into a complete program

  1. Your module
  2. Other modules from the same project
  3. Modules from the library

An executable is a program that will run on the computer. The editor, precompiler, compiler and linker are all executables.

So is your program!