Section 3.1
Arrays
cplusplus.com

Arrays are a series of elements (variables) of the same type placed consecutively in memory that can be individually referenced by adding an index to a unique name.

That means that, for example, we can store 5 values of type int without having to declare 5 different variables each with a different identifier. Instead, using an array we can store 5 different values of the same type, int for example, with a unique identifier.

For example, an array to contain 5 integer values of type int called billy could be represented this way:

where each blank panel represents an element of the array, that in this case are integer values of type int. These are numbered from 0 to 4 since in arrays the first index is always 0, independently of its length .

Like any other variable, an array must be declared before it is used. A typical declaration for an array in C++ is:

type name [elements];
where type is a valid object type (int, float...), name is a valid variable identifier and the elements field, that is enclosed within brackets [], specifies how many of these elements the array contains.

Therefore, to declare billy as shown above it is as simple as the following sentence:

int billy [5];

NOTE: The elements field within brackets [] when declaring an array must be a constant value, since arrays are blocks of static memory of a given size and the compiler must be able to determine exactly how much memory it must assign to the array before any instruction is considered.

Initializing arrays.

When declaring an array of local scope (within a function), if we do not specify otherwise, it will not be initialized, so its content is undetermined until we store some values in it.

If we declare a global array (outside any function) its content will be initialized with all its elements filled with zeros. Thus, if in the global scope we declare:

int billy [5];
every element of billy will be set initialy to 0:
But additionally, when we declare an Array, we have the possibility to assign initial values to each one of its elements using curly brackets { }. For example:
int billy [5] = { 16, 2, 77, 40, 12071 };
this declaration would have created an array like the following one:
The number of elements in the array that we initialized within curly brackets { } must match the length in elements that we declared for the array enclosed within square brackets [ ]. For example, in the example of the billy array we have declared that it had 5 elements and in the list of initial values within curly brackets { } we have set 5 different values, one for each element.

Because this can be considered useless repetition, C++ includes the possibility of leaving the brackets empty [ ] and the size of the Array will be defined by the number of values included between curly brackets { }:

int billy [] = { 16, 2, 77, 40, 12071 };

Access to the values of an Array.

In any point of the program in which the array is visible we can access individually anyone of its values for reading or modifying as if it was a normal variable. The format is the following:
name[index]
Following the previous examples in which billy had 5 elements and each of those elements was of type int, the name which we can use to refer to each element is the following:
For example, to store the value 75 in the third element of billy a suitable sentence would be:
billy[2] = 75;
and, for example, to pass the value of the third element of billy to the variable a, we could write:
a = billy[2];
Therefore, for all purposes, the expression billy[2] is like any other variable of type int.

Notice that the third element of billy is specified billy[2], since first is billy[0], the second is billy[1], and therefore, third is billy[2]. By this same reason, its last element is billy[4]. Since if we wrote billy[5], we would be acceding to the sixth element of billy and therefore exceeding the size of the array.

In C++ it is perfectly valid to exceed the valid range of indices for an Array, which can create problems since they do not cause compilation errors but they can cause unexpected results or serious errors during execution. The reason why this is allowed will be seen farther ahead when we begin to use pointers.

At this point it is important to be able to clearly distinguish between the two uses that brackets [ ] have related to arrays. They perform two differt tasks: one is to set the size of arrays when declaring them; and second is to specify indices for a concrete array element when referring to it. We must simply take care not to confuse these two possible uses of brackets [ ] with arrays:

int billy[5];         // declaration of a new Array (begins with a type name)
billy[2] = 75;        // access to an element of the Array.

Other valid operations with arrays:

billy[0] = a;
billy[a] = 75;
b = billy [a+2];
billy[billy[a]] = billy[2] + 5;

// arrays example
#include <iostream.h>

int billy [] = {16, 2, 77, 40, 12071};
int n, result=0;

int main ()
{
  for ( n=0 ; n<5 ; n++ )
  {
    result += billy[n];
  }
  cout << result;
  return 0;
}
12206

Multidimensional Arrays


Multidimensional arrays can be described as arrays of arrays. For example, a bidimensional array can be imagined as a bidimensional table of a uniform concrete data type.
jimmy represents a bidimensional array of 3 per 5 values of type int. The way to declare this array would be:
int jimmy [3][5];
and, for example, the way to reference the second element vertically and fourth horizontally in an expression would be:
jimmy[1][3]

(remember that array indices always begin by 0).
Multidimensional arrays are not limited to two indices (two dimensions). They can contain as many indices as needed, although it is rare to have to represent more than 3 dimensions. Just consider the amount of memory that an array with many indices may need. For example:
char century [100][365][24][60][60];
assigns a char for each second contained in a century, that is more than 3 billion chars! This would consume about 3000 megabytes of RAM memory if we could declare it.

Multidimensional arrays are nothing more than an abstraction, since we can obtain the same results with a simple array just by putting a factor between its indices:

int jimmy [3][5];   is equivalent to
int jimmy [15];   (3 * 5 = 15)
with the only difference that the compiler remembers for us the depth of each imaginary dimension. Serve as example these two pieces of code, with exactly the same result, one using bidimensional arrays and the other using only simple arrays:

// multidimensional array
#include <iostream.h>

#define WIDTH 5
#define HEIGHT 3

int jimmy [HEIGHT][WIDTH];
int n,m;

int main ()
{
  for (n=0;n<HEIGHT;n++)
    for (m=0;m<WIDTH;m++)
    {
      jimmy[n][m]=(n+1)*(m+1);
    }
  return 0;
}
// pseudo-multidimensional array
#include <iostream.h>

#define WIDTH 5
#define HEIGHT 3

int jimmy [HEIGHT * WIDTH];
int n,m;

int main ()
{
  for (n=0;n<HEIGHT;n++)
    for (m=0;m<WIDTH;m++)
    {
      jimmy[n * WIDTH + m]=(n+1)*(m+1);
    }
  return 0;
}

none of the programs above produce any output on the screen, but both assign values to the memory block called jimmy in the following way:

We have used defined constants (#define) to simplify possible future modifications of the program, for example, in case that we decided to enlarge the array to a height of 4 instead of 3 it could be done by changing the line:
#define HEIGHT 3
to
#define HEIGHT 4
with no need to make any other modifications to the program.

Arrays as parameters

At some moment we may need to pass an array to a function as a parameter. In C++ is not possible to pass by value a complete block of memory as a parameter to a function, even if it is ordered as an array, but it is allowed to pass its address. This has almost the same practical effect and it is a much faster and more efficient operation.

In order to admit arrays as parameters the only thing that we must do when declaring the function is to specify in the argument the base type for the array, an identifier and a pair of void brackets []. For example, the following function:

void procedure (int arg[])
admits a parameter of type "Array of int" called arg. In order to pass to this function an array declared as:
int myarray [40];
it would be enough to write a call like this:
procedure (myarray);

Here you have a complete example:

// arrays as parameters
#include <iostream.h>

void printarray (int arg[], int length) {
  for (int n=0; n<length; n++)
    cout << arg[n] << " ";
  cout << "\n";
}

int main ()
{
  int firstarray[] = {5, 10, 15};
  int secondarray[] = {2, 4, 6, 8, 10};
  printarray (firstarray,3);
  printarray (secondarray,5);
  return 0;
}
5 10 15
2 4 6 8 10

As you can see, the first argument (int arg[]) admits any array of type int, wathever its length is. For that reason we have included a second parameter that tells the function the length of each array that we pass to it as the first parameter. This allows the for loop that prints out the array to know the range to check in the passed array.

In a function declaration is also possible to include multidimensional arrays. The format for a tridimensional array is:

base_type[][depth][depth]
for example, a function with a multidimensional array as argument could be:
void procedure (int myarray[][3][4])
notice that the first brackets [] are void and the following ones are not. This must always be thus because the compiler must be able to determine within the function which is the depth of each additional dimension.

Arrays, both simple or multidimensional, passed as function parameters are a quite common source of errors for less experienced programmers. I recommend the reading of chapter 3.3, Pointers for a better understanding of how arrays operate.

© The C++ Resources Network, 2000-2003 - All rights reserved

Previous:
2-3. Functions (II).

index
Next:
3-2. Strings of characters.