Unit 10: Arrays and Vectors

  1. For loops
    1. Vanilla for loops
    2. Range-based for loops
  2. About arrays
    1. What are arrays? Why so many kinds?
    2. Index and Element
  3. Types of arrays you should know
    1. C-style traditional arrays
    2. C++ STL array
    3. C++ STL vector
    4. C++ dynamic array (using a pointer)
  4. Using arrays/vectors
    1. Arrays/vectors with objects
    2. Iterating over array/vectors with a for loop
    3. Accessing an element with a variable index
  5. Debugging arrays/vectors
    1. Out of bounds errors
    2. Accessing a vector's index when nothing allocated

  6. Example code and additional resources

This week's stuff:

Arrays and Vectors

Vanilla for loops

A for loop is a type of loop that works good for counting.
A for loop header takes the form: for ( INIT; CONDITION; UPDATE ) and it contains a body { } like if statements and while loops. The loop's contents will continue looping while the CONDITION evaluates to TRUE.

Most frequently, we count UP with a for loop, like this:

// Display 0 1 2 3 4 to the screen.
for ( int i = 0; i < 5; i++ ) // INIT ; CONDITION ; UPDATE
{
  cout << i << " ";
}

We can do the same thing with a while loop, but with more lines of code:

int i = 0; // INIT
while ( i < 5 ) // CONDITION
{
  cout << i << " ";
  i++; // UPDATE
}

Range-based for loops

Range-based for loops allow us to iterate over a sequence of items, without having a counter variable like i. It looks like this:

// Go over all the elements of "myList"
// and use "item" to represent each one
for ( auto& item : myList )
{
  cout << item << endl;
}

The auto keyword is a special keyword in C++ that can be used in place of a TYPE in a variable declaration. It will automatically figure out the data type of the variable.

auto my_num = 50; // Creates an integer
auto my_price = 9.99; // Creates a double

What are arrays? Why so many kinds?

An array is a way we can store a sequence of data, all grouped together under one name. All the elements stored in an array (in C++) must be the same data type.


In C++ we have various ways we can create arrays. Part of this is because C++ was built on top of C, so we can write things in a C-code-style in C++.

I'm going to cover all the ways I think that you might experience in future classes so you're at least familiar with each one, but for the most part we'll be working with vector, the most useful.


What we'll cover:

  1. C-style arrays (I call these "traditional arrays")
  2. C++'s array class from the STL
  3. C++'s vector class from the STL
  4. Creating a dynamic array with a pointer

Index and Element

When we create an array (a non-vector array) we must specify a size of the array - the size must be known at compile-time.

The array will contain elements - each element is basically a single variable, stored within the array.

Each element is at some position in the array. The number representing this position is known as the index. The first index is always 0.
For an array of size n, the minimum valid index is 0 and the maximum valid index is n-1.

We can access items in the array using the subscript operator [ ].

C-style traditional arrays

Form: TYPE ARRAYNAME[ SIZE ];

  • The SIZE must be an integer literal (5, 10, etc.) or a named constant int. Variables are not allowed (not with every compiler!)
  • The array does not keep track of its own size or how many items are stored within, so we need to track that manually.
const int TOTAL_SUPPLIES = 5;
string school_supplies[ TOTAL_SUPPLIES ];

school_supplies[0] = "Notebook";
school_supplies[1] = "Pencil";
school_supplies[2] = "Highlighter";
school_supplies[3] = "Eraser";
school_supplies[4] = "Day planner";

for ( int i = 0; i < TOTAL_SUPPLIES; i++ )
{
    cout << "Index: " << i;
    cout << "\t Value: " << school_supplies[i] << endl;
}
Index: 0	 Value: Notebook
Index: 1	 Value: Pencil
Index: 2	 Value: Highlighter
Index: 3	 Value: Eraser
Index: 4	 Value: Day planner

C++ STL array

Form: array<TYPE, SIZE> ARRAYNAME;

array<string, 5> school_supplies;

school_supplies[0] = "Notebook";
school_supplies[1] = "Pencil";
school_supplies[2] = "Highlighter";
school_supplies[3] = "Eraser";
school_supplies[4] = "Day planner";

for ( int i = 0; i < school_supplies.size(); i++ )
{
  cout << "Index: " << i;
  cout << "\t Value: " << school_supplies[i] << endl;
}
Index: 0	 Value: Notebook
Index: 1	 Value: Pencil
Index: 2	 Value: Highlighter
Index: 3	 Value: Eraser
Index: 4	 Value: Day planner

C++ STL vector

Form: vector<TYPE> ARRAYNAME;

vector<string> school_supplies;
string input;

while ( true )
{
  cout << "Enter item or STOP to end: ";
  getline( cin, input );

  if ( input == "STOP" ) { break; }
  school_supplies.push_back( input );
}

cout << endl;

for ( int i = 0; i < school_supplies.size(); i++ )
{
  cout << "Index: " << i;
  cout << "\t Value: " << school_supplies[i] << endl;
}
Enter item or STOP to end: Notebook
Enter item or STOP to end: Pencil
Enter item or STOP to end: Highlighter
Enter item or STOP to end: STOP

Index: 0	 Value: Notebook
Index: 1	 Value: Pencil
Index: 2	 Value: Highlighter

C++ dynamic array (pointers!)

Form: TYPE* ARRAYNAME = new TYPE[ SIZE ];
must deallocate manually: delete [] ARRAYNAME;

  • SIZE can be an int variable.
  • Allocate memory with new and deallocate memory with delete.
  • Can reuse pointer after memory deallocation.
int size;
cout << "How many school supplies? ";
cin >> size;
cin.ignore();
cout << endl;

string* school_supplies = new string[ size ];

for ( int i = 0; i < size; i++ )
{
    cout << "Enter item #" << i << ": ";
    getline( cin, school_supplies[i] );
}

cout << endl;
for ( int i = 0; i < size; i++ )
{
    cout << "Index: " << i;
    cout << "\t Value: " << school_supplies[i] << endl;
}

delete [] school_supplies;
How many school supplies? 3

Enter item #0: Highlighters
Enter item #1: Pencils
Enter item #2: Erasers

Index: 0	 Value: Highlighters
Index: 1	 Value: Pencils
Index: 2	 Value: Erasers

Arrays/vectors with objects

When working with objects, we can still access the member variables using the dot operator ., which will come after the subscript operator [ ]

Struct declaration:

struct Product
{
    string name;
    float price;
};

Array of the struct object:

Product store_products[5];

store_products[0].name = "Highlighter";
store_products[0].price = 2.99;

store_products[1].name = "Pencil";
store_products[1].price = 0.75;

cout << store_products[0].name << ", $" << store_products[0].price << endl;
                        

Iterating over array/vector with for loop

We can iterate over our array as long as we know its size. For a "traditional" C array and dynamic array we need to track the size in a named constant/variable, but with array and vector we have the .size() function.

for ( int i = 0; i < SIZE; i++ )
{
    cout << "Index: " << i << "\t";
    cout << "Name:  " << store_products[i].name << "\t";
    cout << "Price: " << store_products[i].price << endl;
}

We can also use range-based for loops to iterate over all the items. However, if we do it this way, we do not have access to the integer, just the element's value:

for ( auto& item : store_products )
{
    cout << "Name:  " << item.name << "\t";
    cout << "Price: " << item.price << endl;
}

Accessing an element with a variable index

We can use integer variables to access an element of an array at some index. This could be useful if we have the user enter an index in the program, then they can access one specific item from the array.

const int SIZE = 4;
string arr[SIZE] = { "Highlighter", "Notebook", "Pencil", "Eraser" };

cout << "Which item do you want to see? ";
int index;
cin >> index;

cout << "That item is: " << arr[index] << endl;
Which item do you want to see? 2
That item is: Pencil

Out of bounds errors

When we have an array of some size, the valid indices are 0 to size-1. If we go outside of bounds of the array, the program will either crash or run into undefined behavior. Because of this, it's important to do error checks to make sure any user-entered indices aren't out of bounds.

const int SIZE = 4;
string arr[SIZE] = { "Highlighter", "Notebook", "Pencil", "Eraser" };

cout << "Which item do you want to see? ";
int index;
cin >> index;

while ( index < 0 || index >= SIZE )
{
    cout << "Invalid index! Try again: ";
    cin >> index;
}

cout << "That item is: " << arr[index] << endl;
                        
Which item do you want to see? 5
Invalid index! Try again: -2
Invalid index! Try again: 1
That item is: Notebook

Accessing a vector's index when nothing allocated

With a vector, remember that it starts at a size of 0. You can't access an element with [ ] if the memory isn't allocated! Make sure the index you're accessing is between 0 and size()-1.

vector<string> arr;
arr.push_back( "Highlighter" ); // 0
arr.push_back( "Notebook" );    // 1
arr.push_back( "Eraser" );      // 2

cout << "Which item do you want to see? ";
int index;
cin >> index;

while ( index < 0 || index >= arr.size() )
{
  cout << "Invalid index! Try again: ";
  cin >> index;
}

cout << "That item is: " << arr[index] << endl;
Which item do you want to see? 5
Invalid index! Try again: -2
Invalid index! Try again: 1
That item is: Notebook

Example code and additional resources

Example code: (repository)

Documentation:

Archived videos: