Przejdź do głównej zawartości

Dynamic arrays

In this lesson we'll learn how to use dynamic arrays in C++ using std::vector.

More about vector

You might be wondering why the type that represents a dynamic array data structure in C++ uses the name "vector." It can be confusing for those who associate the term with the mathematical concept of vectors. Interestingly, this name was chosen by the original author of the STL (Standard Template Library), Alexander Stepanov. However, in retrospect, Stepanov admitted that using "vector" as the name of the data structure was a mistake.

vector is one of the many containers in the standard library. You'll learn about other containers gradually as you progress through the course. In this lesson I will often use the term array and vector interchangeably.

Documentation

Once you finish this lesson you can look at the documentation if you want to learn more about vectors. Be aware that the documentation is not a tutorial, but rather a reference and it may be a bit overwhelming at first.

Creating a vector

Let's go back and consider the code we've shown in the Motivation section of the previous lesson. There is a great candidate to be turned into an array. The following variables are of the same type (std::string) and differ only in number at the end of their name.

std::string player_name1;
std::string player_name2;
std::string player_name3;
#include <iostream>
#include <string>

int main()
{
std::string player_name1;
std::string player_name2;
std::string player_name3;

std::cout << "Please enter the name of player 1: ";
std::cin >> player_name1;

std::cout << "Please enter the name of player 2: ";
std::cin >> player_name2;

std::cout << "Please enter the name of player 3: ";
std::cin >> player_name3;
}

Instead of creating three separate variables, we can create one array that contains three elements.

To use std::vector we first have to include its header file:

#include <vector>

As we already know from the Introduction, to create a vector we have to know the type of the elements that will be stored inside it. All elements in a vector are of the same type.

#include <iostream>
#include <string> // do not forget about string
#include <vector>

int main()
{
std::vector<std::string> player_names(3);
// ...
}

The above example shows how to create a vector that stores std::strings.

Convenience

Before we continue, let's put an appropriate using statement at the beginning of the main function block to skip the std:: prefix:

int main() {
using std::vector, std::string;

vector<string> player_names(3);
}

Later we'll use more elements from the standard library, like std::cout and std::cin. You can add these to the using statement too.

vector is a template, which means that it can be used with different types. We tell it which type to use by putting it in angle brackets right after vector. Like this:

Using vector with different types
vector< int > array_of_ints;
vector< float > array_of_floats;
vector< char > array_of_chars;
vector< string > array_of_strings;
vector< /*other type*/ > array_of_xyz;

This code defines the vector player_names that stores text elements (std::strings):

Defining a variable of vector type
vector<string> player_names(3);

Writing (3) after player_names makes it so that when it is created it will have room for three elements of type string right from the beginning.

Storing 3 elements in the vector
player_names(3)

Note that this is a vector-specific thing and not a general rule. If you want to create a vector that is initially empty, just don't write the parentheses at all:

Creating an empty vector
vector<string> player_names;
Empty parentheses problem

A mistake that is often made by beginners is to write empty parentheses when creating a vector (or actually any other type):

This is not defining a variable
vector< string > player_names();

Later in the course you'll learn about functions, and the syntax that declares them:

This is actually a function declaration
// prism-push-types:AnyType
AnyType function_name();

This is why the empty parentheses turns this into a function declaration, which is not what we want.

Accessing elements

There are two ways of accessing an element of a vector, that we're interested in:

Both ways are very similar, with the only difference being that the [] operator does not check if the index is out of bounds. We'll show you what this means in a moment. Now let's see how we can use them - we'll assign the following names to the players:

Player indexName
0HappyBanana
1AngryCrab
2SadWolf

Here is how we can set them in the code:

#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names(3);

// Setting names of the players
player_names[0] = "HappyBanana";
player_names[1] = "AngryCrab";
player_names[2] = "SadWolf";

// Printing the name of the first player:
cout << "Name of the first player: " << player_names[0];
}
Output
Name of the first player: HappyBanana

To access an element of an array, we put its index in square brackets right after the array name:

arrayName[ index ]

A non-empty array with a number of elements equal to N always has indexes ranging from 0 to N-1 inclusive. The three-element array player_names has indexes 0, 1 and 2.

Out of bounds access

A very common mistake is to try to access an element with an index that is out of bounds. If we had tried to rename the player at index 3 the program would most likely crash and burn.

player_names[3] = "NewPlayer"; // !

This code will compile correctly (we might get a warning) but when the program is executed it will try to access a memory that is not allocated for the program. This is called a buffer overflow and it is a very serious problem.

An alternative, safer way of accessing an element is to use the at() method:

player_names.at( 3 ) = "NewPlayer";

The difference is that the at() method checks if the index is out of bounds and throws an exception if it is. Be aware that it won't make your program valid by itself. The key benefit is that it will show you a useful error message and won't allow the program to perform a potentially dangerous operation.

We'll learn more about the syntax we used to call the at() method in a moment.

Example

This is how we can ask a user to enter the name of a certain player:

cout << "Enter the name of the second player: ";
cin >> player_names[1];

Now let's output the number of characters in the provided name:

cout << "The name of the second player has " << player_names[1].size() << " characters.\n";
Possible output
Enter the name of the second player: FuriousFlamingo
The name of the second player has 15 characters.

Providing initial values

There is also a way to provide initial values for the elements of the vector right from the beginning:

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Printing the name of the first player:
cout << "Name of the first player: " << player_names[0];
}
Alternative syntax

In the case of initializing a vector you can also omit the = sign:

Alternative syntax
vector<string> player_names { // note the lack of '='
"HappyBanana",
"AngryCrab",
"SadWolf",
};

The result is the same.

We will use this method of initialization in the current lesson from now on.

Adding elements at the end

To add an item to the end of an array (in this case player_names), we need to use push_back like this:

player_names.push_back("WickedWitch");

// Printing the name of player with index 3
cout << "Name of the player with index 3: " << player_names[3];
Output
Name of the player with index 3: WickedWitch
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

// Printing the name of player with index 3
cout << "Name of the player with index 3: " << player_names[3];
}

From the moment .push_back(...) instruction was executed, the player_names array already has four elements. We say that we are calling the push_back(...) method. We'll talk more about calls and methods in the future. For now, just remember that:

  1. we put a dot after the name of the array
  2. we write the name of the method, which is in this case push_back
  3. then in parentheses we enter what we want to add (e.g. a value or a variable)

Note that after we added the new element, the array has four elements, with indices 0, 1, 2 and 3:

Before:

IndexName
0HappyBanana
1AngryCrab
2SadWolf

After:

IndexName
0HappyBanana
1AngryCrab
2SadWolf
3WickedWitch

To let the user add a new player, we can ask them to enter their name, and then add it to the array:

std::cout << "Enter the name of the new player: ";
std::string new_player_name;
std::cin >> new_player_name;
player_names.push_back(new_player_name);

Inserting elements at a specific position

At this point you will have to trust me a little. I won't go into details because it's too complicated for now. To insert before index n to a vector (in this case player_names) we use the following notation:

player_names.insert(player_names.begin() + n, elementToInsert);

Simply put, insert adds an element just before a specified position

which isn't the same thing as an index. To obtain it, we need to use begin() and add the index to it.

Knowing this, we will now insert a new player just before the AngryCrab (index 1):

player_names.insert(player_names.begin() + 1, "BadPenguin");
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

player_names.insert(player_names.begin() + 1, "BadPenguin");

// Printing the name of player with index 1
cout << "Name of the player with index 1: " << player_names[1];
}

This is how the array changes after the insertion:

Before:

IndexName
0HappyBanana
1AngryCrab
2SadWolf
3WickedWitch

After:

IndexName
0HappyBanana
1BadPenguin
2AngryCrab
3SadWolf
4WickedWitch

Removing elements

This is a similar case to inserting elements. We need to specify a position again. So to remove the n-th element from a vector (e.g. from player_names) we will use the following notation:

Erasing n-th element from player_names
player_names.erase( player_names.begin() + n );

We'll now erase the first player from the array:

player_names.erase( player_names.begin() + 0 );
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

player_names.insert(player_names.begin() + 1, "BadPenguin");

// Erase the first element:
player_names.erase(player_names.begin() + 0);

// Printing the name of player with index 1
cout << "Name of the player with index 1: " << player_names[1];
}

Note that in this case + 0 actually does nothing, but I put it there to make it clear: player_names.begin() is the same as player_names.begin() + 0.

The contents of the array before and after the removal:

Before:

IndexName
0HappyBanana <-- gets deleted
1BadPenguin
1AngryCrab
2SadWolf
3WickedWitch

After:

IndexName
0BadPenguin
1AngryCrab
2SadWolf
3WickedWitch

As you can see the first element was removed and the rest of the elements shifted by one index. This is because the array is a contiguous block of memory and vector ensures that there is no empty space left after an element is removed.

uwaga

Before erasing an item from an array, make sure it exists (that is, it's in scope [0, N)).

Deleting n-th element from an array (safe)
int index;
cin >> index; // don't forget to add using std::cin;

if (index >= 0 && index < player_names.size())
{
player_names.erase( player_names.begin() + index );
}
else
cout << "Index " << index << " does not exist!";

Clearing the contents

To clear the contents of a vector, we can use the clear() method:

player_names.clear();

After the call, the array will be empty.

Reading the size

Because vector can change size whenever you want it to, you may sometimes need to read the number of elements it currently contains. The current size can be read using the size() method:

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

cout << "The array contains " << player_names.size() << " elements\n";

// Adding a new player:
player_names.push_back("WickedWitch");
cout << "Added new player.\n";
cout << "The array contains " << player_names.size() << " elements\n";
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

cout << "The array contains " << player_names.size() << " elements\n";

// Adding a new player:
player_names.push_back("WickedWitch");
cout << "Added new player.\n";
cout << "The array contains " << player_names.size() << " elements\n";

player_names.insert(player_names.begin() + 1, "BadPenguin");

// Erase the first element:
player_names.erase(player_names.begin() + 0);
}
Output
The array contains 3 elements
Added new player.
The array contains 4 elements

Just like we previously did with the method push_back, we write the name after the dot. Then we put the parentheses, and in the case of .size we leave them empty.

Checking if vector is empty

To check if a vector is empty, we can use the empty() method like this:

if (player_names.empty())
cout << "The array is empty!\n";
else
cout << "The array is not empty!\n";
}

Displaying elements

If we want to display all the elements of an array, we'll have to use a loop. We will tell more about loops in the future. They allow you to execute the same piece of code multiple times.

Displaying items
for (string name : player_names)
{
cout << "Player name: " << name << '\n';
}
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

// Print each player's name
for (string name : player_names)
{
cout << name << '\n';
}
}
Output
Player name: HappyBanana
Player name: AngryCrab
Player name: SadWolf
Player name: WickedWitch

To understand this, let me show you how to "read" it:

For (for) each player name (name) which is of a type std::string in an array player_names execute the following block of code...

There is only one statement inside this block of code:

cout << "Player name: " << name << '\n';

The loop will write the nicknames of the players one by one into the variable name, and execute the display instruction (cout) for each of them.

Summary

We learned how to do basic operations on std::vector type. Make sure to check out the sublessons because there is still a lot to practice. You can find them in the sidebar if you expand the "Dynamic arrays" item.

Dynamic arrays

In this lesson we'll learn how to use dynamic arrays in C++ using std::vector.

More about vector

You might be wondering why the type that represents a dynamic array data structure in C++ uses the name "vector." It can be confusing for those who associate the term with the mathematical concept of vectors. Interestingly, this name was chosen by the original author of the STL (Standard Template Library), Alexander Stepanov. However, in retrospect, Stepanov admitted that using "vector" as the name of the data structure was a mistake.

vector is one of the many containers in the standard library. You'll learn about other containers gradually as you progress through the course. In this lesson I will often use the term array and vector interchangeably.

Documentation

Once you finish this lesson you can look at the documentation if you want to learn more about vectors. Be aware that the documentation is not a tutorial, but rather a reference and it may be a bit overwhelming at first.

Creating a vector

Let's go back and consider the code we've shown in the Motivation section of the previous lesson. There is a great candidate to be turned into an array. The following variables are of the same type (std::string) and differ only in number at the end of their name.

std::string player_name1;
std::string player_name2;
std::string player_name3;
#include <iostream>
#include <string>

int main()
{
std::string player_name1;
std::string player_name2;
std::string player_name3;

std::cout << "Please enter the name of player 1: ";
std::cin >> player_name1;

std::cout << "Please enter the name of player 2: ";
std::cin >> player_name2;

std::cout << "Please enter the name of player 3: ";
std::cin >> player_name3;
}

Instead of creating three separate variables, we can create one array that contains three elements.

To use std::vector we first have to include its header file:

#include <vector>

As we already know from the Introduction, to create a vector we have to know the type of the elements that will be stored inside it. All elements in a vector are of the same type.

#include <iostream>
#include <string> // do not forget about string
#include <vector>

int main()
{
std::vector<std::string> player_names(3);
// ...
}

The above example shows how to create a vector that stores std::strings.

Convenience

Before we continue, let's put an appropriate using statement at the beginning of the main function block to skip the std:: prefix:

int main() {
using std::vector, std::string;

vector<string> player_names(3);
}

Later we'll use more elements from the standard library, like std::cout and std::cin. You can add these to the using statement too.

vector is a template, which means that it can be used with different types. We tell it which type to use by putting it in angle brackets right after vector. Like this:

Using vector with different types
vector< int > array_of_ints;
vector< float > array_of_floats;
vector< char > array_of_chars;
vector< string > array_of_strings;
vector< /*other type*/ > array_of_xyz;

This code defines the vector player_names that stores text elements (std::strings):

Defining a variable of vector type
vector<string> player_names(3);

Writing (3) after player_names makes it so that when it is created it will have room for three elements of type string right from the beginning.

Storing 3 elements in the vector
player_names(3)

Note that this is a vector-specific thing and not a general rule. If you want to create a vector that is initially empty, just don't write the parentheses at all:

Creating an empty vector
vector<string> player_names;
Empty parentheses problem

A mistake that is often made by beginners is to write empty parentheses when creating a vector (or actually any other type):

This is not defining a variable
vector< string > player_names();

Later in the course you'll learn about functions, and the syntax that declares them:

This is actually a function declaration
// prism-push-types:AnyType
AnyType function_name();

This is why the empty parentheses turns this into a function declaration, which is not what we want.

Accessing elements

There are two ways of accessing an element of a vector, that we're interested in:

Both ways are very similar, with the only difference being that the [] operator does not check if the index is out of bounds. We'll show you what this means in a moment. Now let's see how we can use them - we'll assign the following names to the players:

Player indexName
0HappyBanana
1AngryCrab
2SadWolf

Here is how we can set them in the code:

#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names(3);

// Setting names of the players
player_names[0] = "HappyBanana";
player_names[1] = "AngryCrab";
player_names[2] = "SadWolf";

// Printing the name of the first player:
cout << "Name of the first player: " << player_names[0];
}
Output
Name of the first player: HappyBanana

To access an element of an array, we put its index in square brackets right after the array name:

arrayName[ index ]

A non-empty array with a number of elements equal to N always has indexes ranging from 0 to N-1 inclusive. The three-element array player_names has indexes 0, 1 and 2.

Out of bounds access

A very common mistake is to try to access an element with an index that is out of bounds. If we had tried to rename the player at index 3 the program would most likely crash and burn.

player_names[3] = "NewPlayer"; // !

This code will compile correctly (we might get a warning) but when the program is executed it will try to access a memory that is not allocated for the program. This is called a buffer overflow and it is a very serious problem.

An alternative, safer way of accessing an element is to use the at() method:

player_names.at( 3 ) = "NewPlayer";

The difference is that the at() method checks if the index is out of bounds and throws an exception if it is. Be aware that it won't make your program valid by itself. The key benefit is that it will show you a useful error message and won't allow the program to perform a potentially dangerous operation.

We'll learn more about the syntax we used to call the at() method in a moment.

Example

This is how we can ask a user to enter the name of a certain player:

cout << "Enter the name of the second player: ";
cin >> player_names[1];

Now let's output the number of characters in the provided name:

cout << "The name of the second player has " << player_names[1].size() << " characters.\n";
Possible output
Enter the name of the second player: FuriousFlamingo
The name of the second player has 15 characters.

Providing initial values

There is also a way to provide initial values for the elements of the vector right from the beginning:

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Printing the name of the first player:
cout << "Name of the first player: " << player_names[0];
}
Alternative syntax

In the case of initializing a vector you can also omit the = sign:

Alternative syntax
vector<string> player_names { // note the lack of '='
"HappyBanana",
"AngryCrab",
"SadWolf",
};

The result is the same.

We will use this method of initialization in the current lesson from now on.

Adding elements at the end

To add an item to the end of an array (in this case player_names), we need to use push_back like this:

player_names.push_back("WickedWitch");

// Printing the name of player with index 3
cout << "Name of the player with index 3: " << player_names[3];
Output
Name of the player with index 3: WickedWitch
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

// Printing the name of player with index 3
cout << "Name of the player with index 3: " << player_names[3];
}

From the moment .push_back(...) instruction was executed, the player_names array already has four elements. We say that we are calling the push_back(...) method. We'll talk more about calls and methods in the future. For now, just remember that:

  1. we put a dot after the name of the array
  2. we write the name of the method, which is in this case push_back
  3. then in parentheses we enter what we want to add (e.g. a value or a variable)

Note that after we added the new element, the array has four elements, with indices 0, 1, 2 and 3:

Before:

IndexName
0HappyBanana
1AngryCrab
2SadWolf

After:

IndexName
0HappyBanana
1AngryCrab
2SadWolf
3WickedWitch

To let the user add a new player, we can ask them to enter their name, and then add it to the array:

std::cout << "Enter the name of the new player: ";
std::string new_player_name;
std::cin >> new_player_name;
player_names.push_back(new_player_name);

Inserting elements at a specific position

At this point you will have to trust me a little. I won't go into details because it's too complicated for now. To insert before index n to a vector (in this case player_names) we use the following notation:

player_names.insert(player_names.begin() + n, elementToInsert);

Simply put, insert adds an element just before a specified position

which isn't the same thing as an index. To obtain it, we need to use begin() and add the index to it.

Knowing this, we will now insert a new player just before the AngryCrab (index 1):

player_names.insert(player_names.begin() + 1, "BadPenguin");
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

player_names.insert(player_names.begin() + 1, "BadPenguin");

// Printing the name of player with index 1
cout << "Name of the player with index 1: " << player_names[1];
}

This is how the array changes after the insertion:

Before:

IndexName
0HappyBanana
1AngryCrab
2SadWolf
3WickedWitch

After:

IndexName
0HappyBanana
1BadPenguin
2AngryCrab
3SadWolf
4WickedWitch

Removing elements

This is a similar case to inserting elements. We need to specify a position again. So to remove the n-th element from a vector (e.g. from player_names) we will use the following notation:

Erasing n-th element from player_names
player_names.erase( player_names.begin() + n );

We'll now erase the first player from the array:

player_names.erase( player_names.begin() + 0 );
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

player_names.insert(player_names.begin() + 1, "BadPenguin");

// Erase the first element:
player_names.erase(player_names.begin() + 0);

// Printing the name of player with index 1
cout << "Name of the player with index 1: " << player_names[1];
}

Note that in this case + 0 actually does nothing, but I put it there to make it clear: player_names.begin() is the same as player_names.begin() + 0.

The contents of the array before and after the removal:

Before:

IndexName
0HappyBanana <-- gets deleted
1BadPenguin
1AngryCrab
2SadWolf
3WickedWitch

After:

IndexName
0BadPenguin
1AngryCrab
2SadWolf
3WickedWitch

As you can see the first element was removed and the rest of the elements shifted by one index. This is because the array is a contiguous block of memory and vector ensures that there is no empty space left after an element is removed.

uwaga

Before erasing an item from an array, make sure it exists (that is, it's in scope [0, N)).

Deleting n-th element from an array (safe)
int index;
cin >> index; // don't forget to add using std::cin;

if (index >= 0 && index < player_names.size())
{
player_names.erase( player_names.begin() + index );
}
else
cout << "Index " << index << " does not exist!";

Clearing the contents

To clear the contents of a vector, we can use the clear() method:

player_names.clear();

After the call, the array will be empty.

Reading the size

Because vector can change size whenever you want it to, you may sometimes need to read the number of elements it currently contains. The current size can be read using the size() method:

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

cout << "The array contains " << player_names.size() << " elements\n";

// Adding a new player:
player_names.push_back("WickedWitch");
cout << "Added new player.\n";
cout << "The array contains " << player_names.size() << " elements\n";
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

cout << "The array contains " << player_names.size() << " elements\n";

// Adding a new player:
player_names.push_back("WickedWitch");
cout << "Added new player.\n";
cout << "The array contains " << player_names.size() << " elements\n";

player_names.insert(player_names.begin() + 1, "BadPenguin");

// Erase the first element:
player_names.erase(player_names.begin() + 0);
}
Output
The array contains 3 elements
Added new player.
The array contains 4 elements

Just like we previously did with the method push_back, we write the name after the dot. Then we put the parentheses, and in the case of .size we leave them empty.

Checking if vector is empty

To check if a vector is empty, we can use the empty() method like this:

if (player_names.empty())
cout << "The array is empty!\n";
else
cout << "The array is not empty!\n";
}

Displaying elements

If we want to display all the elements of an array, we'll have to use a loop. We will tell more about loops in the future. They allow you to execute the same piece of code multiple times.

Displaying items
for (string name : player_names)
{
cout << "Player name: " << name << '\n';
}
#include <iostream>
#include <string>
#include <vector>

int main()
{
using std::vector, std::string, std::cout;

vector<string> player_names = {
"HappyBanana",
"AngryCrab",
"SadWolf",
};

// Adding a new player:
player_names.push_back("WickedWitch");

// Print each player's name
for (string name : player_names)
{
cout << name << '\n';
}
}
Output
Player name: HappyBanana
Player name: AngryCrab
Player name: SadWolf
Player name: WickedWitch

To understand this, let me show you how to "read" it:

For (for) each player name (name) which is of a type std::string in an array player_names execute the following block of code...

There is only one statement inside this block of code:

cout << "Player name: " << name << '\n';

The loop will write the nicknames of the players one by one into the variable name, and execute the display instruction (cout) for each of them.

Summary

We learned how to do basic operations on std::vector type. Make sure to check out the sublessons because there is still a lot to practice. You can find them in the sidebar if you expand the "Dynamic arrays" item.