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 ofcout
andendl
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
- Short integer: 2 bytes (will be smaller than long)
- 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¶
Syntax generally follows void FunctionName(argOne, argTwo)
to define the function followed by FuntionName()
to call the function.
// Usage of void when the function does not return anything
// In this example, 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
ofushortint
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
Function Inner Workings¶
- Essentially our lines of codes translates to instruction pointers with unique memory addresses.
- Execution of instruction pointers operates on a "LIFO" basis, last in first out.
- Oversimplifying here, in our example, the last line is taken off first and it follows up
// Code Space
int varOneTest = 10; // Instruction pointer 100
std::cout << varOneTest << std::endl; // Instruction Pointer 102
10
@0x7fa6b7de5460
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¶
// In steps of 1
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
// In steps of 2
for (int i=0; i<10; i+=2)
{
// 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 2 contains 0
Element 4 contains 0
Element 6 contains 0
Element 8 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
Exponent¶
- Base to the power of something, this requires a new package called
<cmath>
that we want to include.
#include <cmath>
void SquareNumber(int baseNum, int exponentNum)
{
// Square the locally scoped variable with 2
int squaredNumber;
squaredNumber = pow(baseNum, exponentNum);
std::cout << "Base of 2 with exponent of 2 gives: " << squaredNumber << std::endl;
}
SquareNumber(2, 2)
Base of 2 with exponent of 2 gives: 4
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
Conditional Statements¶
If¶
int maxValue = 10;
// Increment till 10
for (int i=0; i<=10; i+=2)
{
// Stop if the number reaches 10 (inclusive)
if (i == maxValue)
{
cout << "Reached max value!";
cout << "\nValue is " << i << endl;
};
};
Reached max value!
Value is 10
Else¶
int newMaxValue = 20;
// Increment till 10
for (int i=0; i<=10; i+=2)
{
// Stop if the number reaches 10 (inclusive)
if (i == newMaxValue)
{
cout << "Reached max value!";
cout << "\nValue is " << i << endl;
}
// Else print current value
else
{
cout << "\nCurrent Value is " << i << endl;
}
}
Current Value is 0
Current Value is 2
Current Value is 4
Current Value is 6
Current Value is 8
Current Value is 10
Logical Operators¶
And¶
int varOneNew = 10;
int varTwo = 10;
int varCheckOne = 10;
int varCheckTwo = 5;
// This should print out
if ((varOneNew == varCheckOne) && (varTwo == varCheckOne))
{
std::cout << "Both values equal to 10!" << std::endl;
}
// This should not print out as varTwo does not equal to 5
if ((varOneNew == varCheckOne) && (varTwo == varCheckTwo))
{
std::cout << "VarOneNew equals to 10, VarTwo equals to 5" << std::endl;
}
Both values equal to 10!
Or¶
// On the contrary, this exact same statement would print out
// as VarOne is equal to 10 and we are using an OR operator
if ((varOneNew == varCheckOne) || (varTwo == varCheckTwo))
{
std::cout << "VarOneNew equals to 10 or VarTwo equals to 5" << std::endl;
}
VarOneNew equals to 10 or VarTwo equals to 5
Not¶
// This would print out as VarTwo is not equal to 5
if (varTwo != varCheckTwo)
{
std::cout << "VarTwo (10) is not equal to VarCheckTwo (5)." << std::endl;
}
VarTwo (10) is not equal to VarCheckTwo (5).
Getting User Input¶
using namespace std;
long double inputOne, inputTwo;
cout << "This program multiplies 2 given numbers\n";
cout << "Enter first number: \n";
cin >> inputOne;
cout << "Enter second number: \n";
cin >> inputTwo;
cout << "Multiplication value: " << inputOne * inputTwo << endl;
This program multiplies 2 given numbers
Enter first number:
10
Enter second number:
10
Multiplication value: 100
Loops¶
For Loop¶
for (int i=0; i<10; i+=1)
{
cout << "Value of i is: " << i << endl;
}
Value of i is: 0
Value of i is: 1
Value of i is: 2
Value of i is: 3
Value of i is: 4
Value of i is: 5
Value of i is: 6
Value of i is: 7
Value of i is: 8
Value of i is: 9
While Loop¶
int idxWhile = 0;
while (idxWhile < 10)
{
idxWhile += 1;
cout << "Value of while loop i is: " << idxWhile << endl;
}
Value of while loop i is: 1
Value of while loop i is: 2
Value of while loop i is: 3
Value of while loop i is: 4
Value of while loop i is: 5
Value of while loop i is: 6
Value of while loop i is: 7
Value of while loop i is: 8
Value of while loop i is: 9
Value of while loop i is: 10
While Loop with Continue/Break¶
int idxWhileNew = 0;
while (idxWhileNew < 100)
{
idxWhileNew += 1;
cout << "Value of while loop i is: " << idxWhile << endl;
if (idxWhileNew == 10)
{
cout << "Max value of 10 reached!" << endl;
break;
}
}
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Value of while loop i is: 10
Max value of 10 reached!