11.1 Initializing Arrays
11.1 Initializing Arrays
11. Arrays
An array is a series of elements of the same type placed in contiguous memory locations that
can be individually referenced by adding an index to a unique identifier.
That means that, for example, five values of type int can be declared as an array without
having to declare 5 different variables (each with its own identifier). Instead, using an array,
the five int values are stored in contiguous memory locations, and all five can be accessed
using the same identifier, with the proper index.
For example, an array containing 5 integer values of type int called foo could be represented
as:
where each blank panel represents an element of the array. In this case, these are values of
type int. These elements are numbered from 0 to 4, being 0 the first and 4 the last; In C++,
the first element in an array is always numbered with a zero (not a one), no matter its length.
Like a regular 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 type (such as int, float...), name is a valid identifier and the elements
field (which is always enclosed in square brackets []), specifies the length of the array in terms
of the number of elements.
Therefore, the foo array, with five elements of type int, can be declared as:
1
Arrays
But the elements in an array can be explicitly initialized to specific values when it is declared,
by enclosing those initial values in braces {}. For example:
The number of values between braces {} shall not be greater than the number of elements in
the array. For example, in the example above, foo was declared having 5 elements (as
specified by the number enclosed in square brackets, [ ]), and the braces { } contained exactly
5 values, one for each element. If declared with less, the remaining elements are set to their
default values (which for fundamental types, means they are filled with zeroes). For example:
This statement declares an array that can be represented like this:
This creates an array of five int values, each initialized with a value of zero:
When an initialization of values is provided for an array, C++ allows the possibility of leaving
the square brackets empty [ ]. In this case, the compiler will assume automatically a size for
the array that matches the number of values included between the braces { }:
After this declaration, array foo would be 5 int long, since we have provided 5 initialization
values.
Finally, the evolution of C++ has led to the adoption of universal initialization also for arrays.
Therefore, there is no longer need for the equal sign between the declaration and the
initializer. Both these statements are equivalent:
2
Arrays
Static arrays, and those declared directly in a namespace (outside any function), are always
initialized. If no explicit initializer is specified, all the elements are defaultinitialized (with
zeroes, for fundamental types).
name[index]
Following the previous examples in which foo had 5 elements and each of those elements was
of type int, the name which can be used to refer to each element is the following:
For example, the following statement stores the value 75 in the third element of foo:
and, for example, the following copies the value of the third element of foo to a variable called
x:
x = foo[2];
Notice that the third element of foo is specified foo[2], since the first one is foo[0], the second
one is foo[1], and therefore, the third one is foo[2]. By this same reason, its last element is
foo[4]. Therefore, if we write foo[5], we would be accessing the sixth element of foo, and
therefore actually exceeding the size of the array.
In C++, it is syntactically correct to exceed the valid range of indices for an array. This can
create problems, since accessing outofrange elements do not cause errors on compilation, but
can cause errors on runtime. The reason for this being allowed will be seen in a later chapter
when pointers are introduced.
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 different tasks: one is to specify the size
of arrays when they are declared; and the second one is to specify indices for concrete array
3
Arrays
elements when they are accessed. Do not confuse these two possible uses of brackets [] with
arrays.
The main difference is that the declaration is preceded by the type of the elements, while the
access is not.
foo[0] = a;
foo[a] = 75;
b = foo [a+2];
foo[foo[a]] = foo[2] + 5;
For example:
// arrays example
#include <iostream> 12206
using namespace std;
int main ()
{
for ( n=0 ; n<5 ; ++n )
{
result += foo[n];
}
cout << result;
return 0;
}
4
Arrays
jimmy represents a bidimensional array of 3 per 5 elements of type int. The C++ syntax for
this is:
and, for example, the way to reference the second element vertically and fourth horizontally in
an expression would be:
jimmy[1][3]
Multidimensional arrays are not limited to two indices (i.e., two dimensions). They can
contain as many indices as needed. Although be careful: the amount of memory needed for an
array increases exponentially with each dimension. For example:
declares an array with an element of type char for each second in a century. This amounts to
more than 3 billion char! So this declaration would consume more than 3 gigabytes of
memory!
At the end, multidimensional arrays are just an abstraction for programmers, since the same
results can be achieved with a simple array, by multiplying its indices:
With the only difference that with multidimensional arrays, the compiler automatically
remembers the depth of each imaginary dimension. The following two pieces of code produce
the exact same result, but one uses a bidimensional array while the other uses a simple array:
5
Arrays
None of the two code snippets above produce any output on the screen, but both assign values
to the memory block called jimmy in the following way:
Note that the code uses defined constants for the width and height, instead of using directly
their numerical values. This gives the code a better readability, and allows changes in the code
to be made easily in one place.
To accept an array as parameter for a function, the parameters can be declared as the array
type, but with empty brackets, omitting the actual size of the array. For example:
This function accepts a parameter of type "array of int" called arg. In order to pass to this
function an array declared as:
6
Arrays
procedure (myarray);
// arrays as parameters
#include <iostream> 5 10 15
using namespace std; 2 4 6 8 10
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);
}
In the code above, the first parameter (int arg[]) accepts any array whose elements are of type
int, whatever its length. For that reason, we have included a second parameter that tells the
function the length of each array that we pass to it as its first parameter. This allows the for
loop that prints out the array to know the range to iterate in the array passed, without going
out of range.
In a function declaration, it is also possible to include multidimensional arrays. The format for
a tridimensional array parameter is:
base_type[][depth][depth]
Notice that the first brackets [ ] are left empty, while the following ones specify sizes for their
respective dimensions. This is necessary in order for the compiler to be able to determine the
depth of each additional dimension.
7
Arrays
In a way, passing an array as argument always loses a dimension. The reason behind is that,
for historical reasons, arrays cannot be directly copied, and thus what is really passed is a
pointer. This is a common source of errors for novice programmers. Although a clear
understanding of pointers, explained in a coming chapter, helps a lot.
is an array that can store up to 20 elements of type char. It can be represented as:
Therefore, this array has a capacity to store sequences of up to 20 characters. But this capacity
does not need to be fully exhausted: the array can also accommodate shorter sequences. For
example, at some point in a program, either the sequence "Hello" or the sequence "Merry
Christmas" can be stored in foo, since both would fit in a sequence with a capacity for 20
characters.
In this case, the array of 20 elements of type char called foo can be represented storing the
character sequences "Hello" and "Merry Christmas" as:
Notice how after the content of the string itself, a null character ('\0') has been added in order
to indicate the end of the sequence. The panels in gray color represent char elements with
undetermined values.
8
Arrays
The above declares an array of 6 elements of type char initialized with the characters that form
the word "Hello" plus a null character '\0' at the end.
But arrays of character elements have another way to be initialized: using string literals
directly.
In the expressions used in some examples in previous chapters, string literals have already
shown up several times. These are specified by enclosing the text between double quotes (").
For example:
Sequences of characters enclosed in doublequotes (") are literal constants. And their type is, in
fact, a nullterminated array of characters. This means that string literals always have a null
character ('\0') automatically appended at the end.
Therefore, the array of char elements called myword can be initialized with a nullterminated
sequence of characters by either one of these two statements:
In both cases, the array of characters myword is declared with a size of 6 elements of type char:
the 5 characters that compose the word "Hello", plus a final null character ('\0'), which
specifies the end of the sequence and that, in the second case, when using double quotes (") it
is appended automatically.
Please notice that here we are talking about initializing an array of characters at the moment it
is being declared, and not about assigning values to them later (once they have already been
declared). In fact, because string literals are regular arrays, they have the same restrictions as
these, and cannot be assigned values.
9
Arrays
Expressions (once myword has already been declared as above), such as:
myword = "Bye";
myword[] = "Bye";
This is because arrays cannot be assigned values. Note, though, that each of its elements can
be assigned a value individually. For example, this would be correct:
myword[0] = 'B';
myword[1] = 'y';
myword[2] = 'e';
myword[3] = '\0';
In the standard library, both representations for strings (Cstrings and library strings) coexist,
and most functions requiring strings are overloaded to support both.
For example, cin and cout support nullterminated sequences directly, allowing them to be
directly extracted from cin or inserted into cout, just like strings. For example:
int main ()
{
char question1[] = "What is your name? ";
string question2 = "Where do you live? ";
char answer1 [80];
10
Arrays
string answer2;
cout << question1;
cin >> answer1;
cout << question2;
cin >> answer2;
cout << "Hello, " << answer1;
cout << " from " << answer2 << "!\n";
return 0;
}
In this example, both arrays of characters using nullterminated sequences and strings are
used. They are quite interchangeable in their use together with cin and cout, but there is a
notable difference in their declarations: arrays have a fixed size that needs to be specified
either implicit or explicitly when declared; question1 has a size of exactly 20 characters
(including the terminating nullcharacters) and answer1 has a size of 80 characters; while
strings are simply strings, no size is specified. This is due to the fact that strings have a
dynamic size determined during runtime, while the size of arrays is determined on
compilation, before the program runs.
In any case, nullterminated character sequences and strings are easily transformed from one
another:
Nullterminated character sequences can be transformed into strings implicitly, and strings can
be transformed into nullterminated character sequences by using either of string's member
functions c_str or data:
11