Skip to content

C++

Run Jupyter Notebook

You can run the code for this section in this jupyter notebook link.

Installation of Interactive C++17

Xeus-Cling is a game-changer where similar to Python Jupyter Notebooks, we can run C++ Jupyter Notebooks now. Run the following bash commands in sequence to create a C++ kernel for Jupyter Notebook.

conda create -n cpp
source activate cpp
conda install -c conda-forge xeus-cling
jupyter kernelspec install --user /home/ritchie/miniconda3/envs/cpp/share/jupyter/kernels/xcpp17
jupyter notebook

Printing

Printing Single Line

// When you compile, the preprocessor runs and acts on all line with the pound key first

// This is a preprocessor instruction that
// essentially places the file with the name iostream into this spot
#include <iostream>
// Print one line
std::cout << "Using Xeus Cling" << std::endl;
Using Xeus Cling

Printing 2 Lines

// Print two lines
std::cout << "First Line \nSecond Line" << std::endl;
First Line 
Second Line

Printing with Tabs

// Print numbers with nicely formatted tabs
std::cout << "One hundred:\t";
std::cout << (float) 1000/10 << std::endl;

std::cout << "Two hundred:\t";
std::cout << (double) 2000/10 << std::endl;

std::cout << "Three hundred:\t";
std::cout << (double) 3000/10 << std::endl;
One hundred:    100
Two hundred:    200
Three hundred:  300

Easier Printing (subjective) with Namespaces

  • Gets irritating to use std in front of cout and endl to keep printing so we can use namespaces
using namespace std;
cout << "No need for messy std::" << endl;
No need for messy std::

Variables

General memory management

In C++, you always need to determine each variable's type so the compiler will know how much memory (RAM) to allocate to the variable

Types of Variables

Type Bytes (Size) Range of Values
char 1 0 to 255 or -127 to 127
unsigned char 1 -127 to 127
signed char 1 0 to 255
bool 1 True or False
int 4 -2,147,483,648 to 2,147,483,647
unsigned int 4 0 to 4,294,967,295
signed int 4 -2,147,483,648 to 2,147,483,647
short int 2 -32,768 to 32,767
long int 4 -2,147,483,648 to 2,147,483,647
float 4 3.4e-38 to 3.4e38
double 8 1.7e-308 to 1.7e-08
long double 8 1.7e-308 to 1.7e-08

Integer sizes

  • Typical sizes
    • Short integer: 2 bytes (will be smaller than long)
      • Limitation is that the value of this short integer has a max value, you should be cautious of using short integers
    • Long integer: 4 bytes
    • Integer: 2 or 4 bytes
  • Notes
    • Technically these sizes can vary depending on your processor (32/64 bit) and compiler
    • You should not assume the sizes but the hierarchy of sizes will not change (short memory < long memory)

Integer size

cout << "Size of an integer: " << sizeof (int);
Size of an integer: 4

Short integer size

cout << "Size of a short integer: " << sizeof (short int);
Size of a short integer: 2

Long integer size

cout << "Size of an long integer: " << sizeof (long int);
Size of an long integer: 8

Unsigned or signed integers

  • Unsigned integers: only can hold positive integers
  • Signed integers: can hold positive/negative integers

Signed short integer

cout << "Size of an signed short integer: " << sizeof (signed short int);
Size of an signed short integer: 2

Unsigned short integer

cout << "Size of an unsigned short integer: " << sizeof (unsigned short int);
Size of an unsigned short integer: 2

Signed long integer

cout << "Size of an signed long integer: " << sizeof (signed long int);
Size of an signed long integer: 8

Unsigned long integer

cout << "Size of an unsigned long integer: " << sizeof (unsigned long int);
Size of an unsigned long integer: 8

Constants

Literal Constants

int varOne = 20;
std::cout << varOne << std::endl;
20

Enumerated Constants

This enables you to create a new type! In this example we create a new type directions containing Up, Down, Left, and Right.

enum directions {Up, Down, Left, Right};

directions goWhere;
goWhere = Right;

if (goWhere == Right)
    std::cout << "Go right" << std::endl;
Go right

Functions

Function Without Return Value

// Usage of void when the function does not return anything
// In this exmaple, this function prints out the multiplication result of two given numbers
void MultiplyTwoNumbers(int firstNum, int secondNum)
{
    // Define variable as integer type
    long int value;
    value = firstNum * secondNum;
    std::cout << value << std::endl; 
}

Multiply Two Numbers 3 and 2

MultiplyTwoNumbers(3, 2)
6

Multiply Two Numbers 6 and 2

MultiplyTwoNumbers(6, 2)
12

Aliases Function

Say we want the variable value to be of type unsigned short int such that it's 2 bytes and can hold 2x the range of values compared to just short int. We can use typedef as an alias.

Type Bytes (Size) Range of Values
short int 2 -32,768 to 32,767
unsigned short int 2 0 to 65,536
// Usage of void when the function does not return anything
// In this exmaple, this function prints out the multiplication result of two given numbers
void MultiplyTwoNumbersWithAlias(int firstNum, int secondNum)
{
    // Using an alias
    typedef unsigned short int ushortint;
    // initializing value variable with ushortint type
    ushortint value;
    value = firstNum * secondNum;
    std::cout << value << std::endl; 
}

Multiply Two Numbers 10 and 10

MultiplyTwoNumbersWithAlias(10, 10)
100

Multiply Two Numbers 1000 and 65

MultiplyTwoNumbersWithAlias(1000, 65)
65000

Multiply Two Numbers 1000 and 67

  • Notice how you don't get 67,000? This is because our variable value of ushortint type can only hold values up to the integer 65,536.
  • What this returns is the remainder of 67,000 - 65,536 = 1464
MultiplyTwoNumbersWithAlias(1000, 67)
1464
std::cout << 67 * 1000 - 65536 << std::endl;
1464

Function with Return Value

Unlike functions without return values where we use void to declare the function, here we use int to declare our function that returns values.

// In this exmaple, this function returns the value of the multiplication of two numbers
int MultiplyTwoNumbersNoPrint(int firstNum, int secondNum)
{
    // Define variable as integer type
    long int value;
    value = firstNum * secondNum;
    return value;
}

Call Function

// Declare variable with type
long int returnValue;
// Call function
returnValue = MultiplyTwoNumbersNoPrint(10, 2);
// Print variable
std::cout << returnValue << std::endl;
20

Arrays

An array contains a sequence of elements with the same data type.

Creating an Array

// This is how you declare an array of 50 elements each of type double
double DoubleArray[50];

Accessing Array's Elements

First Element
// This access the first array 
std::cout << DoubleArray[0] << std::endl;
0
Last Element
std::cout << DoubleArray[49] << std::endl;
0
First 10 Elements
for (int i=0; i<10; i++)
{
    // This is how you print a mix of characters and declared variables
    std::cout << "Element " << i << " contains " <<  DoubleArray[i] << std::endl;
}
Element 0 contains 0
Element 1 contains 0
Element 2 contains 0
Element 3 contains 0
Element 4 contains 0
Element 5 contains 0
Element 6 contains 0
Element 7 contains 0
Element 8 contains 0
Element 9 contains 0
Going Beyond The Array's Length

This will return a warning that it's past the end of the array

std::cout << DoubleArray[50] << std::endl;
input_line_36:2:15: warning: array index 50 is past the end of the array (which contains 50 elements)
      [-Warray-bounds]
 std::cout << DoubleArray[50] << std::endl;
              ^           ~~
input_line_32:3:1: note: array 'DoubleArray' declared here
double DoubleArray[50];
^
4.94066e-323

Arrays with Enumeration

enum directionsNew {up, down, left, right, individualDirections};

int directionsArray[individualDirections] = {1, 2, 3, 4};

std::cout << "Up value:\t" << directionsArray[up];
std::cout << "\nDown value:\t" << directionsArray[down];
std::cout << "\nLeft value:\t" << directionsArray[left];
std::cout << "\nRight value:\t" << directionsArray[right];
// This is the number of elements in the array
std::cout << "\nNum value:\t" << sizeof(directionsArray) / sizeof(directionsArray[0]) << std::endl;
Up value:   1
Down value: 2
Left value: 3
Right value:    4
Num value:  4

Arrays with >1 Dimension (Tensors)

Multi Dimension Array with Numbers

// This is how you declare a multi-dimensional array of 5x5 elements each of type double
double multiDimArray[5][5] = {
    {1, 2, 3, 4, 5},
    {2, 2, 3, 4, 5},
    {3, 2, 3, 4, 5},
    {4, 2, 3, 4, 5},
    {5, 2, 3, 4, 5}
};

// Print each row of our 5x5 multi-dimensional array
for (int i=0; i<5; i++)
{
    for (int j=0; j<5; j++)
    {
        std::cout << multiDimArray[i][j];
    };
    std::cout << "\n" << std::endl;
};
12345

22345

32345

42345

52345

Multi Dimension Array with Characters

// This is how you declare a multi-dimensional array of 5x5 elements each of type char
char multiDimArrayChars[5][5] = {
    {'a', 'b', 'c', 'd', 'e'},
    {'b', 'b', 'c', 'd', 'e'},
    {'c', 'b', 'c', 'd', 'e'},
    {'d', 'b', 'c', 'd', 'e'},
    {'e', 'b', 'c', 'd', 'e'},
};

// Print each row of our 5x5 multi-dimensional array
for (int i=0; i<5; i++)
{
    for (int j=0; j<5; j++)
    {
        std::cout << multiDimArrayChars[i][j];
    };
    std::cout << "\n" << std::endl;
};
abcde

bbcde

cbcde

dbcde

ebcde

Copy Arrays

Copy Number Arrays

double ArrayNumOne[] = {1, 2, 3, 4, 5};
double ArrayNumTwo[5];

// Use namespace std so it's cleaner
using namespace std;

// Copy array with copy()
copy(begin(ArrayNumOne), end(ArrayNumOne), begin(ArrayNumTwo));

// Print double type array with copy()
copy(begin(ArrayNumTwo), end(ArrayNumTwo), ostream_iterator<double>(cout, "\n"));
1
2
3
4
5

Copy String Arrays

char ArrayCharOne[] = {'a', 'b', 'c', 'd', 'e'};
char ArrayCharTwo[5];

// Use namespace std so it's cleaner
using namespace std;

// Copy array with copy()
copy(begin(ArrayCharOne), end(ArrayCharOne), begin(ArrayCharTwo));

// Print char type array with copy()
copy(begin(ArrayCharTwo), end(ArrayCharTwo), ostream_iterator<char>(cout, "\n"));
a
b
c
d
e

Mathematical Operators

  • Add, subtract, multiply, divide and modulus

Add

double addStatement = 5 + 5;
std::cout << addStatement;
10

Subtract

double subtractStatement = 5 - 5;
std::cout << subtractStatement;
0

Divide

double divideStatement = 5 / 5;
std::cout << divideStatement;
1

Multiply

double multiplyStatement = 5 * 5;
std::cout << multiplyStatement;
25

Modulus

  • Gets the remainder of the division
double modulusStatement = 8 % 5;
std::cout << modulusStatement;
3

Incrementing/Decrementing

  • 3 ways to do this, from least to most verbose

Methods

Method 1
double idx = 1;
idx++;
std::cout << idx;
2
Method 2
idx += 1;
std::cout << idx;
3
Method 3
idx = idx + 1;
std::cout << idx;
4

Prefix/Postfix

Prefix
  • This will change both incremented variable and the new variable you assign the incremented variable to
  • Summary: both variables will have the same values
// Instantiate
double a = 1;
double b = 1;

// Print original values
cout << "Old a:\t" << a << "\n";
cout << "Old b:\t" << b << "\n";

// Prefix increment
a = ++b;

// Print new values
cout << "New a:\t" << a << "\n";
cout << "New b:\t" << b << "\n";
Old a:  1
Old b:  1
New a:  2
New b:  2
Postfix
  • This will change only the incremented variable but not the variable it's assigned to
  • Summary: incremented variable will change but not the variable it was assigned to
// Instantiate
double c = 2;
double d = 2;

// Print original values
cout << "Old c:\t" << c << "\n";
cout << "Old d:\t" << d << "\n";

// Prefix increment
c = d--;

// Print new values, notice how only d decremented? c which is what d is assigned to doesn't change.
cout << "New c:\t" << c << "\n";
cout << "New d:\t" << d << "\n";
Old c:  2
Old d:  2
New c:  2
New d:  1

Comments