Introduction to C++ course for the CM Hub at Imperial College
- Part 0: Setting up C++
- Part 1: Hello world! Your first steps with C++
- Part 2: Arrays, files and functions
- Part 3: Pointers, classes and preparing for real science
- define the terms source file, compiler, and executable,
- use a compiler to create and run simple codes,
- apply fundamental components of the C++ language including variables, loops, and conditionals,
- create programs designed to solve simple numerical problems,
- interpret common compiler and run-time errors and use these to help debug a program.
In short, you will
- be able to write a simple C++ program,
- be able to understand and edit more complicated C++ programs you have been given,
- feel comfortable searching online for help.
Timestamps are in the descriptions and correspond to the numbering in this document.
- Part 0: Pre-course instructions
- Part 1. You must have C++ set up on your machine before starting.
- Part 2
- Part 3
- Playlist
For some programming languages, like Matlab, there is just one program you need to open to write your code and then run it. For others, like C++, you will need one program to write your code, and then one program to compile it.
A compiler is a program which takes the text file we have written and turns it into something we can run. Compilers do not look like normal programs, with windows and graphics. Instead they are run using the command line, or terminal.
We are going to have two windows open at the same time:
- A text editor (we are going to use Atom)
- The command line or terminal, where a C++ compiler has already been installed and is working
Integrated Development Environments (IDEs) also exist, which often combine a text editor and compiler in one useful program: XCode, Code::Blocks and (to a lesser degree) Visual Studio Code are examples. In scientific computing, we typically develop on different machines to those we end up running on, so in this class we will keep the two ideas separate.
- Open a browser and navigate to Imperial College Software Hub
- Search for
atom
in the search box - The Atom text editor is one of the few search results. Just click
launch
- done! - Clear the search box and then search for
mingw
in the search box - Among the small set of search results that pop up, launch
MinGW 1.0
(the newer version plays badly with Armadillo). - You are all set!
Instructions are in the appendix.
Pros of C++:
- Free
- Fast
- Lots of support
- Lots of libraries
Cons of C++:
- Ideosyncratic
- Steep learning curve; difficult to get started
- Lacks features out of the box
- Not obvious how best to use for science
- Difficult to debug
In short: C++ is a robust, fast language whose steep learning curve makes it worthwhile using for only large maths problems.
- Create a new directory (folder) in your home drive (H:) called
cpp
. We are going to save our files in here. - On the command line:
- Change directory to the H: drive by typing
H:
(or from within the MinGW window,cd H:\
) - Change directory to your new
cpp
directory by typingcd cpp
- Change directory to the H: drive by typing
- Create a new directory (folder) in your home folder called
cpp
. We are going to save our files in here. - On the command line:
- Navigate to your home folder (possibly by typing
cd ~
) - Change directory to your new
cpp
directory by typingcd cpp
- Navigate to your home folder (possibly by typing
- Open up Atom
#include <iostream>
using namespace std;
int main()
{
cout << "Hello world!" << endl;
return 0;
}
- Save as
helloworld.cpp
(colours!) - Compile by going to the command line and typing
c++ helloworld.cpp -o hello
(or possibly g++
on your own machine)
- Then run the program. On Windows this is done with
hello
and on Mac/Linux, with
./hello
Try:
- Adding an extra line to the message
Join in:
#include <iostream>
using namespace std;
int main()
{
int x;
x = 4;
cout << "The value of x is " << x << endl;
return 0;
}
- Compile and run.
Your turn:
- Change the code so it prints 2x instead.
- Let x = 3.9. What do you expect to happen? What happens?
- What happens if you forget to add the semicolon?
Join in:
#include <iostream>
using namespace std;
int main()
{
double x;
double y;
x = 3.141;
y = 1.618;
cout << "The value of x is " << x << " and the value of y is " << y << endl;
return 0;
}
- Compile and run.
Your turn:
- Change the code so that it also prints out the product of x and y.
Join in:
- New file!
height.cpp
. Note that we're going to use strings here, which need the<string>
library.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
double height;
cout << "What is your name?" << endl;
cin >> name;
cout << "What is your height?" << endl;
cin >> height;
cout << name << " is " << height << " metres tall." << endl;
return 0;
}
- Compile and run.
Your turn:
- Convert the height into feet (1 metre = 3.28084 feet)
- Harder: Convert the height into feet and inches (1 foot = 12 inches), rounding down to an integer number of inches. For example, entering 1.81 (metres) should produce "5 feet 11 inches".
- Hint 1: If
a
andb
are integers, thena%b
= a mod b. - Hint 2: Convert to an integer number of inches first.
- Hint 1: If
- What happens if we type nonsense into the inputs?
Basic arithmetic works out of the box, as you've seen. For 'scientific calculator' stuff, we need the <cmath>
library. Libraries are like toolboxes.
Join in:
- New file!
calculator.cpp
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double x;
cout << "Enter a number" << endl;
cin >> x;
cout << "That number squared is " << pow(x,2) << endl;
cout << "The square root of that number is " << sqrt(x) << endl;
return 0;
}
Your turn:
- Add a line displaying the sine of the inputted number.
- Change the code so that it inputs two integers, a and b, and displays a/b.
- Input a as 3, and b as 2. What do you notice?
Join in:
- New file!
bartender.cpp
#include <iostream>
using namespace std;
int main()
{
int age;
cout << "Welcome to the pub." << endl;
cout << "What is your age?" << endl;
cin >> age;
if(age >= 18){
cout << "Have a pint!" << endl;
}
cout << "Goodbye!" << endl;
return 0;
}
- Compile and run!
- Let's make it more fun with
else
if(age > 18){
cout << "Have a pint!" << endl;
} else if(age == 18){
cout << "Show me your ID and then have a pint!" << endl;
} else {
cout << "I'm calling the police." << endl;
}
- Compile and run!
Your turn:
- Also input the name of the customer
- If the name of the customer does not equal your name, get the bartender to ask for money.
- Hint:
!=
is 'not equal to' in C++. - Maybe useful: in
if
statements,&&
is AND,||
is OR.
- Hint:
Join in:
- New file!
square_numbers.cpp
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n = 10;
for(int i=0; i<n; ++i){
cout << pow(i,2) << endl;
}
return 0;
}
- Compile and run!
- Reference: the difference between
++i
andi++
Try:
- Save the script as
cube_numbers.cpp
- Change the script to display the 3rd to 9th cubes.
Join in:
- Change the file: let's comment out the for loop above and instead write it as a while loop.
int i=3; // We can define and initialise a variable at the same time.
while(i<n){
cout << pow(i,3) << endl;
++i;
}
Try:
- Replace
++i
with the more verbose commandi = i+1
and convince yourself that it is equivalent. - Change the script to display the 3rd, 5th, 7th and 9th cubes (i.e. go up in 2s, not in 1s)
Try:
- The Collatz conjecture: create a new script,
collatz_conjecture.cpp
, which inputs a number n, and while n does not equal 1:- Let f = n/2 if n is even
- Let f = 3n + 1 if n is odd
- Display f
- Let n = f
To save and read files, we need to include the <fstream>
library.
Join in:
- New file!
save_to_file.cpp
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream myfile;
myfile.open ("greeting.txt");
myfile << "Hello there!" << endl;
myfile.close();
return 0;
}
Your turn:
- Create a new file,
save_to_file2.cpp
, where you print the first 10 squares to a text file calledsquare_numbers.txt
. - Run your program again. What can you say about how it writes to the text file?
- Replace
myfile.open ("square_numbers.txt");
withmyfile.open ("square_numbers.txt", ios_base::app);
to make C++ append to the end of a text file, rather than overwrite.
Join in:
- Now let's read in!
- New file!
read_from_file.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line;
ifstream myfile;
myfile.open ("greeting.txt");
while (getline(myfile,line)){
cout << line << endl;
}
myfile.close();
return 0;
}
Join in:
- Edit
square_numbers.cpp
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n = 10;
int square_numbers[10];
for(int i=0; i<n; ++i){
square_numbers[i] = pow(i,2);
}
for(int i=0; i<n; ++i){
cout << square_numbers[i] << endl;
}
return 0;
}
- Note you can't
cout
an array - We can also define arrays like this:
int main()
{
int n = 10;
int square_numbers[10];
int favourite_numbers[10] = {3, 1, -4, 1}; // Note we haven't defined them all.;
for(int i=0; i<n; ++i){
square_numbers[i] = pow(i,2);
}
for(int i=0; i<n; ++i){
cout << square_numbers[i] << endl;
}
for(int i=0; i<n; ++i){
cout << favourite_numbers[i] << endl;
}
return 0;
}
-
You can only use curly brackets like this at initialisation time.
-
We can also declare:
int favourite_numbers[] = {3,1,-4,1};
-
Multidimensional arrays work too
int magic_square[3][3] = {{4,9,2},{3,5,7},{8,1,6}};
-
Some basic functionality exists
max_favourite = *max_element(favourite_numbers,favourite_numbers+10);
Try:
- Create a new file
multiplication_table.cpp
. We are going to make it print a 10x10 multiplication table. Make it:- Set up a 10x10 array
product
. - Loop through all rows and columns, so that
product[row][col] = row * col;
- Loop through all rows and columns again,
cout
ing appropriately the elements of the table.
- Set up a 10x10 array
- Edit
read_from_file.cpp
so that it reads in a list of numbers fromnumbers.txt
(no more than 10 numbers long), puts them in an array, and then calculates the mean of those numbers.
Join in:
const int n = 10;
Writing functions allows us to do more complicated things.
Join in:
- New file!
learning_functions.cpp
#include <iostream>
using namespace std;
int sign_function(int n)
{
int sign;
if(n>0){
sign = 1;
} else if(n==0){
sign = 0;
} else {
sign = -1;
}
return sign;
}
int main()
{
int n;
n = 3;
cout << sign_function(n) << endl;
return 0;
}
- Global and local variables.
- Note: order is important. What happens if you define
sign_function
aftermain
?
Your turn:
- Add an extra function to this file,
absolute_value
, which returns the absolute value of an integer which is passed to it. - Add an extra line to the
main
function so that it also displays the absolute value of n.
Join in:
- There is a way to define functions with
main
first: it's called 'forward declaration'. - In general, this is better because it allows more flexible code.
#include <iostream>
using namespace std;
int sign_function(int n);
int main()
{
int n;
n = 3;
cout << sign_function(n) << endl;
return 0;
}
int sign_function(int n)
{
int sign;
if(n>0){
sign = 1;
} else if(n==0){
sign = 0;
} else {
sign = -1;
}
return sign;
}
- Compile and run!
- Now we're going to split our
sign_function
andabsolute_value
functions into separate files, and call them from our main file.
learning_functions.cpp
:
#include <iostream>
using namespace std;
int sign_function(int n);
int absolute_value(int n);
int main()
{
int n;
n = 3;
cout << sign_function(n) << endl;
cout << absolute_value(n) << endl;
return 0;
}
sign_function.cpp
:
#include <iostream> // not strictly necessary
using namespace std;
int sign_function(int n)
{
int sign;
if(n>0){
sign = 1;
} else if(n==0){
sign = 0;
} else {
sign = -1;
}
return sign;
}
absolute_value.cpp
:
#include <iostream> // not strictly necessary
using namespace std;
int absolute_value(int n)
{
return abs(n);
}
- And now we compile like this:
c++ sign_function.cpp absolute_value.cpp learning_functions.cpp -o sign
- All these forward declarations can be tiresome, so we can put them in a header file and
#include
it:
learning_functions.hpp
:
int sign_function(int n);
int absolute_value(int n);
learning_functions.cpp
:
#include <iostream>
#include "learning_functions.hpp" // double quotes for user-defined header files
using namespace std;
int main()
{
int n;
n = 3;
cout << sign_function(n) << endl;
cout << absolute_value(n) << endl;
return 0;
}
(sign_function.cpp
and absolute_value.cpp
unchanged)
- Compile and run, remembering to include all files in the compile command:
c++ sign_function.cpp absolute_value.cpp learning_functions.cpp -o sign
- The header file is also a good place to put constants you want to have pre-defined in all of the files in your project.
Your turn:
- Add a function
is_absolute_value_less_than_1
. Put it in its own file, add its declaration to the header file, make the main file outputis_absolute_value_less_than_1(n)
, compile, and check that it works. - Harder version: Look up the data type for
true
andfalse
in C++
- Your turn:
- Download the scripts from the debugging folder and try to run them. Can you fix them all?
- Long compilation scripts are a bit much:
c++ sign_function.cpp absolute_value.cpp learning_functions.cpp -o sign
- So let's put it in a makefile:
all:
c++ sign_function.cpp absolute_value.cpp learning_functions.cpp -o sign
- (note you need a tab at the beginning, not spaces. Might need to be careful in Atom)
- Then run
make all
Where in memory is a variable being stored?
Join in:
- New file!
pointers.cpp
:
#include <iostream>
using namespace std;
int main(){
int x = 10;
cout << "Value of x is " << x << endl;
cout << "Address of x is " << &x << endl;
return 0;
}
- The
&
sign indicates an address in memory. - A pointer is a variable whose value is the address of another variable, and is notated with a
*
#include <iostream>
using namespace std;
int main(){
int x = 10;
int *p;
p = &x;
cout << "Value of x is " << x << endl;
cout << "Address stored in p is " << p << endl;
cout << "Value of *p variable is " << *p << endl;
return 0;
}
Your turn:
- See what happens to the value of
*p
if we change the value ofx
.
Join in:
- Historically pointers were used instead of arrays.
- New file!
pointer_array.cpp
#include <iostream>
using namespace std;
int main () {
int primes[3] = {2, 3, 5};
int *p;
p = primes; // Set the pointer to point at the start of the array
for (int i = 0; i < 3; i++) {
cout << "Address of primes[" << i << "] is " << p << endl;
cout << "Value of primes[" << i << "] is " << *p << endl;
++p;
}
return 0;
}
Your turn:
- See what
*(primes + 2)
outputs.
Classes are one of the main things that separate C++ from C. Classes are ways for us to set up objects that have properties and functions which are particular to that type of object.
Join in:
- New file
rectangles.cpp
#include <iostream>
using namespace std;
class Rectangle {
public:
double width; // Width of rectangle
double height; // Height of rectangle
};
int main() {
Rectangle Rec1; // Declare Rec1 of type Rectangle
// Rec1 specification
Rec1.height = 5.0;
Rec1.width = 6.0;
double area;
// area of Rec1
area = Rec1.height * Rec1.width;
cout << "Area of Rec1: " << area << endl;
return 0;
}
Your turn:
- Add another rectangle,
Rec2
You should get something like:
#include <iostream>
using namespace std;
class Rectangle {
public:
double width; // Width of rectangle
double height; // Height of rectangle
};
int main() {
Rectangle Rec1; // Declare Rec1 of type Rectangle
Rectangle Rec2; // Declare Rec2 of type Rectangle
// Rec1 specification
Rec1.height = 5.0;
Rec1.width = 6.0;
// Rec2 specification
Rec2.height = 10.0;
Rec2.width = 12.0;
double area;
// area of Rec1
area = Rec1.height * Rec1.width;
cout << "Area of Rec1: " << area << endl;
// area of Rec2
area = Rec2.height * Rec2.width;
cout << "Area of Rec2: " << area << endl;
return 0;
}
Join in:
- Let's make area a 'member function' of the class (so we can call
Rec1.area()
, for example)
class Rectangle {
public:
double width; // Length of rectangle
double height; // Height of rectangle
double area() {return width*height;}
};
Your turn:
- Replace
area = Rec1.height * Rec1.width;
witharea = Rec1.area();
and see that it works. - Add a member function
perimeter
which returns the length of the perimeter.
Join in:
- We're going to look at another way of creating a member function. This is entirely equivalent.
- Just like how we forward declared functions earlier, we can forward declare them here.
class Rectangle {
public:
double width; // Length of rectangle
double height; // Height of rectangle
double area() {return width*height;}
void set_dimensions (double,double);
};
void Rectangle::set_dimensions (double x, double y) {
width = x;
height = y;
}
Your turn:
- Replace
Rec1.height = 5.0;
andRec1.width = 6.0;
with a call toRec1.set_dimensions
If you want to use Rectangle
in lots of files, it's annoying to define it every time.
Your turn:
- Put the class declaration and
set_dimensions
definition in a header file,rectangle.hpp
, and call it fromrectangles.cpp
Your turn:
- Create a class
complex_number
. Set up some functions for adding and multiplying them.
Armadillo is a linear algebra library for C++ which uses syntax quite similar to that used in Matlab or Python (with NumPy). Setup is different for different operating systems but the instructions are pretty good.
Here we are going to just include the library directly by downloading and linking to the library files. This doesn't take advantage of your computer's inbuilt fast linear algebra libraries, but it is enough for our purposes.
Installation
- Download the Armadillo zip file from this GitHub repository.
- Extract it to the folder
armadillo-9.870.2
in yourcpp
folder.
Join in:
- New file:
armadillo_test.cpp
:
#include <iostream>
#include <armadillo>
using namespace std;
using namespace arma;
int main()
{
mat A = randu<mat>(4,5);
mat B = randu<mat>(4,5);
cout << A*B.t() << endl;
return 0;
}
Compile:
-
(On your own machine)
c++ armadillo_test.cpp -o armadillo_test -I ~/cpp/armadillo-9.870.2/include -llapack -lblas
-
(On college machines)
c++ armadillo_test.cpp -o armadillo_test -I H:/cpp/armadillo-9.870.2/include -llapack -lblas
-
New file:
armadillo_equations.cpp
:
Let's solve the system of equations
- x + 5z = –1
- 2x + y + 6z = 0
- 3x + 4y = 1
#include <iostream>
#include <armadillo>
using namespace std;
using namespace arma;
int main()
{
mat A = mat("1 0 5; 2 1 6; 3 4 0");
mat b = mat("-1; 0; 1");
mat x;
x = solve(A,b);
cout << x << endl;
return 0;
}
Compile:
- (On your own machine)
c++ armadillo_equations.cpp -o armadillo_equations -I ~/cpp/armadillo-9.200.8/include -llapack -lblas
- (On college machines)
c++ armadillo_equations.cpp -o armadillo_equations -I H:/cpp/armadillo-9.200.8/include -llapack -lblas
We should get the solution: x = 19, y = –14, z = –4.
- Complex numbers: use
<complex>
library - Parallel processing: use OpenMP
- When compiling, use the flag
-O2
to optimise for speed a little bit. Use-O3
for more optimisation.-O0
is the default. Example:
c++ helloworld.cpp -o hello -O3
Follow the instructions below, depending on which type of machine you will use.
We are going to be writing our code in a text editor. This is a program which lets us produce plain text files. There are lots of choices available, but we recommend downloading Atom.
A compiler is a program which takes the text file we have written and turns it into something we can run. Compilers do not look like normal programs, with windows and graphics. Instead they are run using the command line. We will discuss this in class but for now, follow the instructions below, depending on which type of machine you will use.
A C++ compiler should be installed by default on macOS and most Linux distributions.
- Open Terminal.
- Type
c++
and press Enter. - If it says
clang: error: no input files
orc++: fatal error: no input files
, then you are ready to go.
First let's check that you haven't already got a C++ compiler on your computer. If you have installed Fortran in the past, you might already have a C++ compiler.
- Open Command Prompt from the Start menu (right-click the Start button and select Command Prompt).
- Type
g++
and press Enter. - If you get the error
g++: fatal error: no input files
, then you are good to go. If you get a different message, you don't have a C++ compiler installed and should continue following these instructions. - To install the compiler, follow the instructions on this YouTube video. Is this awkward? Yes. Is it worth it? Yes!
- Check that it works by following steps 1--3 above.
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Licence.