Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
17 views155 pages

Part 2

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views155 pages

Part 2

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 155

Learning Objectives: Array Basics

Create and initialize an array

Access and modify array elements

Iterate through arrays using both a regular for loop and


an enhanced for loop

Determine array output


Creating an Array

What Is an Array?
Before we discuss vectors, we will first learn about arrays, a simpler form
of a vector. An array is a data structure that stores a collection of data such
as ints, doubles, strings, etc. This data is often referred to as the array’s
elements. Being able to store elements into an array helps reduce the
amount of time needed to declare and initialize variables. For example, if
you wanted to store the ages of all family members in your household, you
would typically have to declare and initialize integer variables and values
for each family member. Copy the code below into the text editor on the
left and then click the TRY IT button to see the output. You can also click on
the ++Code Visualizer++ link underneath to see how the program runs
behind the scenes.

int Allan = 71;


int Bob = 42;
int Carol = 37;
int David = 5;
int Ellen = 18;

cout << Allan << endl;

Code Visualizer

challenge

What happens if you:


Change Allan in cout << Allan << endl to Bob, Carol, David, or
Ellen?

Code Visualizer

Array Creation
To avoid the repetitive task of declaring and initializing multiple variables,
you can declare an array and directly assign values or elements into that
array like below.

int ages[] = {71, 42, 37, 5, 18};

Code Visualizer

Method Syntax with Elements:

Specify the data type that the array will store (i.e. int).
Declare the variable name for the array (i.e. ages) followed by empty
brackets [] followed by the assignment symbol =.
Elements assigned to the array are separated by commas , and enclosed
within curly braces {}.

Additional information
If you used the Code Visualizer, you’ll notice that the array variable ages
refers to all of the elements as a collection. An array is considered to be a
collection that bundles all of the data that it holds.

Note that the first


array slot, or index, is always 0 so 71 is located at index 0 instead of 1.

Alternatively, you can create an array without any elements in which you
will need to declare and specify the array variable name and size before
you can assign elements to the array.

int ages[5];

Method Syntax without Elements

Specify the data type that the array will store (i.e. int).
Declare the variable name for the array (i.e. ages) followed by the
number of elements you want the array to hold within brackets (i.e.
[5]).
Additional information
Note that when you declare an array without initializing any elements, the
system will still reserve enough memory for the array to hold the specified
number of elements. This means that you can initialize elements within the
array later on.

Array Details
If an element within an array has not been initialized yet, printing it will
cause the system to output random memory data. Random memory data
is often generated when array elements are not initialized.

int ages[5];
cout << ages[0] << endl;

Note that ages[0] in the example above refers the element at index 0, also
known as the first position within the array. Currently, the element at the
first position is not initialized so printing the first element will only output
random memory data. In fact, the same will happen if you try to print any
other elements within the array. Additionally, all elements within the array
must be of the same type. If you try to store a string within an integer array,
or a double within a boolean array, you will get an error message.

int ages[] = {71, 42, 37, 5, "eighteen"};

cout << ages[4] << endl;

challenge

What happens if you:


Change "eighteen" in the code above to the integer 18?
Replace all your code with just int ages[];
important

IMPORTANT
When you create an array in C++, you must specify the number of
elements that you expect the array to hold. Otherwise, you will get an
error.

P.O. Boxes at the postal office are symbolically similar to arrays. Each row
of P.O. Boxes is like an array, except each box can only store one item
(element) and each item within that row must be of the same type
(i.e. integers).

.guides/img/ArrayElementsIndices
Accessing an Array

Array Access
To access and print array elements, you need to know their position. The
position at which an element is stored is called its index. For example,
names[0] refers to the first element in the array called names. Array indices
always start at 0 and increment by 1 with each element that comes next.
Due to this, numbers[4] refers to the fifth element in the array, not the
fourth.

string names[] = {"Alan", "Bob", "Carol", "David", "Ellen"};

cout << names[0] << endl;

challenge

What happens if you:


Change names[0] in the code above to names[2]?
Change names[0] in the code above to names[3]?
Change names[0] in the code above to names?

important

IMPORTANT
You may have noticed that printing the names array without specifying
an index resulted in an output that included a mixture of numbers and
letters. This occurs because printing an array actually prints its
memory location, not its elements. You’ll learn how to print all
elements in an array without having to specify all of their indices on a
later page.

Array Key Points


bool bools[] = {true, false, true};
double decimals[] = {2.3, 4};
int integers[1];

cout << bools[0] << endl;

challenge

What happens if you:


Change bools[0] in the original code to bools[1]?
Hint
The system will print 0 because bools[1] refers to the second
element in the bools array. Remember that 0 is the integer
equivalent to false and 1 is the integer equivalent to true. To print
their respective boolean equivalent, use cout << boolalpha <<
bools[1] << endl; instead.
Change bools[0] in the original code to decimals[1]?
Hint
The system will print 4 because decimals[1] refers to the second
element in the decimals array.
Change bools[0] in the original code to integers[1]?
Hint
The system will print random memory data because integers[1] is
not valid within the integers array. Currently there is only one
element at the first index which has not been formally initialized
yet.
Change int integers[1]; in the original code to int integers[1] =
{1.2}; and cout << bools[0] << endl; to cout << integers[0] <<
endl;?
Hint
The system will return an error message. Though you have tried to
initialize the first element within the integers array to 1.2, the
system will not allow you to put a double element into an integer
array. However, it is possible to put an integer element into a
double array because integers can be expressed as doubles but not
vice versa.
important

IMPORTANT
Here are some key points to keep in mind when working with arrays:

When you declare an array, you must specify the number of


elements you wish the array to hold before you can initialize any
elements. One exception is if you declare and initialize the array
and elements at the same time. Doing so means you do not need to
specify the number of elements in brackets [] since the system will
determine that based on the number of elements you have
initialized.

If you do not initialize any elements, printing the elements will only
result in random memory data.

If you try to access an element position that is not valid (i.e. the
second element in the integers array), the system will also output
random memory data.

Elements must be of the same type as the array. The only exception
is that integers can be expressed as doubles and can therefore be
put into a double array.

.guides/img/ArrayExceptions
Modifying an Array

Array Modification
To modify an element within an array, simply find the index at which that
element is stored and assign a new value to it.

int grades[] = {85, 95, 48, 100, 92};


cout << grades[2] << endl;

grades[2] = 88; //88 will replace 48 at index 2


cout << grades[2] << endl;

Code Visualizer

challenge

What happens if you:


Change int grades[] = {85, 95, 48, 100, 92}; in the code above
to int grades[5];?
Copy the original code but change all cout << grades[2] << endl;
to cout << grades[3] << endl;?
Change grades[2] = 88; in your current code to grades[3] = 100;?

Code Visualizer

Modifying Multiple Arrays


You can create and modify as many arrays as you’d like. For example, you
can create an array to store your family members and another array to
store their age.
string family[] = {"Dad", "Mom", "Brother", "Sister"};
int age[4];

cout << family[0] << " " << age[0] << endl;
cout << family[1] << " " << age[1] << endl;
cout << family[2] << " " << age[2] << endl;
cout << family[3] << " " << age[3] << endl;

Code Visualizer

challenge

What happens if you:


Add age[0] = 50; directly below the line int age[4];?
Add age[1] = 45; below the line int age[4]; but before the cout
statements?
Add age[2] = 25; below the line int age[4]; but before the cout
statements?
Add age[3] = 20; below the line int age[4]; but before the cout
statements?
Change "Sister" within the string array to "Brother2"?

Code Visualizer

important

IMPORTANT
Since the integer array above was created without any initialization,
random memory data were populated as elements within the array at
first. Then by setting the array indices to specific values, you were able
to modify the array to include the appropriate age for each family
member.
Iterating an Array

Array Iteration
Though we can add many elements to our array, printing each of them can
get quite tedious. For example, if we have 10 names of friends in our array,
we would need to specify each of their array index to print them.

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

cout << friends[0] << endl;


cout << friends[1] << endl;
cout << friends[2] << endl;
cout << friends[3] << endl;
cout << friends[4] << endl;
cout << friends[5] << endl;
cout << friends[6] << endl;
cout << friends[7] << endl;
cout << friends[8] << endl;
cout << friends[9] << endl;

Luckily, we can use loops which we had learned previously to help us with
this process. To print out all of our friends’ names without repeating the
print statement ten times, we can use a for loop to iterate 10 times.

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

for (int i = 0; i < 10; i++) {


cout << friends[i] << endl;
}
challenge

What happens if you:


Change cout << friends[i] << endl; in the code above to cout <<
friends[0] << endl;?
Change the cout statement to cout << friends[10] << endl;?

important

IMPORTANT
Did you notice that the print statement above includes i as the index
for friends? We do this because i will take on the values specified by
the for loop. The loop starts at 0 and increments by 1 until it reaches 9
(not including 10). Thus, friends[0] will print, then friends[1], so on
and so forth until friends[9] is printed. Then the loop ends.

Array Size
To make the iteration process easier, we can use the sizeof() operator to
determine how many elements are in our array. To use sizeof(), just call it
by using the keyword sizeof followed by the array name within
parentheses ().

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

cout << sizeof(friends) << endl;

Why Does sizeof(friends) output 320?

Unfortunately, the sizeof() operator does not determine the number of the
elements within an array. Instead, sizeof() calculates the size of the array
in bytes. In C++, a string takes up 32 bytes and since there are 10 string
elements in the array, the size of the array in bytes is 320.

To calculate the number of elements within an array, we will need to use


sizeof() twice.
string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",
"Fred", "Grace", "Henry", "Ian", "Jen"};

cout << sizeof(friends) / sizeof(friends[0]) << endl;

sizeof(friends) calculates the array’s size in bytes and sizeof(friends[0])


calculates the first element’s size in bytes. By dividing the array size by the
element’s size, we were able to determine the number of elements that
exist within the array. Note that it doesn’t matter whether we calculate the
first element’s size or the second’s since all of the elements are of the same
size (32 bytes each).

Looping Through the Elements


Now that you can determine number of elements within an array, you can
loop through the array to output each element individually.

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

for (int i = 0; i < sizeof(friends) / sizeof(friends[0]); i++) {


cout << friends[i] << endl;
}

challenge

What happens if you:


add "Kate" as an element to the array right after "Jen"?
remove "Alan" and "Bob" from the array?

Notice how sizeof(friends) / sizeof(friends[0]) continues to keep track


of how many elements are in our array even though we’ve made several
changes.
Enhanced For Loop

Using an Enhanced For-Loop


There is a special type of for loop that can be used with arrays called an
enhanced for loop. An enhanced for loop, also known as a range-based
for loop, can be used to iterate through array elements without having to
refer to any array indices. To use an enhanced for loop, you need the
following:
* The keyword for followed by parentheses ().
* A typed iterating variable followed by colon : followed by the array
name.
* Note that the iterating variable must be of the same type as the array.
* Any commands that repeat within curly braces {}.
* Note that when using an enhanced for loop, you can print the iterating
variable itself without using brackets [].

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

for (string i : friends) {


cout << i << endl;
}

challenge

What happens if you:


change cout << i << endl; in the code above to cout <<
friends[i] << endl;?
copy the original code but change string i to int i?
important

IMPORTANT
One of the main differences between a regular for loop and an
enhanced for loop is that an enhanced for loop does not refer to any
index or position of the elements in the array. Thus, if you need to
access or modify array elements, you cannot use an enhanced for
loop. In addition, you cannot use an enhanced for loop to iterate
through a part of the array. Think of an enhanced for loop as an all-or-
nothing loop that just prints all of the array elements or nothing at all.
Also note that the iterating variable type must match the array type.
For example, you cannot use for (int i : friends) since friends is a
string array and i is an integer variable. Use for (string i : friends)
instead.
Helpful Array Algorithms

Array Algorithms
In addition to being used with loops, arrays can also be used with
conditionals to help with tasks such as searching for a particular element,
finding a minimum or maximum element, or printing elements in reverse
order.

Searching for a Particular Element

string cars[] = {"Corolla", "Camry", "Prius", "RAV4",


"Highlander"};
string Camry = "A Camry is not available."; //default string
value

for (string s : cars) { //enhanced for loop


if (s == "Camry") { //if "Camry" is in array
Camry = "A Camry is available."; //variable changes if
"Camry" exists
}
}

cout << Camry << endl; //print whether Camry exists or not

challenge

What happens if you:


delete "Camry" from the cars array?
try to modify the code above so that the algorithm will look for
Prius in the array and will print A Prius is available. if Prius is
an element and A Prius is not available. if it is not an element.

Sample Solution
string cars[] = {"Corolla", "Camry", "Prius", "RAV4",
"Highlander"};
string Prius = "A Prius is not available.";

for (string s : cars) {


if (s == "Prius") {
Prius = "A Prius is available.";
}
}

cout << Prius << endl;

Finding a Minimum or Maximum Value

int grades[] = {72, 84, 63, 55, 98};


int min = grades[0]; //set min to the first element in the array

for (int i : grades) { //enhanced for loop


if (i < min) { //if element is less than min
min = i; //set min to element that is less
}
}
//elements are not modified so enhanced for loop can be used

cout << "The lowest grade is " << min << endl; //print lowest
element

challenge

What happens if you:


replace 72 in the int array with 42?
try to modify the code so that the algorithm will look for the
maximum element instead?

Sample Solution
int grades[] = {72, 84, 63, 55, 98};
int max = grades[0];

for (int i : grades) {


if (i > max) {
max = i;
}
}

cout << "The highest grade is " << max << endl;

Printing Elements in Reverse Order

string letters[] = {"A", "B", "C", "D", "E"};


int elements = sizeof(letters) / sizeof(letters[0]); //number of
elements

//start at index 4, then decrement by 1 until i < 0, then stop


for (int i = elements - 1; i >= 0; i--) {
cout << letters[i] << endl;
}

//regular for loop needed to access each element index


Learning Objectives: Vector Basics

Create an empty vector

Add and remove vector elements

Modify vector elements

Iterate through vector using both a regular for loop and


an enhanced for loop

Determine vector output

Determine key differences between vectors and arrays


Creating a Vector

What Is a Vector?
Although arrays are very useful for data collection, they are considered
static, meaning once they are created, you cannot add or remove elements
from them without changing the way they are initialized. Vectors, on the
other hand, are dynamic, meaning you can make changes to them while
the program is running. Vectors are particularly helpful when you don’t
know how large your collection of elements will become. Since vectors are
dynamic, you can add and remove elements later on if needed. In order to
use vectors, you must include #include <vector> in the header of your
program. For convenience, the program file to your left already contains
the included statement.

Vector Creation
To create a vector, you need to include the following:
* The keyword vector followed by the data type in angle brackets <>.
* A variable name that refers to the vector.
* The number of elements the vector can hold within parentheses ().

vector<int> numbers(3);

cout << numbers << endl;

important

IMPORTANT
When you try to print an array reference variable, you will get the
array’s memory address. However, this is not the case for vectors.

To print an element within the vector, use the at() function and specify the
index of the position of the element you wish to print within the
parentheses.
vector<int> numbers(3);

cout << numbers.at(0) << endl;

Similar to arrays, the first index or position of the vector also starts at index
0. Thus, numbers.at(0) refers to the element at the first position in the
vector, which currently does not contain any initialized elements. When a
vector is declared without any initialized elements, the system will
populate the vector with 0 as elements by default. This is common across
vectors of many data types except strings. Additionally, if you try to output
an element at an index that does not exist, you will get an out_of_range
error message.

vector<int> numbers(3);

cout << numbers.at(3) << endl;


//index 3 refers to the fourth element, not third, which doesn't
exist

Determining Vector Size


Vectors use the function size() to determine the number of elements that
exist instead of the operator sizeof() which is used for arrays. Note their
slight difference in syntax and usage.

vector<int> numbers(3);
int digits[3];

cout << numbers.size() << endl;


cout << sizeof(digits) / sizeof(digits[0]) << endl;

challenge

What happens if you:


remove 3 within vector<int> numbers(3);?
remove 3 within int digits[3];?
important

IMPORTANT
In both arrays and vectors, you must specify how many elements you
expect them to hold. Otherwise, you will not be able to determine their
size. However, if you initialize the array or vector upon declaration,
then you don’t have to specify the number of elements since the system
can determine that automatically.
Adding and Removing Elements

Adding Vector Elements


To add elements to the vector, simply use the push_back() function. The
push_back() function will add whatever element that is specified inside
parentheses () to the end of the vector. If an element is added to an empty
vector such as vector<int> numbers(0), that element will be the first and
only element in the vector.

vector<int> numbers(0); //vector with no elements


numbers.push_back(50); //add 50 as an element to end of vector

cout << numbers.at(0) << endl; //50 becomes first and only
element

Note that the push_back() function does not replace elements.

vector<int> numbers(2); //vector with 2 uninitialized elements


numbers.push_back(50); //add 50 as an element to end of vector

cout << numbers.at(0) << endl; //first uninitialized element


cout << numbers.at(1) << endl; //second uninitialized element
cout << numbers.at(2) << endl; //50 is the third element now

challenge

What happens if you:


change numbers.push_back(50); in original code to
numbers.push_back(true);?
change numbers.push_back(50); in original code to
numbers.push_back(50.99);?
change numbers.push_back(50); in original code to
numbers.push_back("50.99");? Note: “50.99”
important

IMPORTANT
Arrays are strict when it comes to data type compatibility, however,
vectors are more flexible. Between the four common data types, string
is the only type that cannot be associated with the other three in a
vector. Integers, doubles, and booleans are all compatible with each
other. Remember, in C++, true is 1 and false is 0.

In addition, when doubles are converted into integers, their decimal


value get eliminated. This is why pushing 50.99 into an int vector
causes it to turn into 50 without the decimal value.

To add an element to a specific index in the vector, you can use the
insert() along with the begin() functions like below.

vector<int> numbers(2);
numbers.insert(numbers.begin()+1, 50); //add 50 to index 1
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl;
cout << numbers.at(2) << endl;

numbers.insert(numbers.begin()+1, 100); //add 100 to index 1


cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl;
cout << numbers.at(2) << endl; //50 now becomes index 2

challenge

What happens if you:


change numbers.insert(numbers.begin()+1, 50); in the original
code to numbers.insert(numbers.begin()+2, 50);?
change numbers.insert(numbers.begin()+1, 100); in the original
code to numbers.insert(numbers.begin(), 100);?
important

IMPORTANT
The begin() function always refer to the first position in the vector,
which is also the 0th index. If you want to refer to the 1st index, use
begin()+1. For the 2nd index, use begin()+2, so on and so forth.

Removing Vector Elements


To remove an element from the end of a vector, use the pop_back(). Note
that using pop_back will remove the element and its index, thus decreasing
the size of the vector by 1.

vector<int> numbers(0); //empty vector


numbers.push_back(50); //add 50 to vector
numbers.push_back(100); //add 100 to vector
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl << endl;

numbers.pop_back(); //remove last element vector


cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl; //100 has been deleted completely

challenge

What happens if you:


remove cout << numbers.at(1) << endl; from the original code?

To remove an element from a specific index in the vector, use the erase()
function and specify the index you want to erase with begin(). When an
element and its index is removed from the vector, all of the elements to its
right will be moved one place to the left.
vector<int> numbers(0); //empty vector
numbers.push_back(50); //add 50 to vector
numbers.push_back(100); //add 100 to vector
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl << endl;

numbers.erase(numbers.begin()); //removes 50
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl; //no longer exists

challenge

What happens if you:


remove cout << numbers.at(1) << endl; from the original code?
change numbers.erase(numbers.begin()); from the original code to
numbers.erase(numbers.begin()+1);?
Modifying Elements

Modifying Vector Elements


To modify vector elements, use the at() method to specify the index
number and then assign a new element to it.

vector<string> contact(0);
contact.push_back("First name");
contact.push_back("Last name");
contact.push_back("Phone number");
cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

contact.at(2) = "Email"; //change element at index 2 to "Email"


cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

challenge

What happens if you:


add contact.at(1) = "Nick name"; to the line directly before
contact.at(2) = "Email";?

Initializing Vector Elements


It is possible to initialize elements inside a vector without constantly using
push_back(). The following code will produce the same result as the
original code above.
vector<string> contact{"First name", "Last name", "Phone
number"};
cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

contact.at(2) = "Email"; //change element at index 2 to "Email"


cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

When initializing elements within a vector, you do not specify the number
of elements in parentheses. The system will automatically know how many
elements are being added to the vector. The initialized elements should be
in curly braces {} and separated by commas ,.
Iterating a Vector

Iterating Vector Elements


Iterating through a vector is very similar to iterating through an array. The
main difference is that in a vector, we use at() to access the elements
instead of brackets []. Both of the code blocks below use a regular for to
produce the exact same results. The first code block contains an array and
the second contains a vector.

//iterating through an array


int grades[] = {85, 95, 48, 100, 92};

for (int i = 0; i < sizeof(grades)/sizeof(grades[0]); i++) {


cout << grades[i] << endl;
}

//iterating through an vector


vector<int> grades{85, 95, 48, 100, 92};

for (int i = 0; i < grades.size(); i++) {


cout << grades.at(i) << endl;
}

Enhanced For Loop in Vector


We can also use an enhanced for loop, or range-based for loop, to iterate
through a vector.

//iterating a vector with Enhanced For Loop


vector<int> grades{85, 95, 48, 100, 92};

for (auto i : grades) { //can use int or auto for iterating


variable!
cout << i << endl;
}
important

IMPORTANT
When using an enhanced for loop for a vector, you must label the
iterating variable accordingly. If your elements are of type int then
your iterating variable must also be int. If the elements are strings
then your variable must be typed as string. However, you can always
use auto to force the variable to match your element type.
Vector vs. Array

Vector vs. Array


Which one is better: vector or array? The answer is, it really depends. If you
know how many elements you need in your collection and you don’t intend
on changing the order of those elements, then it is better to use an array.
On the other hand, if you don’t know how many elements you need and
want to modify the order of elements later on, then it is better to use a
vector.

Although an array is shorter to write and arguably easier to use, it is static,


meaning it is not possible to add additional elements to the array after it
has already been initialized. In contrast, a vector is more dyanamic,
meaning you can add, remove, and reorganize elements as needed later on.

Here is a table showing the differences between vectors and arrays. Note
that type stands for data type. Also note that var stands for vector or array
name, num stands for an integer number, index stands for index or position
number, and element stands for a vector or array element.

Method/Types Vector Array


vector<type> var(num) or type var[num] or type
Create vector<type> var{element, var[] = {element,
element…} element…}

Find number of
var.size() sizeof(var)/sizeof(var[0])
elements
Access an
var.at(index) var[index]
element
Modify an
var.at(index) = element var[index] = element
element
var.push_back(element) or
Add an element var.insert(var.begin()+index, n/a
element)

Remove an var.pop_back() or
n/a
element var.erase(var.begin()+index)

for (int i = 0; i <


for (int i = 0; i < var.size();
for loop sizeof(var)/sizeof(var[0]);
i++) {cout << var.at(i);}
i++) {cout << var[i];}
Enhanced for for (type i : var) {cout <<
for (type i : var) {cout << i}
loop i}
Common integer, double, boolean, int, double, boolean,
compatible strings strings
types

Using Both a Vector and Array


Vectors and arrays can be used in tandem with each other. For example,
the following code keeps track of the top five students in a class.

string top[] = {"First: ", "Second: ", "Third: ", "Fourth: ",
"Fifth: "};
vector<string> names(0);

names.push_back("Alan");
names.push_back("Bob");
names.push_back("Carol");
names.push_back("David");
names.push_back("Ellen");

for (int i = 0; i < 5; i++) {


cout << top[i] << names.at(i) << endl;
}

challenge

Without deleting any existing code, try to:


switch Alan and Carol’s places.
replace David with Fred.
make Grace get “Fifth” place and remove Ellen from the list.

Sample Solution
string top[] = {"First: ", "Second: ", "Third: ", "Fourth: ",
"Fifth: "};
vector<string> names(0);

names.push_back("Alan");
names.push_back("Bob");
names.push_back("Carol");
names.push_back("David");
names.push_back("Ellen");

names.at(0) = "Carol"; //switch Alan with Carol


names.at(2) = "Alan"; //and vice versa

names.at(3) = "Fred"; //Fred replaces David

names.insert(names.begin()+4, "Grace"); //Grace takes Ellen's


place
names.pop_back(); //Ellen's "Sixth" place gets removed

for (int i = 0; i < 5; i++) {


cout << top[i] << names.at(i) << endl;
}
Helpful Vector Algorithms

Vector Algorithms
Like arrays, vectors can be used to search for a particular element and to
find a minimum or maximum element. Additionally, vectors can reverse
the order of elements rather than just simply printing the elements in
reverse order.

Searching for a Particular Element

vector<string> cars(0);
string Camry = "A Camry is not available."; //default string
value

cars.push_back("Corolla");
cars.push_back("Camry");
cars.push_back("Prius");
cars.push_back("RAV4");
cars.push_back("Highlander");

for (auto a : cars) { //enhanced for loop


if (a == "Camry") { //if "Camry" is in vector
Camry = "A Camry is available."; //variable changes if
"Camry" exists
}
}

cout << Camry << endl; //print whether Camry exists or not

challenge

What happens if you:


add cars.erase(cars.begin()+1); to the line directly below
cars.push_back("Highlander");?
try to modify the code above so that the algorithm will look for
Prius in the array and will print A Prius is available. if Prius is
an element and A Prius is not available. if it is not an element.
Sample Solution

vector<string> cars(0);
string Prius = "A Prius is not available.";

cars.push_back("Corolla");
cars.push_back("Camry");
cars.push_back("Prius");
cars.push_back("RAV4");
cars.push_back("Highlander");

for (auto a : cars) {


if (a == "Prius") {
Prius = "A Prius is available.";
}
}

cout << Prius << endl;

Finding a Minimum or Maximum Value

vector<int> grades(0);
grades.push_back(72);
grades.push_back(84);
grades.push_back(63);
grades.push_back(55);
grades.push_back(98);

int min = grades.at(0); //set min to the first element in the


array

for (auto a : grades) { //enhanced for loop


if (a < min) { //if element is less than min
min = a; //set min to element that is less
}
}
//elements are not modified so enhanced for loop can be used

cout << "The lowest grade is " << min << endl; //print lowest
element
challenge

What happens if you:


add grades.at(0) = 42; to the line directly below
grades.push_back(98);?
try to modify the code so that the algorithm will look for the
maximum element instead?

Sample Solution

vector<int> grades(0);
grades.push_back(72);
grades.push_back(84);
grades.push_back(63);
grades.push_back(55);
grades.push_back(98);

int max = grades.at(0);

for (auto a : grades) {


if (a > max) {
max = a;
}
}

cout << "The highest grade is " << max << endl;

Reversing the Order of Elements


vector<string> letters(0);
letters.push_back("A");
letters.push_back("B");
letters.push_back("C");
letters.push_back("D");
letters.push_back("E");

int original = letters.size(); //original size

//regular for loops needed to access element indices

for (int i = letters.size() - 1; i >= 0; i--) {


letters.push_back(letters.at(i));
} //add elements in reverse order to the vector

for (int j = 0; j < original; j++) {


letters.erase(letters.begin());
} //remove all the original elements

//enhanced for loop can be used for just printing


for (auto a : letters) {
cout << a << " "; //print all new vector elements
}

important

IMPORTANT
Note that we used letters.erase(letters.begin()) which causes the
system to delete both the element and the index. Thus, the next
element in the vector becomes the new 0th index which we want to
continue to delete.
Learning Objectives: 2D Arrays

Create and initialize a 2D array

Access and modify 2D array elements

Iterate through 2D arrays using both a regular for loop


and an enhanced for loop

Determine 2D array output


Creating a 2D Array

An Array Inside Another Array


An array inside another array is called a 2D array. A 2D arrays is symbolic
of a table where there are rows and columns. The first index number
represents the row position and the second index number represents the
column position. Together, the row and column indices enable elements to
be stored at specific locations.

.guides/img/2DArray

string names[3][5];

2D Array Syntax

Array type followed by a name for the 2D array followed by two empty
pairs of brackets [][].
The number of rows goes inside the first pair of brackets and the
number of columns goes inside the second pair of brackets.

Why Array Inside Array?


The way 2D arrays store elements is a little unique. Rather than creating an
actual table like shown above, each initial row of the 2D array actually
refers to another column array. This is why a 2D array is considered to be
an array inside of another array.
.guides/img/2DArrayReference

To determine the number of rows and columns in the 2D array, we can use
the sizeof() operator like we did for arrays.

string names[3][5];

cout << sizeof(names) / sizeof(names[0]) << " rows" << endl;


cout << sizeof(names[0]) / sizeof(string) << " columns" << endl;

important

IMPORTANT
Note that when determining column length, you must refer to the 2D
array’s 0th row index. For example, names[0] doesn’t just refer to the
first element in the row, it also refers to the entire column of elements.
See image above.

sizeof(names[0]) calculates the size of the entire column while


sizeof(string) calculates the size of one string. Thus, dividing the two,
sizeof(names[0]) / sizeof(string), will calculate how many string
elements there are.
Accessing and Modifying a 2D
Array

2D Array Access
To access and modify elements inside a 2D array, you need to specify the
row and column indices at which the elements are located. For example
names[1][2] refers to the element that’s at row index 1 and column index 2.

.guides/img/2DArray

Below is a code block showcasing a 2D array that contains fifteen P.O. Box
names from a postal office. Note that you can initialize the elements inside
your 2D array just like how you initialize elements inside a regular array.
Each column array is separated by curly braces {} as well as a comma ,.

string names[ ][5] = { {"Alan", "Bob", "Carol", "David",


"Ellen"},
{"Fred", "Grace", "Henry", "Ian", "Jen"},
{"Kelly", "Liam", "Mary", "Nancy",
"Owen"} };

cout << names[1][2] << endl;


challenge

What happens if you:


change names[1][2] from the original code to names[2][1]?
change names[1][2] from the original code to names[3][0]?

important

IMPORTANT
Note that you must declare the number of elements within the column
brackets. You can leave the row brackets empty, but you cannot leave
the column brackets empty. Also, when you try to print an element that
is outside of the row/column range, the system will either print
random memory data or nothing at all.

2D Array Modification
To modify elements within a 2D array, simply access the element and
assign another element to it.

string names[3][5] = { {"Alan", "Bob", "Carol", "David",


"Ellen"},
{"Fred", "Grace", "Henry", "Ian", "Jen"},
{"Kelly", "Liam", "Mary", "Nancy",
"Owen"} };

cout << names[1][2] << endl;

names[1][2] = "Harry";
cout << names[1][2] << endl;

challenge

What happens if you:


change all names[1][2] within the code above to names[0][0]?
change "Harry" within your current code to "Amy"?
Iterating a 2D Array

2D Array Iteration
To iterate through a 2D array, we can use two for loops, one nested inside
another. The outer for loop is for the rows while the inner for is for the
columns.

int digits[3][3] = { {1, 2, 3},


{4, 5, 6},
{7, 8, 9} };

int row = sizeof(digits) / sizeof(digits[0]); //number of rows


int col = sizeof(digits[0]) / sizeof(int); // number of columns

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
cout << digits[i][j] << endl;
}
}

Code Visualizer

challenge

What happens if you:


change all sizeof(digits[0]) from the code above to
sizeof(digits[1])?
remove << endl from the code?

Code Visualizer

Note that all of the columns’ lengths are the same, there are 3 columns for
each row. Therefore, it doesn’t matter if we use digits[0], digits[1], or
digits[2] when calculating the number of elements in each row and
column. Also note that using << endl prints the elements vertically while
removing it prints the elements horizontally. To print the elements so that
the columns stay together but the rows separate, we can try something like
this:
int digits[3][3] = { {1, 2, 3},
{4, 5, 6},
{7, 8, 9} };

int row = sizeof(digits) / sizeof(digits[0]);


int col = sizeof(digits[0]) / sizeof(int);

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
if (j == col - 1) {
cout << digits[i][j] << endl;
}
else {
cout << digits[i][j] << " ";
}
}
}

Code Visualizer

The if conditional forces the elements to be printed with a newline every


time the iterating variable reaches the end of the column index. Otherwise,
the elements will be printed with a space instead.

2D Array with Enhanced For Loop


Like arrays and vectors, 2D arrays can also make use of the enhanced for
loop.

int digits[3][3] = { {1, 2, 3},


{4, 5, 6},
{7, 8, 9} };

for (auto &i : digits) {


for (int j : i) {
if ((j == 3) | (j == 6) | (j == 9)) {
cout << j << endl;
}
else {
cout << j << " ";
}
}
}

Code Visualizer
You may have noticed that the outer loop contains for (auto &i : digits).
Unlike a regular array where we can access the first element by locating
just one index, we need two indices in order to access elements within a 2D
array. The &i creates a reference iterating variable that can refer to the 2D
array. We type it as auto because doing so will cause the system to force the
variable to match the 2D array type. In fact, we can always use auto to type
variables to cause them to match the data that they refer to. For example,
we can use for (auto j : i) for the inner loop instead of using int.

Also note that we cannot use an enhanced for loop to manipulate array
indices. Our iterating variable goes through the 2D array and takes on each
element value rather than each element index. This is why we have the
conditional statement if ((j == 3) | (j == 6) | (j == 9)) rather than
if (j == col - 1).
Lab: Arrays

Tutorial Lab 1: Using an Array


An array is a data structure that groups data together into a collection of
elements. Each element has its own index or position within the array.
These elements can be initialized, accessed, modified, and printed. Copy the
code below into the text editor on the left. Then click on the TRY IT button
to see the resulting output.

string classes[] = {"Math", "English", "Science", "Social


Studies", "Spanish"};

classes[4] = "French";

for (int i = 0; i < sizeof(classes)/sizeof(classes[0]); i++) {


cout << classes[i] << endl;
}

Program Summary

1. An array called classes is created and initialized with elements


(i.e. "Math", "English", etc.).
2. At index 4, "Spanish" is modified and replaced with "French". Keep in
mind that array indices start at 0, not 1.
3. A for loop iterates through the elements in the array. It starts at index 0,
ends right before index 5, and increments by 1 after each iteration.
4. Each element from index 0 through index 4 gets printed with a newline.
Lab: Vectors

Tutorial Lab 2: Using a Vector


A vector is another data structure that has many of the same functionalities
as an array. However, they are more flexible in the functions that they are
able to use. These functions include adding and removing elements within
the vector, meaning vectors can dynamically change their size, something
arrays cannot do. Copy the code below into the text editor on the left. Then
click on the TRY IT button to see the resulting output.

vector<string> veggies(0);
veggies.push_back("carrot");
veggies.push_back("tomato");
veggies.push_back("celery");
veggies.push_back("spinach");

veggies.erase(veggies.begin()+1);
veggies.at(1) = "potato";

for (auto a : veggies) {


cout << a << endl;
}

Program Summary

1. A vector called veggies is created.


2. carrot, tomato, celery, and spinach are added to the vector as elements.
3. The element at index 1 (tomato) is removed.
4. The element potato replaces the element at index 1, which is currently
celery since tomato was deleted previously.
5. An enhanced for loop is used which creates an iterating variable a
(typed auto) to take on the value of each element.
6. Each element a is then printed with a newline.
Lab: 2D Arrays

Tutorial Lab 3: Using a 2D Array


A 2D array is an array inside another array. This data structure can be
visually compared to a table where there are rows and columns and each
element exists inside each “cell.” To access or modify elements, both the
row index and column index are needed. Like arrays, 2D arrays are static
so elements cannot be added or removed after initialization.

int coordinates[5][2] = { {-4, 3},


{2, 1},
{0, -8},
{-11, 9},
{-5, -7} };

int row = sizeof(coordinates) / sizeof(coordinates[0]);


int col = sizeof(coordinates[0]) / sizeof(int);

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
if (j == 1) {
cout << coordinates[i][j] << endl;
}
else {
cout << coordinates[i][j] << " ";
}
}
}

Code Visualizer
Lab Challenge: 2D Chessboard

2D Chessboard
You are trying to create a chessboard representation using the alphabetical
letters O and X. The O represents the lighter spaces while the X represents
the darker spaces.

OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO

So far you have the following code within the text editor to your left:
#include <iostream>
using namespace std;

int main() {

string chessboard[8][8];

int row = sizeof(chessboard) / sizeof(chessboard[0]);


int col = sizeof(chessboard[0]) / sizeof(string);

//add code below this line

//add code above this line

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
if (j == col - 1) {
cout << chessboard[i][j] << endl;
}
else {
cout << chessboard[i][j];
}
}
}

return 0;

Chessboard Challenge
challenge

Assignment:
For this challenge, you will use your knowledge of 2D arrays to
produce the chessboard pattern:

OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO

Requirement:
Your program cannot make any changes to the existing code in the
program. If you do, you will not earn any credit for this challenge. If
you accidentally delete any existing code, you can copy the original
code shown above back into your program.

Hint: It is probably much easier to use nested for loops in your code to
populate the 2D array with either O or X than to go through each (row,
column) index to modify the elements.
Learning Objectives: Pointer Basics

Define what a pointer is

Declare a pointer

Apply the reference or address operator “&”

Apply the dereference or content operator "*"


What Is a Pointer?

Pointer Introduction
A pointer is a data type that stores a memory address of another piece of
data. Much like how an array points to all of its elements as a collection,
pointers point to the memory address of the data that they are associated
with.

.guides/img/PointerBasics

The picture above shows how pointers work. A pointer is like a key that
stores the address of the locker that it is associated with. This association
also enables the pointer to gain access to the content of what’s inside the
locker.

The advantage of using a pointer is that you do not need to worry about the
value of the data that the pointer is pointing to. Thus, if the data ever
changes its value, the pointer will still be able to access the new data as
long as the pointer still points to the data’s memory address.
Declaring a Pointer

Pointer Declaration
All pointers have a data type and a name that they are referred to. To
declare a pointer, you need to have the following syntax in order:

The data type of the pointer (e.g. int, string, etc.).


An asterisk symbol *.
A name for the pointer.

int* p;

cout << p << endl;

challenge

What happens if you:


change int* p; in the original code to double* p;, bool* p;, or
string* p;?
change int* p; in the original code to int *p;?
change int* p; in the original code to int *p = 2;?

important

IMPORTANT
The asterisk symbol can be placed anywhere between the end of
the data type (i.e. int) and the variable name (i.e. p). int* p;, int
*p, and int * p all work the same way.

Pointers can only be assigned a memory address, which is why


trying to assign 2 to a pointer will result in an error.

Pointers that are not assigned a memory address will have a default
output of 0, also referred to as null pointers.
Reference Operator

Pointer Reference
A pointer can only be assigned a memory address. They cannot be
assigned values that are int, double, string, etc. A memory address is
denoted with the & symbol, called the reference operator, and they go in
front of the variable that the address is associated with.

int a = 2;
int* p = &a;

cout << p << endl;

Code Visualizer

challenge

What happens if you:


run the same exact code again by clicking TRY IT?
change int* p = &a;; in the original code to int* p = & a;?

Code Visualizer

important

IMPORTANT
Memory is dynamic in C++ so whenever programs are compiled or
executed again, they will often output memory addresses that are
different from before.

Though memory address is dynamic, once a pointer has been


assigned a memory address, that association remains until the
program is re-compiled or re-executed.
Dereference Operator

Pointer Dereference
Every memory address holds a value and that value can be accessed by
using the dereference operator. The dereference operator is denoted by
the asterisk symbol *.

int a = 5; //regular int variable set to 5


int* p = &a; //int pointer points to a's memory address

cout << *p << endl; //dereference p to print its content

Code Visualizer

challenge

What happens if you:


change int a = 5; in the original code to int a = 50;?
change int* p = &a; in the original code to string* p = &a;?

Code Visualizer

important

IMPORTANT
A pointer can only be assigned a memory address of a variable that
holds a value of the same type as the pointer. For example, if &a is
the memory address of an int variable, then you cannot assign it to
a string pointer (string* p = &a).

Though memory address is dynamic, once a pointer has been


assigned a memory address, that association remains until the
program is re-compiled or re-executed.
Pointer to another Pointer
It is possible to have a pointer point to another pointer. To assign the
memory address of a pointer to a new pointer, that new pointer must be
denoted with two asterisk symbols **.

int a = 5;
int* p = &a;
int** p2 = &p;

cout << *p << endl;


cout << **p2 << endl;

Code Visualizer

challenge

What happens if you:


change int a = 5; in the original code to int a = 100;?
change cout << **p2 << endl; in the original code to cout << *p2
<< endl;?

Code Visualizer

important

IMPORTANT
Dereferencing a new pointer to an old pointer will return the memory
address of the old pointer. If that pointer is dereferenced again, then
the value of the variable that the old pointer pointed to will be
returned. For example, **p2 and *p both returned 5 because p2 points
to p which points to a which equals 5.
.guides/img/PointerTable

challenge

Fun Fact:
If you dereference an array, it will return only the first element in the
array.

int array[] = {24, 52, 97};

cout << *array << endl;


Why Use Pointers?

Array Memory Usage


Before we can see how useful pointers can be, let’s take a look at how
memory is used within an array:

char names[3][6] = { "Alan",


"Bob",
"Carol" };

for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {


cout << names[i] << endl;
}

Code Visualizer

Remember: The row index [3] is optional but the column index [6] is
mandatory.

Why is the column index 6 instead of 5?


When working with a string of characters, the last character is always a
special character known as a null character. This character is often
referred as NUL or \0. Therefore, the maximum character length within this
array is ‘C’,‘a’,‘r’,‘o’,‘l’,‘\0’, which has 6 characters. This is why to
be able to store all of the characters, the column index must be set to 6.

The code above creates an array of characters where the row index [3]
refers to the three starting characters A for Alan, B for Bob, and C for Carol,
and the column index 6 refers to how many character each of the rows can
hold which also includes the null characters (NUL or \0). Notice how the null
characters also take up memory space.
.guides/img/ArrayNullCharacter

Here, we know how long the names would be, so we were able to budget
the right amount memory for them. However, what if we didn’t? In such a
case, we would have to assign additional space for our characters,
something larger, like 20 for example. That way, if the name Carol was a
mistake and it was actually supposed to be ChristopherJones, we can feel
more confident that the array will still be able to hold all of the characters.
Unfortunately, this causes more memory to be wasted as depicted in the
image below.

.guides/img/ArrayWasteMemory

Pointer Usage
This is where pointers come in handy because they can help the system
save memory. When using pointers for character arrays, the pointers will
only point to the 3 leading characters A, B, and C. You do not need to specify
the column index. Note that C++ requires the keyword const for pointers
that point to characters within an array. This forces the characters to
remain intact and prevents the pointer from potentially pointing
elsewhere.
const char* names[] = { "Alan",
"Bob",
"ChristopherJones" };

for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {


cout << names[i] << endl;
}

Code Visualizer

.guides/img/PointerArray

Notice how we did not have to include any index values, which means the
potential for wasting memory can be avoided. All we needed was to
reserve enough memory for the creation of 3 pointers.
Lab: Pointer Operators

Tutorial Lab: Reference and Dereference


Operators
Pointers are used to store the memory address of a particular variable. Two
important operators associated with pointers are the reference & and the
dereference operators *. The & operator returns the memory address of a
variable and the * operator returns the value or content of the variable
being pointed to.

bool b = true;
bool* p = &b;

cout << p << endl; //prints b's memory address


cout << boolalpha << *p << endl; //prints b's value

A pointer can also point to another pointer. When doing so, the new
pointer will be denoted with two asterisk symbols **. ** is also used to
dereference a pointer twice.

bool b = true;
bool* p = &b;
bool** p2 = &p; //p2 points to p

cout << p2 << endl; //prints p's memory address


cout << *p2 << endl; //prints p's content which is b's address
cout << boolalpha << **p2 << endl;
//p2 is dereferenced twice to print b's value
Lab Challenge: Pointer Keys

Pointer Keys
You are trying to come up with a set of pointers or keys that, when referred
to, will be able to tell you the age of each of your family members. For
example, the pointer amy should be associated with the variable age1.

So far you have the following information in your code:

#include <iostream>
using namespace std;

int main() {

int age1 = 12;


int age2 = 31;
int age3 = 29;
int* amy;
int* bob;
int** carol;

//add code below this line

cout << *amy << endl; //do not edit

cout << *bob << endl; //do not edit

cout << **carol << endl; //do not edit

//add code above this line

return 0;

Pointer Challenge
challenge

Assignment:
Your task is to associate the pointers within the code to their respective
variables. The output of your program should produce:

Amy's age is: 12


Bob's age is: 31
Carol's age is: 29

Requirement:
To receive credit for the challenge, you need to do the following:
* Only add to the existing code, do not make any changes, otherwise,
you will not receive credit for your work. If you accidentally delete any
existing code, you can copy the original code shown above back into
your program.

You must use the pointers amy, bob, and carol in your code and
assign the pointers to their appropriate data.

NOTE that the pointer carol is a pointer to another pointer. You


will need to create a new pointer in your code to make the
association.
Learning Objectives: String Basics

Identify the three properties of strings

Understand the meaning of mutability

Determine if a string is present in another string and at


what index

Print a string from the start index to end index

Utilize escape characters to add special characters to a


string
String Properties

String Length
We have already seen strings in the “Fundamentals”section. We are going
to dig a little deeper with this data type. All strings have the following
characteristics:

1. Characters - Strings are made up of characters between quotation


marks (previously covered in the “Fundamentals” section).
2. Length - Each string has a length (total number of characters).
3. Index - Each character in a string has a position, called an index.

To calculate the length of a string, use the length() function. This function
will return an integer that is the sum of all of the characters between the
quotation marks.

string my_string = "Hello";


int len_string = my_string.length();

cout << len_string << endl;

challenge

What happens if you:


Change my_string to "Hello world!"?
Change my_string to ""?
Change my_string to "-1"?
Change my_string to "Привет"
important

IMPORTANT
Although each character that you see on a typical keyword usually has
a length of 1, there are other foreign characters that do not follow this
convention. For example, Привет, which stands for Hello in Russian,
actually has a length of 12 instead of 6.

String Index
Previously in the vectors module, we learned that vectors and arrays have
elements that reside in certain positions or indices. A string too has indices
that correspond to the position where each of its character resides. Like
vector and array indices, string indices also start at 0.

.guides/img/StringIndex

Strings & Quotation Marks


Quotation marks are required to declare the value of a string. However,
quotation marks are not a part of the string itself. That is why quotation
marks are not counted with the length() function and why they do not
have an index.

To reference a character, use the string name followed by the at()


function. Within parentheses (), provide the index number of the
character you want the system to return. Alternatively, you can also use
brackets [] to enclose the index number.

.guides/img/StringAtIndex
string my_string = "Hello!";
char character = my_string.at(1);

cout << character << endl;

challenge

What happens if you:


Change char character to my_string.at(my_string.length())?
Change char character to my_string.at(my_string.length()-1)?
Change char character to my_string.at(5)?
Change char character to my_string.at(-1)?
Change char character to my_string[5]?
Change char character to my_string[my_string.length()]?

Note that you cannot use my_string[my_string.length()]. An index


number is needed.
Mutability

Mutability
You now know how to reference each character of a string. What do you
think the code below will do?

string my_string = "House";


my_string.at(0) = "M";

cout << my_string << endl;

If you thought the code above would print Mouse, that would be a logical
guess. However, you see an error. Unlike vectors and arrays where the
characters can be manipulated, string literals are immutable. That means
you cannot change the string literal itself. You can, however, manipulate a
particular character within the string.

string my_string = "House";


my_string.at(0) = 'M';

cout << my_string << endl;

Can you spot the difference between the two code snippets mentioned
above? The difference lies within the double quotes "" and single quotes ''.
You cannot change the string literal, but you can change a character at a
particular index. Thus, my_string.at(0) = 'M' changes the string to Mouse
but my_string.at(0) = "M" does not.

String Re-Assignment
In addition to character manipulation, you can also change the entire
string itself by overwriting it with a new value(s).

string my_string = "House";


my_string = "Mouse";

cout << my_string << endl;


Strings in C++, like other data types, can be re-assigned. The previous
examples on this page are about mutability. That is, changing just a part of
a whole. The current example is about the assignment operator. Re-
assignment replaces the entire value of a variable with a new value. In
conclusion, you can either change one character at a time within a string,
or change the entire string literal by reassigning it.

.guides/img/MutabilityAssignment
Find

The find() Function


The find() function tells you if a character or a string is present in another
string, and if so, at what index it is at. find() returns an integer index if the
character or string is present and 18446744073709551615 if not.

What does 18446744073709551615 mean?


18446744073709551615 is the largest integer value possible in C++. When
find() is called and 18446744073709551615 is returned, it means the system
has searched through all values and cannot locate the specified value.
18446744073709551615 is an unsigned value, but it is equivalent to -1 as a
signed value.

string my_string = "The brown dog jumps over the lazy fox.";

cout << my_string.find("dog") << endl;

challenge

What happens if you:


Change the cout statement to be cout << my_string.find("cat");?
Change the cout statement to be cout << my_string.find("Dog");?
Change the cout statement to be cout << my_string.find(" ");?
Change the cout statement to be cout <<
my_string.find(my_string);?

If you want to start searching for a string or character starting at a


particular index, you can specify the start index number after the specified
string.

string my_string = "The brown dog jumps over the lazy fox.";

cout << my_string.find("he", 4) << endl; //start at index 4


challenge

What happens if you:


Change my_string.find("he", 4) to my_string.find("he", 27)?
Change my_string.find("he", 4) from the original code to
my_string.find("he")?
Substr

The substr() Function


The subst() function returns a portion of the string. Within parentheses (),
provide the index at which you want the string to start followed by a
comma followed by the number of characters you want the string to
include. Note that if you don’t specify the number of characters, the system
will start copying from the start index through to the end of the string. If
you don’t specify the start index, then the system will copy the entire string.
The subst() function does not modify the original string. Instead, it returns
a partial or entire copy of the original string.

.guides/img/StringSubstr

string my_string = "The brown dog jumps over the lazy fox.";
string my_slice = my_string.substr(4, 9);

cout << my_slice << endl;

challenge

What happens if you:


Change my_slice to be my_string.substr(1, 2)?
Change my_slice to be my_string.substr()?
Change my_slice to be my_string.substr(1, 1)?
Change my_slice to be my_string.substr(2)?
Escape Characters

Escape Characters
An escape character is a character that has a different interpretation than
what you see in a string. Escape characters always start with a backslash
(\). The most common escape character is the newline character (\n) which
causes C++ to print on the next line.

string my_string = "Hello\nworld";


cout << my_string << endl;

Escape
Description Example
Character
\\ Prints a backslash cout << "\\" << endl;

Prints a single
\' cout << "\'" << endl;
quote
Prints a double
\" cout << "\"" << endl;
quote
Prints a tab cout << "Hello\tworld" <<
\t
(spacing) endl;

challenge

What happens if you:


Use \n\n instead of \n in the original code?
Replace \n\n in your current code with \t?
Replace \t in your current code with \"?

Quotes Inside Quotes


Imagine that you have this small bit of dialog, And then she said, "Hi
there." and want to store it as a string. Typing "And then she said, "Hi
there."" would cause an error.
.guides/img/StringQuotes

When you use a " to start a string, C++ looks for the next " to end it. To
avoid syntax errors, you can use a double quote to start your string, single
quotes for the inner quote, and end the string with a double quote.

string my_string = "And then she said, 'Hi there.'";


cout << my_string << endl;

challenge

What happens if you:


Replace single quotes (') with double quotes (") and double
quotes(") with single quotes (') in the original code?
Change all quotes to double quotes (")?
Use the escape character \" for the inner quotation marks that
surround Hi there. (e.g. "And then she said, \"Hi there.\"")?
Learning Objectives: String
Functions

Identify the functions and applications of the following


string functions:

find_first_of() & find_last_of()


push_back() & insert()
pop_back() & erase()
replace()
append()
toupper() & tolower()
Find First Of & Last Of

The find_first_of() Function


The find_first_of() function works similarly to how the find() function
does. However, the find_first_of() function will search for any matching
characters specified. For example, given the string "this is his string",
my_string.find_first_of("his") will return 1 because the character h
within his appears first at index number 1. Like the find() function, you
can optionally specify an index number to direct the system where to start
searching.

.guides/img/FindFirstOf

The find_last_of() function


You can use the find_last_of() function to search for a set of characters in
a string that occur last. Here is an example, given the string “this is his
string”, my_string.find_last_of(“his”) will return 15 because the i in his
occurs last at index 15. If you don’t want the system to search the whole
string, you can specify an index as a second parameter to direct the system
where to start searching.

string string1 = "The brown dog jumps over the lazy fox.";
string string2 = "brown";

cout << string1.find_first_of(string2) << endl;


challenge

What happens if you:


Set string2 to "wornb"?
Change the cout statement to string1.find_first_of(string2,
14)?
Set string2 to "axe" and change the cout statement to
string1.find_first_of(string2, 34)?
Set string2 to "i" and change the cout statement to
string1.find_first_of(string2)?

Remember that 18446744073709551615 is equivalent to -1 which also


means not found.
Push Back & Insert

The push_back() Function


In a previous module, you were introduced to vectors. The push_back()
function works the same way in strings as it does in vectors. It adds a
specific character to the end of the string.

string my_string = "Today is Satur";


my_string.push_back('d');

cout << my_string << endl;

challenge

What happens if you:


add the code my_string.push_back("ay"); below
my_string.push_back('d');?
replace my_string.push_back("ay"); with
my_string.push_back('a');?
add the code my_string.push_back('y'); below
my_string.push_back('a');?

The insert() Function


Unfortunately, the push_back() function cannot add multiple characters
(string) to an existing string. However, the insert() function can. Unlike
many functions where specifying the starting index number is optional,
doing so is necessary for insert() to work.

Note that the index specification comes before the string you want the
system to add. For example, my_string.insert(0, "abc") will add the
string abc to the 0th index which is also the beginning of the string. To add
to the end of the string, you can use my_string.length(). Note that you do
not need to subtract 1 from my_string.length() because the system will
add characters starting at the index after the last character of the string.
string my_string = "Today is Satur";
my_string.insert(my_string.length(), "day");

cout << my_string << endl;

challenge

What happens if you:


replace my_string.insert(my_string.length(), "day"); with
my_string.insert(0, "day");?
change the code back to my_string.insert(my_string.length(),
"day"); and add my_string.insert(9, "a good "); below it?
Pop Back & Erase

The pop_back() Function


The pop_back() function removes a single character from the end of a
string. You do not include anything within parentheses ().

string my_string = "Today is my birthday!";


my_string.pop_back();

cout << my_string << endl;

The erase() Function


The erase() function can remove multiple characters from a string or the
entire string itself. To remove the whole string, leave the parentheses ()
empty. Alternatively, you can specify one index number to remove all
characters starting at that index to the end of the string. Specify two index
numbers to start at an index and erase a certain number of characters at
that index forward.

string my_string = "Today is my birthday!";


my_string.erase(my_string.length()-1);

cout << my_string << endl;

challenge

What happens if you:


Replace my_string.erase(my_string.length()-1); with
my_string.erase(12);?
Replace my_string.erase(12); in your current code with
my_string.erase(12, 5);?
Replace my_string.erase(12, 5); in your current code with
my_string.erase();

Why do I see Command was successfully executed.?


When Codio does not detect anything being printed to the console, you will
see the message Command was successfully executed. displayed. The
command my_string.erase() causes the entire string to become empty and
since an empty string has no output, you will see Command was successfully
executed. instead.
Replace

The replace() Function


The replace() function is really a combination of the erase() and insert()
functions. Let’s take a look at an example.

my_string.replace(1, 2, "3")

There are three parameters of interest within replace() above. The 1


represents the index at which we want to start erasing. The 2 tells the
system how many characters to erase starting at index 1. And the "3" is the
string that the system will insert into the string at index 1.

string string1 = "Hello world!";


string string2 = "Codio.";
string string3 = string1.replace(6, 5, string2);
// erase all characters from index 6 plus 5 chars to the right
in string1
// then insert string2 at index 6 within string1

cout << string3 << endl;

challenge

What happens if you:


Change string3 to string1.replace(6, 6, string2)?
Change string3 to string1.replace(2, 3, "y")?
Append

The append() function


An alternative way to concatenate or combine strings is to use the
append() function. The append() function works in the same way as adding
literal strings together using the + operator.

string a = "High";
string b = " Five";

cout << a.append(b) << endl;

challenge

What happens if you:


Change the cout statement to a.append(b + "!")?
Change the cout statement to a.append("Five" + "!")?
Change the cout statement to "High" + " Five" + "!"?
Change the cout statement to a + " Five" + "!"?
Change the cout statement back to a.append(b) and replace string
b = " Five"; with int b = 5;

important

IMPORTANT
NOTE that the append() function is exclusively for strings. Thus, you
cannot include other data types like ints when using append() unless
they are converted to strings first. Additionally, when using the +
operator to combine two strings together, make sure that at least one
of the strings is a string variable. Otherwise, the system will think you
are trying to manipulate a string literal, which is not allowed.
Uppercase & Lowercase

The toupper() Function


The toupper() function returns the uppercase form of a specified character.
Insert the character you wish to convert as a parameter.

Note that by default, toupper() returns the ASCII representation of the


uppercase letter. Thus, you’ll need char to convert the ASCII code into
alphabetical.

.guides/img/StringToUpper

string my_string = "the big brown dog";

cout << char(toupper(my_string.at(0))) << endl;

challenge

What happens if you:


Change the cout statement to
char(toupper(my_string.at(my_string.length()-1)))?
Change the cout statement to char(toupper('t'))?
Change the cout statement to char(toupper(my_string))?

The tolower() Function


The tolower() function returns the lowercase form of a specified character.
It has all of the technicalities that the toupper() function has.

string my_string = "THE BIG BROWN DOG";

cout << char(tolower(my_string.at(1))) << endl;

challenge

What happens if you:


Change the cout statement to
char(tolower(my_string.at(my_string.length()-1)))?
Change the cout statement to char(tolower('B'))?
Change the cout statement to char(tolower('%'))?
Learning Objectives: String
Iteration

Define string iteration

Identify two ways to iterate over a string

Explain the inner workings of string iteration


Iteration: For Loop

Iterating Over Strings


Iterating over a string allows you to deal with each character of a string
individually without having to repeat certain commands. You start with the
character at index 0 and move through the end of the string.

string my_string = "Hello world";

for (int i = 0; i < my_string.length(); i++) {


cout << my_string.at(i);
}

challenge

What happens if you:


Change the value of my_string to
"\u25A3\u25A8\u25D3\u25CC\u25A2"?
Note: Some Unicode characters are not compatible with cout
and/or endl; commands.
Change the value of my_string to "10, 11, 12, 13, 14"?
Change the cout statement to cout << my_string.at(i) << endl;?
Change the cout statement to cout << my_string;?

Note that you can also use a range-based or enhanced for loop to iterate
over strings. Make sure to cast the iterating variable as char!

string my_string = "Hello world";

for (char c : my_string) {


cout << c;
}
Iteration: While Loop

While Loop
String iteration is most often done with a for loop. However, a while can be
used as well.

string my_string = "Calvin and Hobbes";


int i = 0;

while (i < my_string.length()) {


cout << my_string.at(i);
i++;
}

challenge

What happens if you:


Change the loop to while (i <= my_string.length())?
Copy the original code but change the cout statement to cout <<
i;?
Copy the original code but remove i++;?

Comparing While & For Loops

string my_string = "C++";

for (int i = 0; i < my_string.length(); i++) {


cout << my_string.at(i);
}
string my_string = "C++";
int i = 0;

while (i < my_string.length()) {


cout << my_string.at(i);
i++;
}

Above are two ways of iterating through a string. The first way uses the for
loop and the second uses a while loop. Both produces the same result.
However, the for loop is usually preferred because it requires less code to
accomplish the same task. You can also use an enhanced for loop, which
requires the least account of code, but an enhanced while loop does not
exist.
Learning Objectives: String
Comparison
Compare strings with == and !=

Compare strings with compare()


== & !=

Comparing with ==
The == operator can be used with strings just like it is with numbers or
boolean values. Note that without the boolalpha flag, the system will return
1 if true and 0 if false. 1 represents string equality and 0 represents
inequality.

string string1 = "It's Friday!";


string string2 = "It's Friday!";

cout << (string1 == string2);

challenge

What happens if you:


Change the value of string1 to "it's friday!"?
Change the value of string2 to "it\'s friday!"?
Change the cout statement to cout << boolalpha << (string1 ==
string2);?

Comparing with !=
You can also test for string inequality with the != operator.

string string1 = "It's Friday!";


string string2 = "It's Monday.";

cout << (string1 != string2);


challenge

What happens if you:


Change the value of string2 to "It's Friday"?
Change the value of string2 to "It's Friday!"?
Change the cout statement to cout << boolalpha << (string1 !=
string2);?
Compare

Lexicographical Order
In C++, strings can be compared lexicographically, meaning they can be
compared according to how they will appear in the dictionary. You can use
the compare() method to determine which of two strings comes first. A
return value of a negative integer means the first string comes first, a
return value of a positive integer means the second string comes first, and
a return value of 0 means the strings are equal and neither comes first.

string string1 = "apple";


string string2 = "cat";

if (string1.compare(string2) < 0) {
cout << "string1 comes first" << endl;
}
else if (string1.compare(string2) > 0) {
cout << "string2 comes first" << endl;
}
else {
cout << "the strings are equal" << endl;
}

challenge

What happens if you:


Change string2 to "apple"?
Change string2 to "10"?
Change string1 to "2" in your current code?

Why Does “10” Come Before “2”?


When C++ compares strings lexicographically, it compares each character
of the strings one by one from left to right. Since the first character in 10 is
1, and 1 comes before 2, 10 is considered to come before 2 even though
numerically 2 is supposed to come first.
string string1 = "123";
string string2 = "9";

if (string1.compare(string2) < 0) {
cout << "string1 comes first" << endl;
}
else if (string1.compare(string2) > 0) {
cout << "string2 comes first" << endl;
}
else {
cout << "the strings are equal" << endl;
}

challenge

What happens if you:


Change string1 to "apple"?
Change string2 to "Apple" in your current code?
Change string1 to an empty string "" in your current code?

Letters vs. Numbers vs. Empty Strings


Lexicographically speaking, empty strings always come first, followed by
numbers, then uppercase letters, and finally lowercase letters.
Lab 1

Counting Uppercase and Lowercase Characters


You are going to write a program that takes a string and prints out two
messages. One message tells you how many uppercase characters are in the
string. The other message tells how many lowercase characters are in the
string. The program will ignore all numbers and special characters
(punctuation, symbols, etc.).

String Functions

You will need two string functions that were not covered earlier to help
with this project:
* isupper() - Returns an integer greater than 0 if the character is
uppercase, 0 if the character is not.
* islower() - Returns an integer greater than 0 if the character is
lowercase, 0 if the character is not.

Variables

You will need three variables for this project. One variable will count all of
the lowercase characters, another to count the uppercase characters, and
one for the string itself.

int lower_count = 0;
int upper_count = 0;
string my_string = "Roses are Red, Violets are Blue";

Iterating Over the String

The next thing to do is iterate over the string and to check each character of
the string. A enhanced for loop works best.

for (char ch : my_string)

Checking for Uppercase and Lowercase


It does not matter if you check for an uppercase character first or check for
a lowercase character. Let’s start with lowercase characters. Ask if the
character is lowercase and increment the appropriate counting variable.

if (islower(ch)) {
lower_count += 1;
}

What you do not want to do is use an else statement. This will not give you
an accurate count. For example, asking if a special character is lowercase
will return 0. However, that does not mean that it is an uppercase character
either. Special characters are neither uppercase nor lowercase. So use an
else if statement and ask if the character is uppercase. If so, increment
the uppercase counting variable.

else if (isupper(ch)) {
upper_count += 1;
}

Print the Results

The final step is to print the messages with the count values.

cout << "There are " << lower_count << " lowercase characters."
<< endl;
cout << "There are " << upper_count << " uppercase characters."
<< endl;

There should be 4 uppercase characters and 21 lowercase characters.

Code
int lower_count = 0;
int upper_count = 0;
string my_string = "Roses are Red, Violets are Blue";

for (char ch : my_string) {


if (islower(ch)) {
lower_count += 1;
}
else if (isupper(ch)) {
upper_count += 1;
}
}

cout << "There are " << lower_count << " lowercase
characters." << endl;
cout << "There are " << upper_count << " uppercase
characters." << endl;
Lab 2

Reverse a String
You are going to write a program that takes a string and prints it in reverse
order.

Variables

All you need for this program is the string variable and a loop to iterate
through the string.

string my_string = "The brown dog jumps over the lazy fox";

String Iteration

Since we are going to reverse the order of the string, we will need to start at
the end of the string and iterate back to the front. Unfortunately, an
enhanced for loop will not help us in this case because it only iterates from
left to right. However, we can still use a regular for loop.

The for loop should start at the back my_string,length()-1 and run as long
as index is greater than or equal to 0. After each iteration, the iterating
variable should also decrement by 1 to allow the loop to reverse.

for (int i = my_string.length()-1; i >= 0; i--)

Reversing a string comes down to taking the character from the end
printing that first, then go backwards. This will be done by accessing the
indices with at().

my_string.at(i);

Printing the result

All that’s left to do is print. Remember not to include endl or the system
will print a newline after each character.

cout << my_string.at(i);


You should see xof yzal eht revo spmuj god nworb ehT.

Code

string my_string = "The brown dog jumps over the lazy fox";

for (int i = my_string.length()-1; i >= 0; i--) {


cout << my_string.at(i);
}
Lab 3

Swapping the Case of Characters


You are going to write a program that takes a string and prints a new string
where all of the uppercase letters become lowercase, and the lowercase
letters become uppercase.

Variables

You are going to need two string variables. The first string variable
represents the original string and the second represents the modified
string. For now, the modified string can be empty.

string original_string = "THE BROWN DOG JUMPS over the lazy


fox!";
string modified_string;

String Iteration

It does not matter if you start at the beginning of the string or the end for
iteration. An enhanced for loop is the easiest way to iterate through the
original_string. Set the iterating variable as ch.

for (char ch : original_string)

String Functions

You are going to use the isupper() and islower() functions to test if a
character is uppercase or lowercase. In addition, you will be using the
toupper() and tolower() functions to convert characters to their new cases.

Conditional

For consistency, we will test if a character is lowercase first. However, you


may choose to test for uppercase first. It does not matter as long as the
conversion is correct.

if (islower(ch))
If this is true, then append the uppercase version of the character to the
variable modified_string.

modified_string += toupper(ch);

If the conditional is false, then append the lowercase version of the


character to modified_string.

else {
modified_string += tolower(ch);
}

You do not need to worry about special characters. Converting them to


uppercase or lowercase has no effect.

Printing the Results

Once the loop has finished, print both the original string and the modified
string.

cout << "The original string is: " + original_string << endl;
cout << "The modified string is: " + modified_string << endl;

You should see the following output:

The original string is: THE BROWN DOG JUMPS over the lazy fox!
The modified string is: the brown dog jumps OVER THE LAZY FOX!

Code
string original_string = "THE BROWN DOG JUMPS over the lazy
fox!";
string modified_string;

for (char ch : original_string) {


if (islower(ch)) {
modified_string += toupper(ch);
}
else {
modified_string += tolower(ch);
}
}

cout << "The original string is: " + original_string << endl;
cout << "The modified string is: " + modified_string << endl;
Lab 4

Count the Vowels


You are going to write a program that counts the number of vowels that
appear in a string. For the purpose of this exercise, vowels are upper and
lowercase a, e, i, o, u.

Variables

For this project, you will need three variables. One will be the string.
Another will be a char to represent each character of the string. The final
variable will be a count of all the vowels.

string my_string = "The Brown Dog Jumps Over The Lazy Fox";
char ch;
int count = 0;

String Iteration

Use a for loop to iterate through the string. Then set ch to check every
character in the string.

for (int i = 0; i < my_string.length(); i++) {


ch = my_string.at(i);
}

Checking for a Vowel

Use a conditional to see if the characters in the string are equal to any
vowels. Make sure to account for both uppercase and lowercase vowels.

if (ch == 'a' || ch == 'e' || ch == 'i' ||


ch == 'o' || ch == 'u' || ch == 'A' ||
ch == 'E' || ch == 'I' || ch == 'O' ||
ch == 'U') {

Note that characters are wrapped in single quotes ' ', not double quotes in
C++.
Incrementing the Counter

If ch equals any of the vowels, increment the count variable.

count += 1;

Printing the Result

The string may contain no vowels, one vowel, or more than one vowels.
Thus, you’ll need conditionals to output the appropriate responses.

if (count == 0) {
cout << "There are no vowels in the string." << endl;
}
else if (count == 1) {
cout << "There is 1 vowel in the string." << endl;
}
else {
cout << "There are " << count << " vowels in the string." <<
endl;
}

You should see that there are 9 vowels in the string.

Code
string my_string = "The Brown Dog Jumps Over The Lazy Fox";
char ch;
int count = 0;

for (int i = 0; i < my_string.length(); i++) {


ch = my_string.at(i);
if (ch == 'a' || ch == 'e' || ch == 'i' ||
ch == 'o' || ch == 'u' || ch == 'A' ||
ch == 'E' || ch == 'I' || ch == 'O' ||
ch == 'U') {
count += 1;
}
}

if (count == 0) {
cout << "There are no vowels in the string." << endl;
}
else if (count == 1) {
cout << "There is 1 vowel in the string." << endl;
}
else {
cout << "There are " << count << " vowels in the string." <<
endl;
}
Lab Challenge: Vowel Replacement

Replacing Vowels with a *


You are going to write a program that takes a string called my_string and
returns the string but with a * in the place of vowels. Assume that vowels
are upper and lowercase a, e, i, o, u. For example, if my_string =
"Hello", then your program will print "H*ll*".

Some of the code has already been filled out for you. Your task is to
complete the program so that it produces some of the sample output below.
If you accidentally change anything from the original code, you can copy
and paste the code back into the text editor.

#include <iostream>
using namespace std;

int main(int argc, char** argv) {

string my_string = (argv[1]);


char ch;

//add code below this line

//add code above this line

return 0;

Compile and test your code with a few different values

Expected Output
Hll

Expected Output
ppl
Expected Output
Wtrmln!

Requirements

You should not make any changes to the code that already exists. If you
accidentally delete any existing code, you can copy and paste the entire
program from above.
You can use any number of string functions and conditionals to
produce the desired output.
Learning Objectives: Reading
Demonstrate how to open a file using ifstream

Use the get(), getline(), and rdbuf() functions to read a


string stream

Iterate through a file using a while loop

Define the term “token”

Tokenize a string read from a file using a delimiter

Ignore characters in a file with the ignore() function


File Basics

File Basics
This module is all about working with files on a computer. The first step is
to locate the desired file. That means being able to navigate the file system.
The file we are going to use is called practice1.txt. It is located in the text
folder, which is inside the folder called student. So the path to the file is:
student/text/practice1.txt.

File Path

Use a string to represent the file path. This string will be passed to direct
the system to open a file.

string path = "student/text/practice1.txt";

Opening and Closing Files


One of the most common ways to open, close, read, and write files is to use
the ifstream or ofstream data type. The difference between ifstream and
ofstream is that ifstream is used to read data from files whereas ofstream is
used to write to files. Both of these data types can be accessed and utilized
by including #include <fstream> in the header of your code file. Let’s try to
open practice1.txt as specified from above using ifstream.

string path = "student/text/practice1.txt";

ifstream file;
file.open(path);

You’ll see that Command was successfully executed. is returned, which isn’t
very helpful. To know if the file was opened successfully, you can set up
conditions like so:

string path = "student/text/practice1.txt";

ifstream file;
file.open(path);
if (file.is_open()) {
cout << "File successfully opened." << endl;
}
else if (!file.is_open()) {
cout << "File failed to open." << endl;
}

challenge

What happens if you:


Change if (file.is_open()) to if (file)?
Change else if (!file.is_open()) to else if (!file)?
Change the string path to "student/text/practice2.txt"?

Before your program terminates, it is a best practice to close the file. When
a file is opened, it takes up memory that will not free up until the file is
properly closed.
string path = "student/text/practice1.txt"; // setting file path

ifstream file; //create a read-only data stream


file.open(path); //open the file as a stream
if (file) { //check if file exists
cout << "File successfully opened." << endl;
}
else if (!file) { //check if file does not exist
cout << "File failed to open." << endl;
}
file.close(); //close the file

File Error Handling


Back in the “User-Defined Functions” module, you were introduced to the
try, throw, and catch blocks which are used to handle runtime errors that
occur as the program runs. You can apply the same concept to catch errors
when opening files which is the preferred way to handle these errors.

string path = "student/text/practice1.txt";

try { //try these actions


ifstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open."); //throw error
}
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

challenge

What happens if you:


Change the string path to "student/text/practice2.txt"?
info

What is cerr?
When printing error messages, cerr is preferred over cout. cerr is not
bufferred, which means it is not stored in memory to be printed later
on. It just gets printed immediately. Therefore, as a rule of thumb,
important data and variables should be printed with cout while error
messages should be printed with cerr.
Reading a File

Reading a File
Let’s start reading from a file that contains some text. First set the string
path to student/text/readpractice.txt. Then open the file and handle any
opening errors. To read from a file, use the getline() function. The
getline() has at least two parameters; the first is the input stream to read
from and the second is a string to store what is read.

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read; //create string to store what is read into
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
getline(file, read);
cout << read;
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}
important

IMPORTANT
You’ll notice from above that the system printed File successfully
opened and closed. first and then C++ was created by Bjarne
Stroustrup. was printed. This is due to cerr being unbuffered, which
means it gets printed immediately. cout is buffered, so it will store its
content into memory before printing, which explains the delay. This
doesn’t mean that cerr always gets printed first, it just depends on
what on quickly cout stores its content.

To see the content of the file readpractice.txt, click this link here:
readpractice.txt

If you take a look at the content of the file, you’ll see that it has more text
than just C++ was created by Bjarne Stroustrup.. The reason why only
one line of text was printed is because getline() only reads up until a
newline character is reached. To continue to read more lines of text, wrap
getline() inside a while loop.

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read; //create string to store what is read into
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
cout << read;
}
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}
challenge

What happens if you:


Change cout << read; in the code to cout << read << endl;?
Change the entire code to:

string path = "student/text/readpractice.txt";

try {
ifstream file;
char ch; //create string to store what is read into
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (file.get(ch)) {
cout << ch;
}
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}

Change cout << ch; in the new code to cout << ch << endl;?

The get() function in the new code works similarly to the getline()
function. However, get() reads character by character instead of by
strings.

Additionally, did you notice that File successfully opened and closed.
was printed at two different locations before and after << endl was added?
This all depends on how quickly cerr and cout work behind the scenes. To
avoid inconsistencies in printing, we’ll avoid printing the success message
moving forward.
Reading a Buffer

The rdbuf() Function


The getline() and get() functions require a variable to store its content. If
all you want to do is to read a file however, then the variable becomes
useful and simply takes up extra memory. When a file is opened, its content
is buffered or stored in memory until it gets closed. During this buffering
stage, you can use the function rdbuf() to read the content of the file
without having to create any variables.

string path = "student/text/readpractice.txt";

try {
ifstream file;
file.open(path); //content of file goes into memory buffer
if (!file) {
throw runtime_error("File failed to open.");
}
cout << file.rdbuf(); //read the buffered content
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

challenge

What happens if you:


Switch the line cout << file.rdbuf(); with file.close()?

If the file is closed, the buffer gets flushed to clear the memory that was
used. So after a file is closed, you will not be able to read the buffered
content anymore.
Delimiters

Delimiters
Delimiters are a predefined character that separates one piece of
information from another. Some common delimiters involve white spaces
(' ') and commas (','). When using getline() previously, we only made
use of two of its parameters. It actually has a third parameter which is
reserved for a delimiter. By default, this delimiter is the newline character
('\n'). Thus the parameters for getline(x, y, z) are:
* The stream source (x).
* The string variable to store what is read (y).
* The delimiter to separate the content of the stream source (z).

Let’s specify the getline() function to use a comma as a delimiter ,.

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
getline(file, read, ','); //specify comma as delimiter
cout << read;
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see file’s content: readpractice.txt

When a delimiter is applied, the system will read only up to that delimiter.
This is why you only see content up through the first comma occurrence. If
you want to continue reading further and get to the other comma
occurrences, you can put the command inside a while loop.
string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) { //specify comma as
delimiter
cout << read;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see file’s content: readpractice.txt

The code above continues to read the stream and separates the content via
the delimiter, ,. This is why there are no commas present in the output.
However, it doesn’t look very clear that the stream has been separated
since the system continues to print the remainder of the stream. You can
add << endl to the output so that the system will print a newline after each
delimiter is reached so that you can see clearer where the content is
separated.
string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) { //specify comma as
delimiter
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see file’s content: readpractice.txt

challenge

What happens if you:


Change the delimiter argument from ',' to a white space ' '?
Change the delimiter again to an 'a'?
Change the delimiter again to a newline '\n'?

Click to see file’s content: readpractice.txt


Tokens

Tokens
When we apply a delimiter to break up a stream or string, the resulting
separated strings are sometimes referred to as tokens. Tokens are useful if
you want to use their data for further analysis later on. For example, you
can store each token as an element in a vector in which you can extract
further information from later on. What do you think the code below does?

The following file contains the first and last names of 5 individuals:
names.txt
string path = "student/text/names.txt";
vector<string> names;
string last_name = "Smith";
int count = 0;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ' ')) {
names.push_back(read);
}
file.close();
for (int i = 0; i < names.size(); i++) {
if (i % 2 == 1) {
if (names.at(i) == last_name) {
count++;
}
}
}
cout << "There are " << count << " people whose last name is
Smith." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}

The code above enables you to do several things:


1. Break the stream into several tokens separated by a white space.
2. Store the tokens into a vector.
3. Iterate through the vector to count how many people have the last name
“Smith”.
4. Print the resulting count.
challenge

What happens if you:


Try to search for a first name such as "Jackie" instead?
Sample Solution

string path = "student/text/names.txt";


vector<string> names;
string first_name = "Jackie"; //change variable to first
name
int count = 0;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ' ')) {
names.push_back(read);
}
file.close();
for (int i = 0; i < names.size(); i++) {
if (i % 2 == 0) { //start checking index 0 and then
every other index
if (names.at(i) == first_name) { //first name found
count++;
}
}
}
cout << "There are " << count << " people whose first
name is Jackie." << endl;
} //change the print statement as needed

catch (exception& e) {
cerr << e.what() << endl;
}

Applying Another Delimiter


If you need to further break down your tokens, you can use a nested loop to
iterate through those tokens to break them down even further. For
example, if your list of names was organized like this:

Jason Seymore
Jackie Simmons
Jennifer Small
Jane Smith
John Smith

Then using the code above will cause issues since it only takes a white
space as a delimiter, not a newline. To include both the newline and white
space as delimiters, you can use a stringstream data type (#include
<sstream>) to create another string stream off of the string variable read.
The first getline() function will separate the stream using a newline as the
delimiter and the second getline() will use a white space as a delimiter.
string path = "student/text/names2.txt";
vector<string> names;
string last_name = "Smith";
int count = 0;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) { //newline delimiter
stringstream ss(read); //create a string stream of read
while (getline(ss, read, ' ')) { //white space delimiter
names.push_back(read);
}
}
file.close();
for (int i = 0; i < names.size(); i++) {
if (i % 2 == 1) {
if (names.at(i) == last_name) {
count++;
}
}
}
cout << "There are " << count << " people whose last name is
Smith." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see files’ content: names2.txt and names.txt

challenge

What happens if you:


Change the string path from "student/text/names2.txt" to
"student/text/names.txt"?

Notice how you get the same result regardless of how your names are
organized in the text file.
Ignore Function

The Ignore Function


The ignore function takes an integer as a parameter, and causes C++ to go
to a specific character in the text file. The integer is the index for the text
file. So ignore(0) is the first character of the file, ignore(1) is the second
character, etc. The code below prints out the entire text file.

Click to see file’s content : readpractice.txt

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Now compare the output above with the output from the code below. C++
will ignore the first 29 characters and start reading only from the character
at position 30.
string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.ignore(30); //ignore all chars before index 30
while (getline(file, read)) {
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

challenge

Try these variations:


Change the ignore argument to 40: file.ignore(40);
Change the ignore argument to 400: file.ignore(400);

Why do I see Command was successfully executed.?


The text file only has 242 characters total, which include white spaces
and newlines. Ignoring all characters before index 400 is like ignoring
the entire file. Nothing gets read or printed which is why the system
returned Command was successfully executed..
Learning Objectives: Writing
Demonstrate how to open a file and write to it using
ofstream

Explain what happens when you write to a file that does


not exist

Demonstrate how to write multiline strings to a file

Differentiate between input, output, and append modes


Writing to a File

Writing to a File
When writing to a file, you’ll want to use ofstream instead of ifstream. Like
before, create your string path, open the file, and check for whether it can
be opened successfully.

string path = "student/text/practice1.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

If the file is successfully opened, you can start writing to the file using the
insertion operator << followed by what you want to write in double quotes
"". Remember to close the file, and if you want, you can print a message at
the end telling the user that that the file was successfully written to.
string path = "student/text/practice1.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file << "Hello there";
file.close();
cerr << "Finished writing to file.";
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Click on the link to open the file and see what was wrttien: Open
practice1.txt

challenge

Try these variations:


Open the practice1.txt file after each change to see what gets written.
* Change "Hello there" to "Goodbye".
* Change "Goodbye" in your current code to "".
* Open student in the sidebar on the left. Open the text folder and
right-click on practice1.txt. Select Delete... and YES to delete the file
and then run the program again.

Why is there no error message?


If you tell C++ to create an ofstream file, it will automatically create
that file if one does not exist. Or it will overwrite the existing file with a
new one. This is why you do not see an error message. You will only see
an error message if for some reason the system is not able to create the
file at all.

Open practice1.txt

Reading a Written File


If you want to read from the file after it was written to, you can create an
ifstream to read from the file.
string path = "student/text/practice1.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file << "Hello there";
file.close();

ifstream stream;
string read;
stream.open(path);
while (getline(stream, read)) {
cout << read << endl;
}
stream.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

challenge

What happens if you:


Change "Hello there" to "Hi!".
Add file << " My name is AI." << endl; to the line after file <<
"Hi!";?
Multiline Strings

Multiline Strings
In addition to being able to write and output string literals (e.g. file <<
"Hi!";), we can also write and output the content of variables (e.g. file <<
var;). Let’s tweak the code from the previous page to write multiple
messages to a text file called practice2.txt. We’ll create three string
variables, text1, text2, and text3. The first message will go into a string
variable text1, the second will go into text2, and the third will go into
text3.

string path = "student/text/practice2.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
string text1 = "Hello, ";
string text2 = "your balance is: ";
string text3 = "12.34";
file << text1 + text2 + text3;
file.close();

ifstream stream;
string read;
stream.open(path);
while (getline(stream, read)) {
cout << read << endl;
}
stream.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Open practice2.txt
challenge

What happens if you:


Change string text3 = "12.34"; to double text3 = 12.34;?
Change file << text1 + text2 + text3; to file << text1 + text2
<< text3;?
Split the code file << text1 + text2 << text3; into two lines:

file << text1 + text2 << endl;


file << text3;

Change file << text1 + text2 << endl; to file << text1 + text2
<< '\n';?
Change file << text1 + text2 << '\n'; to file << "Hello, your
balance is:\n12.34"; and remove file << text3;?

Open practice2.txt

Notice how you can also write the content of other types of data (double,
int, etc.) to a file. You are not restricted to just strings. Also, there are
multiple ways to write the same kind of content to a file.
Appending to a File

Appending to a File
You may have noticed that every time a file is opened using an ofstream
object, a new file is always created, even if one already exists (the system
just overwrites the existing file). If you want to add to an existing file, you
have to tell C++ to open the file in append mode. Let’s look at the code
below and TRY IT.

string path = "student/text/practice3.txt";

try {
ofstream file;
file.open(path, ios::app); //open file in append mode
if (!file) {
throw runtime_error("File failed to open.");
}
string text = "Adding to the file.";
file << text;
file.close();

ifstream stream;
string read;
stream.open(path);
while (getline(stream, read)) {
cout << read << endl;
}
stream.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Open practice3.txt

Since there is no practice3.txt file at the start of the program, C++ will
create one. However, try running the code again and see what happens.

Open practice3.txt
You’ll notice that the output Adding to the file. shows up twice in the file.
This happens because we have included the tag ios::app as a second
parameter when we opened up the file practice3.txt. By default, an
ofstream object has the flag ios::out as a second parameter, which causes
the file to always get overwritten. By changing the parameter to ios::app,
we’re telling the system to add to the file instead of overwriting it.

challenge

What happens if you:


Change ios::app in the code to ios::out?
Change ios::out to ios::in?
Change file << text; to file << text << text;?
Change file << text << text; to file << "Hello";?
Change ios::in back to ios::app?

Open practice3.txt

If you follow through the challenges above, you’ll notice that when the flag
is set to input mode ios::in, the system will overwrite the content without
creating a new file or overwriting the old one. On the other hand, ios::app
will add to the end of the existing content. Lastly, ios::out creates a
completely new file and writes to it.
Learning Objectives: CSV
Define CSV

Read data from a CSV file

Iterate over a CSV file

Print data from a CSV file with formatting

Write data to a CSV file


CSV Files

CSV Files
C++ can work with files besides just text files. Comma Separated Value (CSV)
files are an example of a commonly used file format for storing data. CSV
files are similar to a spreadsheet in that data is stored in rows and columns.
Each row of data is on its own line in the file, and commas are used to
indicate a new column. Here is an example of a CSV file.

Month Python CSV

You can read a CSV file in the same way you read a text file. First create an
ifstream object and then open the CSV file using it.

string path = "student/csv/monty_python_movies.csv";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) {
cout << read + ' ';
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
To iterate through the CSV file, we use while (getline(file, read, ',')).
Since CSV files contain commas that separate information, we set the
delimiter to ','. Then we print the content by using cout << read + ' '.
We add a space to separate the tokens from each other since it is not
apparent that the information is tokenized from using just cout << read;.

challenge

Try this variation:


Change cout << read + ' '; to cout << read << endl;?

By using cout << read << endl; you can clearly see each token line by line.
Depending on your preference, you can choose to arrange the tokens in a
variety of different formats.

Ignoring the Header


The first row of a CSV file is helpful because the header values provide
context for the data. However, the first row is not useful if you want to
know how many rows of data there are, or to calculate the avg value, etc.
Here, you can also use the ignore() function to skip a specific number of
characters.

string path = "student/csv/monty_python_movies.csv";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.ignore(19); //Ignore the first 19 characters from index
0-18
while (getline(file, read, ',')) {
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
challenge

Try this variation:


Change file.ignore(19); to file.ignore(53);?
Change file.ignore(53); to file.ignore(500);?
Change file.ignore(500); to file.ignore(500, '\n');?
Add another file.ignore(500, '\n'); below the first
file.ignore(500, '\n');?

The file.ignore(500, '\n'); command tells the system to skip the first
500 characters or up through the newline character \n. Since there are
fewer than 500 characters, the system will skip everything up through the
first occurrence of the newline. You can add additional ignore commands
to ignore more lines of data if needed.
Printing CSV Data

Printing CSV Data


Iterating over the CSV file and printing each line does not produce visually
pleasing output. The code below produces three columns of data, but there
is no consistency in the spacing between columns. When printed, the data
looks very disorganized and difficult to read.

string path = "student/csv/homeruns.csv";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) {
cout << read + " ";
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

To better organize our CSV data, we can store the data into a vector and
then format and print elements in a way that looks more organized.
string path = "student/csv/homeruns.csv";
vector<string> data;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
data.push_back(read);
}
}
file.close();
for (int i = 0; i < data.size(); i++) {
if (i % 3 == 0) {
cout << setw(20) << left << data.at(i);
}
else if (i % 3 == 1) {
cout << setw(15) << left << data.at(i);
}
else {
cout << data.at(i) << endl;
}
}
}

catch (exception& e) {
cerr << e.what() << endl;
}

To organize our data, we use conditionals to split our elements into three
columns. if (i % 3 == 0) refers to the elements in the first column, else
if (i % 3 == 1) refers to the second column, and else refers to the third.
We use the setw() function to provide padding for our elements. For
example, setw(20) means that the system will reserve 20 characters for the
elements. If the element does not take up 20 characters, then white spaces
will occupy those spaces. To use setw(), you’ll need #include <iomanip> in
the header of your file. The left tag forces the element to be aligned to the
left side.
challenge

Try this variation:


Change setw(20) to setw(16)?
Change setw(15) to setw(10)?
Delete the second left tag?
Delete the first left tag?
Note
By default, standard streams are set to right. This is why deleting
all of the left tags will effectively align the streams back to the
right side. Additionally, you only have to set the left tag once for
all streams that follow to align left as well.

Notice how the last column Active Player is not formatted and is therefore
unaffected by the changes.

important

IMPORTANT
The order or placement of where you use left and setw() can affect all
streams that follow. So it’s important to keep track of the changes that
take place as you print. For example outputting
Writing to CSV Files

Writing to a CSV File


Writing to a CSV files is similar to writing to a text file. First create an
ofstream object to open the CSV file. Then you can write to the CSV file
using the insertion operator <<. To read the CSV file, you can use the same
syntax that was previously shown.

string path = "student/csv/writepractice.csv";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file << "Greeting,Language" << endl;
file << "Hello,English" << endl;
file << "Bonjour,French" << endl;
file << "Hola,Spanish";
file.close();

ifstream file2;
string read;
file2.open(path);
while (getline(file2, read, ',')) {
cout << read + ' ';
}
file2.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Click to open CSV file: writepractice.csv

To organize the CSV data, you can add each token into a vector and then
use conditionals to format and print the data like before.
string path = "student/csv/writepractice.csv";
vector<string> data;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
data.push_back(read);
}
}
file.close();
for (int i = 0; i < data.size(); i++) {
if (i % 2 == 0) {
cout << setw(15) << left << data.at(i);
}
else {
cout << data.at(i) << endl;
}
}
}

catch (exception& e) {
cerr << e.what() << endl;
}
Lab 1

Lab 1
As you read a text file, you go line by line until you reach the end of the file.
What happens if you want to go back to a specific line of text? A common
practice that comes with reading text from a file is to store that information
into something like a vector. This way you can easily reference any data
obtained from the file.

Before reading the file, create the path variable with the file path, and
instantiate the string vector text.

string path = "student/labs/fileslab1.txt";


vector<string> text;

Use try, throw and catch blocks to handle input/output exceptions. In the
try portion, create an ifstream object to read through the file and store its
content into a string variable. While reading, add each line to the vector
text. Print any errors in the catch portion. You can optionally print a
message that the file has successfully been read, but that is not required.

string path = "student/labs/fileslab1.txt";


vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
text.push_back(read);
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
The content of the text file now resides in the vector variable text.
However, the code above only adds text from the file into the vector. To
print what was stored in the vector, use a loop to iterate the vector’s
elements first followed by the cout command.

string path = "student/labs/fileslab1.txt";


vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
text.push_back(read);
}
for (int i = 0; i < text.size(); i++) {
cout << text.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

You should see a passage from Bram Stoker’s Dracula. You’ll notice,
however, that the output is just a collection of text grouped together. In
fact, if you were to print the first element in the vector, you will get the
same result. The entire file was read and stored as the first element in the
vector. This occurs because the default delimiter is a newline and there is
only 1 occurrence of a newline at the end of the file.

Let’s change the delimiter into a period . so that the text will be tokenized
into sentences. Each token will represent one sentence from the passage.
string path = "student/labs/fileslab1.txt";
vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) { //set delimiter as a period
text.push_back(read);
}
for (int i = 0; i < text.size(); i++) {
cout << text.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

The passage is tokenized using a period . as a delimiter. When the


delimiter is specified, the system extracts the period from the text, this is
why you do not see the periods in the output. To put the periods back into
the vector, simply include + '.' in the push_back() statement.
string path = "student/labs/fileslab1.txt";
vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) {
text.push_back(read + '.'); //add period to end
}
for (int i = 0; i < text.size(); i++) {
cout << text.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Your vector now includes 4 elements, each representing a sentence from


the passage extracted from the file fileslab1.txt. To bring your focus to a
particular sentence, you can use the at() function and specify the position
of the sentence you are interested in.
string path = "student/labs/fileslab1.txt";
vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) {
text.push_back(read + '.');
}
cout << text.at(1); //print the second element/sentence
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

To erase the first leading white space, you can use text.at(1).erase(0, 1).
This will take the system to the first position, index 0, and erase just 1
character in that string.

string path = "student/labs/fileslab1.txt";


vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) {
text.push_back(read + '.');
}
cout << text.at(1).erase(0, 1) << endl; //erase the first
string char
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
Lab 2

Lab 2
This lab uses a comma delimited CSV file fileslab2.csv, which contains
integers. There are three columns and four rows. The program below will
print the sum for each row in the CSV. This is what the file currently looks
like:

1,4,5
18,34,99
0,12,51
37,29,61

We’ll start with directing the path to the file, creating a vector nums to store
the data for later, creating an ifstream and string to read and hold the
content of the file temporarily, and using try, throw and catch blocks to
handle any issues when opening the file.

string path = "student/labs/fileslab2.csv";


vector<string> nums;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

After, use the getline() function to iterate through the file and store its
content as tokens in the vector. Note that you will need to go through the
file twice and include a stringstream object to further help tokenize the
data. Try running the code below to see what’s currently stored.
string path = "student/labs/fileslab2.csv";
vector<string> nums;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
nums.push_back(read);
}
}
for (int i = 0; i < nums.size(); i++) {
cout << nums.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

You should see a list of numbers after the code runs. Though what you see
are numbers, they are currently strings which means we cannot do
calculations on them directly. We must convert them into integers first
using stoi(). Additionally, the data is stored in a vector which is one
dimensional but we want to calculate totals for multiple rows. To achieve,
we’ll use a double nested for loop to iterate through the vector in chunks of
three elements which will allow us to calculate the totals of each row.
string path = "student/labs/fileslab2.csv";
vector<string> nums;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
nums.push_back(read);
}
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

for (int i = 0; i < nums.size(); i+=3) {


int total = 0;
for (int j = 0; j < 3; j++) {
total += stoi(nums.at(i + j));
}
cout << "Total: " << total << endl;
}

Your program should print the following output:

Total: 10
Total: 151
Total: 63
Total: 127
Lab 3

Lab 3
The goal of this lab is to rely on user input for data. We are going to
continuously ask the user to enter the name of a superhero followed the
name of their power. If the user enters lowercase q, the system will stop
collecting data and write all of the data collected to the CSV file
superheroes.csv.

First let’s create our string path, ofstream object, read string, and exception
blocks like usual.

string path = "student/labs/superheroes.csv";

try {
ofstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Next, we need to create variables for our user input. Additionally, we also
need to continuously ask the user for output until they enter q. After q is
detected, the information entered will be written to our CSV file.
string path = "student/labs/superheroes.csv";
string name;
string power;

try {
ofstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}

while (true) {
cout << "Please enter a superhero name (or enter q to quit):
";
cin >> name;
if (name == "q") {
break;
}
cout << "Please enter a superhero power (or enter q to
quit): ";
cin >> power;
if (power == "q") {
break;
}
file << name << ',' << power;
}

file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click the TRY IT button to enter information into the terminal. Enter q to
stop the data collection and write to to the CSV file. Click on the CSV file link
below to see everything that was entered.

Open superheroes.csv
Lab Challenge

Lab Challenge
Write a program that reads a text file . This file is stored in the variable
path.

DO NOT alter this line of code in the program!

////////// DO NOT EDIT! //////////


string path = argv[1]; //
//////////////////////////////////

The file contains several instances of the word Burma. Replace each instance
of Burma with Myanmar, and print the results of this transformation. The final
output of your program should be:

Myanmar is a country in Southeast Asia.


The capital of Myanmar is Naypyidaw.
Its population is about 54 million people.
Myanmar is a former British colony.

Hint
You can use the FindAndReplace() function to replace all instances of Burma
with Myanmar. Note that you will need to store the content of the file into a
string in order to use this function.

You might also like