Introduction
In the previous tutorial, we discussed the various data types available and when to use each one. In this tutorial, we are going to talk about arrays, which allow you store multiple variables of the same data type. We are going to use this to store a description of a maze and create a small game.
Code
So, imagine that you want to write a program to store lottery numbers for the local pick 3 lottery. You could do something like this:
int lottoNumber1 = 1;
int lottoNumber2 = 9;
int lottoNumber3 = 35;
And then you could do something like this to check to see if you are a winner:
bool winner = false;
if (myNumber1 == lottoNumber1 &&
myNumber2 == lottoNumber2 &&
myNumber3 == lottoNumber3)
{
winner = true;
}
Which works fine, until a pick 4 version is to be offered in addition to pick 3. Then the winner check would look something like this:
bool winner = false;
if (myNumber1 == lottoNumber1 &&
myNumber2 == lottoNumber2 &&
myNumber3 == lottoNumber3)
{
if(totalNumbers == 4)
{
if(myNumber4 == lottoNumber4)
{
winner = true;
}
}
else
{
winner = true;
}
}
Now, the code is starting to look really ugly. Especially if we start to think about supporting a 5 and a 6 number version! Fortunately, there is a better way. We can use arrays to store the lotto numbers:
int lottoNumbers[] = { 1, 9, 35 };
This declares an array of integers of integers. The square brackets after the variable name tells the compiler that this is multiple integers, instead of just one. The integers in the curly braces are stored in the array. So, in this case, there are three integers stored in the variable lottoNumbers. So, if we want to access one of the integers in the array, we would do something like this:
cout << lottoNumbers[0] << endl;
cout << lottoNumbers[1] << endl;
cout << lottoNumbers[2] << endl;
This will produce the following result:
1
9
35
So, we use an index (integer within the square brackets) to specify which number that we want. A zero means that we want the first number, which is 1. A one means that we want the second number, which is 9, and so on. It is extremely important to remember that in order to get the nth element in the array, the index is n-1.
At first glance, that might seem pretty silly that the first number is at index zero. Why not have it at index one? The answer lies in how the computer handles arrays. When you say that you want an array with 3 integers in it, the computer searches through its available memory looking for a space large enough to store the 3 integers next to each other. Since integers are 32 bits, the computer needs to find a block 96 unused bits. For a small number of bits like this, the computer won’t have to search for very long, but in the case of very large arrays, it could be difficult or impossible.
When the computer finds a continuous block of bits the size that it needs, it stores the 3 integers it in. So in memory it would look something like this:
Address 1000 | Address 1032 | Address 1064 | Address 1096 | Address 1128 |
<other stuff> | 1 | 9 | 35 | <other stuff> |
Now when the computer stores the array, it only really keeps track of where the array starts, in this case at Address 1032. It can do this because it knows that all of the values in the array are stored next to each other. So if it wants to find the second integer in the array, it knows that it is at:
Address = StartAddress + index * AddressIncrement
In our case the AddressIncrement is 32 bits, since integers are 32 bits. The StartAddress is 1032, so the address of the second item (index = 1) is:
Address = 1032 + 1 * 32 = 1064
So, it is able to find the second element in the array based on where the array starts and an index. So, if you want to think about it this way, the index tells the computer how many elements to skip over in order to find the one that you want. In the case of the first element, you don’t want it to skip over any elements, so its index is zero.
So, getting back to the lotto example, the updated logic to determine whether or not you are a winner looks something like this:
bool winner = true;
for(int i = 0; i < totalNumbers; i++)
{
if(myNumbers[i] != lottoNumbers[i])
{
winner = false;
}
}
And what is great about this code is that it works for any number of lotto numbers! So, now when a 4th, 5th, and 6th number is added to the lotto, all we have to do is update the array sizes to store more numbers and we are done.
Arrays can have multiple dimensions, which allow you to store things like matrices. The code to create a 3x3 array of integers looks like this:
int myNumbers[][3] = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
There really isn’t anything new and exciting here. The only difference is that we have to specify the length of all dimensions after the first one.
Maze Game
Now the fun part. Armed with our knowledge of arrays, let’s build a maze game. First, we need to store the maze that we want the user to solve. Let’s store the maze as a two dimensional array of characters, which would look something like this:
char maze[10][9] = { { '+', '-', '-', '-', '-', '-', '-', '-', '+' },
{ '|', ' ', ' ', ' ', '|', ' ', ' ', ' ', '|' },
{ '|', ' ', '|', ' ', ' ', ' ', '|', ' ', '|' },
{ '|', ' ', '+', '-', '-', '-', '+', ' ', '|' },
{ '|', '#', '|', ' ', ' ', ' ', ' ', ' ', '|' },
{ '|', '-', '+', ' ', '+', ' ', '+', '-', '|' },
{ '|', ' ', ' ', ' ', '|', ' ', '|', ' ', '|' },
{ '|', ' ', '|', ' ', '+', '-', '+', ' ', '|' },
{ '|', '*', '|', ' ', ' ', ' ', ' ', ' ', '|' },
{ '+', '-', '-', '-', '-', '-', '-', '-', '+' } };
Where the * indicates the current location of the player and the # indicates the goal location.
So, the first thing that we are going to want to do is print the board to the user.
void print(char maze[10][9])
{
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 9; j++)
{
cout << maze[i][j];
}
cout << endl;
}
}
After we have that, we need to keep track of the current location of the player (the location of the *). When the game starts, the player is in row 8, column 1. (Remember that arrays indices start at zero!) Once we know where the player is, we can ask the user which direction that they would like to move in. We’ll let the user choose from 5 options: up (‘u’), down (‘d’), left (‘l’), right (‘r’), and quit (‘q’). The code to get the user’s input looks something like this:
char move = ' ';
cout << "Move: ";
while(move != 'u' && move != 'd' && move != 'l' && move != 'r' && move != 'q')
{
cin >> move;
}
Now comes the tricky part. We need to determine if the direction that the user wants to move in is valid or if they are trying to walk into a wall. So, say that the user wants to move up (‘u’), then we would check the square with the same column, but the row higher (row – 1) and see if it is empty. If it is then we want to move the user to that square:
if (move == 'u')
{
if (maze[row - 1][col] == ' ')
{
maze[row][col] = ' ';
row--;
maze[row][col] = '*';
}
else if (maze[row - 1][col] == '#')
{
gameOver = true;
}
}
This is also a good time to check to see if the user has made it to the goal location. That’s pretty much it. We just need to make small modifications for the other directions and we are done. The final code is attached.
Summary
In this tutorial, we introduced arrays, which are a way to store many related values of the same data type. We then used an array of characters to store a maze in and wrote a game where the user has to find their way around the maze.
In the next tutorial, we are going to talk about structures, which are a way to store many related values of different data types.
If you have any questions or comments about what was covered here, post them to the comments. I watch them closely and will respond and try to help you out.