A short introduction to computer programming, using C++

Roger Mitton, Birkbeck, University of London

Chapter 2

Arithmetic expressions

C++ uses the following arithmetic operators:
+addition
subtraction
*multiplication
/division
%modulo

The last one is perhaps unfamiliar. The result of x % y ("x mod y") is the remainder that you get after dividing the integer x by the integer y. For example, 13 % 5 is 3; 18 % 4 is 2; 21 % 7 is 0, and 4 % 6 is 4 (6 into 4 won't go, remainder 4). num = 20 % 7; would assign the value 6 to num.

How does the computer evaluate an expression if there is more than one operator in it? For example, given 2 + 3 * 4, does it do the addition first, thus getting 5 * 4, which comes to 20, or does it do the multiplication first, thus getting 2 + 12, which comes to 14? C++, in common with other programming languages and with mathematical convention in general, gives precedence to *, / and % over + and –. This means that, in the example, it does the multiplication first and gets 14.

If the arithmetic operators are at the same level of precedence, it takes them left to right. 10 – 5 – 2 comes to 3, not 7. You can always override the order of precedence by putting brackets into the expression; (2 + 3) * 4 comes to 20, and 10 – (5 – 2) comes to 7.

Some words of warning are needed about division. If the operands are both of type int, the result of a division is also of type int. For example, the result of 7 / 2 is 3, not 3.5. If num, which is an int, had the value 7, then num / 2 would be 3, and 18 / num would be 2. Computers are perfectly capable of handling floating-point numbers such as 3.5, but the type of division carried out depends on the type of the operands. In order to get a result of 3.5, it would be necessary for at least one of the operands to be a floating-point number, such as 7 / 2.0. But if they are both of type int, you get integer division with an integer result. I'm not going to say much about floating-point numbers in this introduction.

A computer would get into difficulty if it tried to divide by zero. Consequently, the system makes sure that it never does. If a program tries to get the computer to divide by zero, the program is unceremoniously terminated, usually with an error message on the screen.

Exercise 2A

Write down the output of this program:

#include <iostream>
using namespace std;
int main()
{   int num = 5;
    cout << num << endl;
    num = num + 2;    cout << num << endl;
    num = num / 3 * 6;    cout << num << endl;
    cout << 7 + 15 % 4 << endl;
    num = 24 / 3 / 4;    cout << num << endl;
    num = 24 / (num / 4);    cout << num << endl;
}

To check your answers, click on Answers to the exercises.

Identifiers and comments

I said earlier that you could use more or less any names for your variables. I now need to qualify that.

The names that the programmer invents are called identifiers. The rules for forming identifiers are that the first character can be a letter (upper or lower case) and subsequent characters can be letters or digits or underscores. (Actually the first character can be an underscore but identifiers beginning with an underscore are often used by system programs and are best avoided.) Other characters are not allowed. C++ is case-sensitive, so Num, for example, is a different identifier from num.

The only other restriction is that you cannot use any of the language's keywords as an identifier. You couldn't use int as the name of a variable, for example. There are 74 keywords but most of them are words that you are unlikely to choose, such as reinterpret_cast or xor_eq. Ones that you might accidentally hit upon are break, case, catch, class, const, continue, delete, double, export, float, friend, long, new, return, short, switch, this, throw, try and union. You should also avoid using words which, though not technically keywords, have special significance in the language, such as cin, cout and string.

Programmers often use very short names for variables, such as i, n or x for integers. There is no harm in this if the variable is used to do an obvious job, such as counting the number of times the program goes round a loop and its purpose is immediately clear from the context. If, however, its function is not so obvious, it should be given a name that gives a clue as to the role it plays in the program. If a variable is holding the total of a series of integers and another is holding the largest of a series of integers, for example, call them total and max rather than x and y.

The aim in programming is to write programs that are "self-documenting", meaning that a (human) reader can understand them without having to read any supplementary documentation. A good choice of identifiers helps to make a program self-documenting.

Comments provide another way to help the human reader to understand a program. Anything on a line after "//" is ignored by the compiler, so you can use this to annotate your program. You might summarise what a chunk of program is doing:

// sorts numbers into ascending order
or explain the purpose of an obscure bit:
x = x * 100 / y;   // x as percent of y

Comments should be few and helpful. Do not clutter your programs with statements of the obvious such as:

num = num + 1;   // add 1 to num
Judicious use of comments can add greatly to a program's readability, but they are second best to self-documentation. Their weakness is that it is all too easy for a programmer to modify the program but forget to make any corresponding modification to the comments, so the comments no longer quite go with the program. At worst, the comments can become so out-of-date as to be positively misleading.

Exercise 2B

Say for each of the following whether it is a valid identifier in C++ and, if not, why not:

BBC, C++, y2k, Y2K, old, new, 3GL, a.out, remove,
first-choice, 2nd_choice, third_choice, constant, UNION

To check your answers, click on Answers to the exercises.

String variables

As well as variables of type int we can have variables of type string. To do this we have to include another of those lines at the start of the program whose purpose I have yet to explain:

#include <string>
We could declare a string variable as follows:
string s;
and also initialize it if we wanted to:
string s = "Wallace";
We can change the value of a string with assignment:
s = "Feathers McGraw";
or, if we had two strings s and t:
s = t;   // (s and t do not need to be the same length)
We can also use cin >> to give a new value to a string:
cin >> s;
When this statement is executed, the computer will skip any leading spaces or tabs or blank lines until it comes to a non-space character. This will be the first character of the string s. Then it picks up characters and adds them to s until it comes to a space, tab or end-of-line, at which point it stops. So, if the input was:
                              Silverdale
the value in s would be "Silverdale" (without the leading spaces). If the input was:
Warton Crag
the value in s would be "Warton", since it would stop at the space.

Another useful input function with strings is getline, as in

getline(cin, s);
This takes the whole of the input line and puts it into s, spaces and tabs included. Executing this statement with the input line
         Silverdale,        Warton Crag  (with the line ending after "Crag") 
would put the whole line into s, including all the spaces, from the leftmost of the leading spaces up to the "g" of "Crag".

The "+" operator has special significance with strings; it is the concatenation operator. For example, if s had the value "Wallace" and t had the value "Grommit", then

s = s + " and " + t;
would give s the value "Wallace and Grommit".

If you want to know how long a string is, you can find out with the length function. If s is the string, s.length() (don't forget the brackets) is the length. You could say, for example:

string s;
cin >> s;
int len = s.length();
And you can obtain a substring of a string with the substr function. For example if s has the value "Silverdale", then s.substr(0,6) will give you the first six letters, ie the string "Silver". The first number in brackets after the substr says where you want the substring to begin, and the second number says how long you want it to be. Note that the initial character of the string is at position 0, not position 1. If you leave out the second number, you get the rest of the string. For example, s.substr(6) would give you "dale", ie the tail end of the string beginning at character 6 ('d' is character 6, not 7, because the first one is character 0).

You can output substrings with cout << or assign them to other strings or combine them with the "+" operator. For example:

string s = "software services";
s = s.substr(0,4) + s.substr(8,1) + s.substr(13);
cout << s << endl;
will output "soft ices".

Exercise 2C

Say what the output of the following program fragment would be:

string s = "artificial reality";
cout << s.substr(11,4) + " " + s.substr(0,3) << endl;
cout << s.substr(11).length() << endl;

To check your answers, click on Answers to the exercises.

Conditionals (if statements)

To write anything more than very straightforward programs we need some way of getting the computer to make choices. We do this in C++ with the keyword if. We can write, for example,

if (num == 180)
    cout << "One hundred and eighty!" << endl;
When the computer executes this, it first sees whether the variable num currently has the value 180 or not. If it does, the computer displays its message; if it doesn't, the computer ignores the cout line and goes on to the next line.

Note that the conditional expression (num == 180) has to be in brackets.

Note also that, to test whether num has the value 180 or not, we have to write if (num == 180) and not if (num = 180). We have to remember to hit the "=" key twice. This is a serious nuisance in C++, especially for beginners. It comes about because the language uses the "=" operator for a different purpose, namely assignment. num = 180 does not mean, " num is equal to 180." It means, "Give the value 180 to num." You may feel that it is obvious that assignment is not what is intended in if (num = 180), but unfortunately the rules of the language allow an assignment at this point, and that is how the computer will interpret it. The line if (num = 180), with one "=" sign, will actually give the value 180 to num. You have been warned.

The following program takes two numbers and displays a message if they happen to be the same:

#include <iostream>
using namespace std;
int main()
{   int num1, num2;
    cout << "Please key in a number: ";
    cin >> num1;
    cout << "And another: ";
    cin >> num2;
    if (num1 == num2)
        cout << "They are the same" << endl;
}

Conditional expressions — the kind that follow an if – can be formed using the following operators:
==is equal to
!=is not equal to
>is greater than
<is less than
>=is greater than or equal to
<=is less than or equal to

When these operators are used with integers, their meaning is obvious, but they can also be used with strings. Here their meaning corresponds to something like alphabetical order. For instance, if (s < t), where s and t are strings means "If s comes before t in alphabetical order." So it would be true if s had the value "Birkbeck" and t had the value "College". All the upper-case letters come before the lower-case, so (s < t) would still be true if s had the value "Zebra" and t had the value "antelope" (upper-case 'Z' comes before lower-case 'a').

But what about strings that contain non-alphabetic characters? Would s come before t if s had the value "#+*" and t had the value "$&!"? To find the answer we have to consult the ASCII table — the American Standard Code for Information Interchange. ASCII, pronounced to rhyme with "Askey", defines a particular ordering of all the characters on the keyboard. (There are other orderings in use, notably EBCDIC which is used on IBM mainframe computers, but, since ASCII was adopted by PCs, it has become the general de facto standard.) The ASCII table tells us that the character '#' comes before the character '$', for instance.

There is a listing of the printable characters in the ASCII set at the end of this chapter. Some points worth remembering are:

Exercise 2D

Say, for each of the following, whether s < t would be true or false, assuming that s had the value on the left and t had the value on the right:
"A""9"
"Zurich""acapulco"
"Abba""ABBA"
"long_thing_with_a_$""long_thing_with_a_&"
"King's College""King Kong"

To check your answers, click on Answers to the exercises.

Two-way branches (if .. else)

The following program fragment tells students whether they have passed their exam:

int  exammark;
cout << "Please key in your exam mark: ";
cin >> exammark;
if (exammark >= 40)
     cout << "A satisfactory result" << endl;

What happens, in the case of this exam mark program, if a student's mark is < 40? The program does nothing. This kind of if statement is a one-way branch. If the condition is true, we do something; if not, we do nothing. But in this case this seems unsatisfactory. If the exam mark is < 40, we would like it to display "I'm afraid you have failed." We could arrange this by including another test — if (exammark < 40) — or, better, we could do it by using the keyword else, thus:

if (exammark >= 40)
     cout << "A satisfactory result" << endl;
else cout << "I'm afraid you have failed." << endl;
The else turns a one-way branch into a two-way branch. If the condition is true, do this; otherwise, do that.

Exercise 2E

Write a program that takes two numbers, one representing a husband's salary and the other representing the wife's, and tells them whether or not their combined income makes them due for tax at the higher rate (exceeding £40000).

To check your answers, click on Answers to the exercises.

Let's suppose we want to extend the exam mark program so that candidates who have passed get two lines of output, thus:

if (exammark >= 40)
     cout << "A satisfactory result" << endl;
     cout << "You may proceed with your project." << endl;
else cout << "I'm afraid you have failed." << endl;
Unfortunately the compiler will object to this. It will say that it has encounted an else in an unexpected place. What is the problem?

Although the layout of this program suggests that the "satisfactory" line and the "proceed with project" line go together, there is nothing to indicate this to the compiler. As I pointed out earlier, the compiler pretty much ignores the layout. So far as the compiler is concerned, we have a one-way if statement (the kind without an else) which ends at the first endl; Then there is another cout line (proceed with project) which is not part of the if statement; it's just the first line of the rest of the program. And then, unexpectedly, appears an else.

We need some way of bracketing together the "satisfactory" line and the "proceed with project" line so as to make it clear to the compiler that both of these lines come under the if. This is how we do it in C++:

if (exammark >= 40)
{    cout << "A satisfactory result" << endl;
     cout << "You may proceed with your project." << endl;
}
else cout << "I'm afraid you have failed." << endl;
The curly braces have the effect of grouping all the statements inside them into a programming unit called a block. If the exam mark is >= 40, the whole of the block is executed. If the mark is < 40, the computer skips to the else and executes the "I'm afraid" line.

You will find that different programmers, and different textbooks, have different ideas about the precise placement of the curly braces. Some would set out the above fragment as:

if (exammark >= 40) {
     cout << "A satisfactory result" << endl;
     cout << "You may proceed with your project." << endl;
}
else cout << "I'm afraid you have failed." << endl;
and there are other variations. Personally I like to see the opening and closing curly braces lined up vertically. It helps the reader to see how they match up.

Exercise 2F

Extend the above program fragment so that all the candidates get two lines of output, the unsuccessful ones getting "I'm afraid you have failed," and "You may re-enter next year."

To check your answers, click on Answers to the exercises.

Suppose now that we wanted to give a different message to candidates who had done exceptionally well. Our first thought might be as follows:

if (exammark >= 70)
{    cout << "An exceptional result!" << endl;
     cout << "We expect a first-class project from you." << endl;
}
if (exammark >= 40)
{    cout << "A satisfactory result" << endl;
     cout << "You may proceed with your project." << endl;
}
else cout << "I'm afraid you have failed." << endl;
But this would not work quite right. It's OK for candidates with marks < 70, but candidates with marks >= 70 would get the following output:
An exceptional result
We expect a first-class project from you.
A satisfactory result
You may proceed with your project.
The problem is that if a mark is >= 70, it is also > 40. The first condition is true, so we get the "exceptional" part, but then the second condition is also true, so we get the "satisfactory" part. We want to proceed to the >= 40 test only if the mark is < 70. We need another else:
if (exammark >= 70)
{    cout << "An exceptional result!" << endl;
     cout << "We expect a first-class project from you." << endl;
}
else if (exammark >= 40)
{    cout << "A satisfactory result" << endl;
     cout << "You may proceed with your project." << endl;
}
else cout << "I'm afraid you have failed." << endl;

Exercise 2G

Write a program which takes two integers as input. If the first is exactly divisible by the second (such as 10 and 5 or 24 and 8, but not 10 and 3 or 24 and 7) it outputs "Yes", otherwise "No", except when the second is zero, in which case it outputs "Cannot divide by zero."

Exercise 2H

Write a program which takes an integer as its input representing the time using the 24-hour clock. 930 is 9.30 am; 2345 is 11.45 pm. Midnight is zero. The program responds with a suitable greeting for the time of day. If you want to make this a bit harder, make the program respond with a "?" if the time represented by the number is impossible, such as 2400, –5 or 1163.

To check your answers, click on Answers to the exercises.

The ASCII character set

The portion of the ASCII table dealing with printable characters is as follows. The numbers indicate the character's position in the ASCII character set; upper-case 'A', for example, is character number 65. Character number 32 is a space.
32 48 064 @80 P 96`112p
33 !49 165A81 Q 97 a113 q
34"50 266 B82R98b114r
35#51367C83S 99c115s
36$52468D84T100d116t
37%53569E85U101e117u
38&54670F86V102f118v
39'55771G87W103g119w
40(56872H88 X104h120x
41)57973I89Y105i121y
42*58:74J90Z106j122z
43+59;75K91[107k123{
44,60<76L92\108l124|
45-61=77M93]109m125}
46.62>78N94 ^110n126~
47/63 ?79O95_111o