array
sThe following examples demonstrate how to declare, initialize and manipulate array
s.
array
and Using a Loop to Initialize the array
’s ElementsThe program in Fig. 7.3 declares five-element integer array
n
(line 9). Line 5 includes the <array>
header, which contains the definition of class template array
. Lines 12–14 use a for
statement to initialize the array
elements to zeros. Like other non-static
local variables, array
s are not implicitly initialized to zero (static
array
s are). The first output statement (line 16) displays the column headings for the columns printed in the subsequent for
statement (lines 19–21), which prints the array
in tabular format. Remember that setw
specifies the field width in which only the next value is to be output.
In this program, the control variables i
(line 12) and j
(line 19) that specify array
subscripts are declared to be of type size_t
. According to the C++ standard size_t
represents an unsigned integral type. This type is recommended for any variable that represents an array
’s size or an array
’s subscripts. Type size_t
is defined in the std
namespace and is in header <cstddef>
, which is included by various other headers. If you attempt to compile a program that uses type size_t
and receive errors indicating that it’s not defined, simply add #include
<cstddef>
to your program.
array
in a Declaration with an Initializer ListThe elements of an array
also can be initialized in the array
declaration by following the array
name with a brace-delimited comma-separated list of initializers. The program in Fig. 7.4 uses an initializer list to initialize an integer array
with five values (line 9) and prints the array
in tabular format (lines 11–16).
array
ElementsIf there are fewer initializers than array
elements, the remaining array
elements are initialized to zero. For example, the elements of array
n
in Fig. 7.3 could have been initialized to zero with the declaration
array<int, 5> n{}; // initialize elements of array n to 0
which initializes the elements to zero, because there are fewer initializers (none in this case) than array
elements. This technique can be used only in the array
’s declaration, whereas the initialization technique shown in Fig. 7.3 can be used repeatedly during program execution to “reinitialize” an array
’s elements.
array
ElementsIf an initializer list is specified in an array
declaration, the number of initializers must be less than or equal to the array
size. The array
declaration
array<int, 5> n{32, 27, 64, 18, 95, 14};
causes a compilation error, because there are six initializers and only five array
elements.
array
’s Size with a Constant Variable and Setting array
Elements with CalculationsFigure 7.5 sets the elements of a 5-element array
named values
to the even integers 2
, 4
, 6
, 8
and 10
(lines 14–16) and prints the array
in tabular format (lines 18–23). These numbers are generated (line 15) by multiplying each successive value of the loop counter, i
, by 2
and adding 2
.
Line 10 uses the const
qualifier to declare a constant variable arraySize
with the value 5
. Constant variables are also called named constants or read-only variables. A constant variable must be initialized when it’s declared and cannot be modified thereafter. Attempting to modify arraySize
after it’s initialized, as in
arraySize = 7;
results in the following errors1 from Visual C++, GNU C++ and LLVM, respectively:
Visual C++: 'arraySize': you cannot assign to a variable that is const
GNU C++: error: assignment of read-only variable ‘x’
LLVM: Read-only variable is not assignable
Not initializing a constant variable when it’s declared is a compilation error.
Assigning a value to a constant variable in a separate statement from its declaration is a compilation error.
Defining the size of an array
as a constant variable instead of a literal constant makes programs clearer and easier to update. This technique eliminates so-called magic numbers—numeric values that are not explained. Using a constant variable allows you to provide a name for a literal constant and can help explain the purpose of the value in the program.
array
Often, the elements of an array
represent a series of values to be used in a calculation. For example, if the elements of an array
represent exam grades, a professor may wish to total the elements of the array
and use that sum to calculate the class average for the exam.
The program in Fig. 7.6 sums the values contained in the four-element integer array a
. The program declares, creates and initializes the array
in line 9. The for
statement (lines 13–15) performs the calculations. The values being supplied as initializers for array a
also could be read into the program—for example, from the user at the keyboard or from a file on disk (see Chapter 14, File Processing). For example, the for
statement
for (size_t j{0}; j < a.size(); ++j) {
cin >> a[j];
}
reads one value at a time from the keyboard and stores the value in element a[j]
.
array
Data GraphicallyMany programs present data to users graphically. For example, numeric values are often displayed as bars in a bar chart, with longer bars representing proportionally larger numeric values. One simple way to display numeric data graphically is with a bar chart that shows each numeric value as a bar of asterisks (*
).
Professors often like to examine grade distributions on an exam. A professor might graph the number of grades in each of several categories to visualize the grade distribution. Suppose the grades were 87, 68, 94, 100, 83, 78, 85, 91, 76 and 87. There was one grade of 100, two grades in the 90s, four grades in the 80s, two grades in the 70s, one grade in the 60s and no grades below 60. Our next program (Fig. 7.7) stores this data in an array
of 11 elements, each corresponding to a grade range. For example, n[0]
indicates the number of grades in the range 0–9, n[7]
indicates the number of grades in the range 70–79 and n[10]
indicates the number of grades of 100. The GradeBook
classes that you’ll see in Figs. 7.13 and 7.19 contain code that calculates grade frequencies based on a set of grades. In this example, we initialize the array n
with frequency values.
The program (Fig. 7.7) reads the numbers from the array
and graphs the information as a bar chart, displaying each grade range followed by a bar of asterisks indicating the number of grades in that range. To label each bar, lines 17–25 output a grade range (e.g., "70-79: "
) based on the current value of counter variable i
. The nested for
statement (lines 28–30) outputs the current bar as the appropriate number of asterisks. Note the loop-continuation condition in line 28 (stars < n[i]
). Each time the program reaches the inner for
, the loop counts from 0
up to n[i]
, thus using a value in array
n
to determine the number of asterisks to display. In this example, n[0]
–n[5]
contain zeros because no students received a grade below 60. Thus, the program displays no asterisks next to the first six grade ranges.
array
as CountersSometimes, programs use counter variables to summarize data, such as the results of a survey. In Fig. 6.7, we used separate counters in our die-rolling program to track the number of occurrences of each side of a die as the program rolled the die 60,000,000 times. An array
version of this program is shown in Fig. 7.8. This version also uses the new C++11 random-number generation capabilities that were introduced in Section 6.9.
Figure 7.8 uses the array
frequency
(line 17) to count the occurrences of die value. The single statement in line 21 of this program replaces the entire switch
statement in lines 22–43 of Fig. 6.7. Line 21 uses a random value to determine which frequency
element to
increment during each iteration of the loop. The calculation in line 21 produces a random subscript from 1 to 6, so array
frequency
must be large enough to store six counters. We use a seven-element array
in which we ignore frequency[0]
—it’s clearer to have the die face value 1 increment frequency[1]
than frequency[0]
. Thus, each face value is used directly as a subscript for array
frequency
. We also replace lines 46–51 of Fig. 6.7 by looping through array
frequency
to output the results (Fig. 7.8, lines 27–29).
array
s to Summarize Survey ResultsOur next example uses array
s to summarize the results of data collected in a survey. Consider the following problem statement:
Twenty students were asked to rate on a scale of 1 to 5 the quality of the food in the student cafeteria, with 1 being “awful” and 5 being “excellent.” Place the 20 responses in an integer array
and determine the frequency of each rating.
This is a popular type of array
-processing application (Fig. 7.9). We wish to summarize the number of responses of each rating (that is, 1–5). The array
responses
(lines 14–15) is a 20-element integer array
of the students’ responses to the survey. The array
responses
is declared const
, as its values do not (and should not) change. We use a six-element array
frequency
(line 18) to count the number of occurrences of each response. Each element of the array
is used as a counter for one of the survey responses and is initialized to zero. As in Fig. 7.8, we ignore frequency[0]
.
The first for
statement (lines 22–24) takes the responses one at a time from the array responses
and increments one of the five counters in the frequency
array
(frequency[1]
to frequency[5]
). The key statement in the loop is line 23, which increments the appropriate frequency
counter, depending on the value of responses[answer]
.
Let’s consider several iterations of the for
loop. When control variable answer
is 0
, the value of responses[answer]
is the value of responses[0]
(i.e., 1
in line 15), so the program interprets ++frequency[responses[answer]]
as
++frequency[1]
which increments the value in array
element 1. To evaluate the expression in line 23, start with the value in the innermost set of square brackets (answer
). Once you know answer
’s value (which is the value of the control variable in line 22), plug it into the expression and evaluate the expression in the next outer set of square brackets (i.e., responses[answer]
, which is a value selected from the responses
array
in lines 14–15). Then use the resulting value as the subscript for the frequency
array
to specify which counter to increment.
When answer
is 1
, responses[answer]
is the value of responses[1]
, which is 2
, so the program interprets ++frequency[responses[answer]]
as
++frequency[2]
which increments array
element 2.
When answer
is 2
, responses[answer]
is the value of responses[2]
, which is 5
, so the program interprets ++frequency[responses[answer]]
as
++frequency[5]
which increments array
element 5, and so on. Regardless of the number of responses processed in the survey, the program requires only a six-element array
(ignoring element zero) to summarize the results, because all the response values are between 1 and 5 and the subscript values for a six-element array
are 0 through 5.
array
SubscriptsIf the data in responses
contained an invalid value, such as 13, the program would have attempted to add 1
to frequency[13]
, which is outside the bounds of the array
. When you use the []
operator to access an array element, C++ provides no automatic array
bounds checking to prevent you from referring to an element that does not exist. Thus, an executing program can “walk off” either end of an array
without warning. In Section 7.10, we demonstrate the class template vector
’s at
member function, which performs bounds checking for you. Class template array
also has an at
member function.
It’s important to ensure that every subscript you use to access an array
element is within the array
’s bounds—that is, greater than or equal to 0 and less than the number of array
elements.
Allowing programs to read from or write to array
elements outside the bounds of array
s are common security flaws. Reading from out-of-bounds array
elements can cause a program to crash or even appear to execute correctly while using bad data. Writing to an out-of-bounds element (known as a buffer overflow) can corrupt a program’s data in memory, crash a program and allow attackers to exploit the system and execute their own code. For more information on buffer overflows, see http://en.wikipedia.org/wiki/Buffer_overflow
.
Referring to an element outside the array
bounds is an execution-time logic error, not a syntax error.
When looping through an array
, the index should never go below 0 and should always be less than the total number of array
elements (one less than the size of the array
). Make sure that the loop-termination condition prevents accessing elements outside this range. In Section 7.5, you’ll learn about the range-based for
statement, which can help prevent accessing elements outside an array’s (or other container’s) bounds.
array
s and Automatic Local array
sChapter 6 discussed the storage-class specifier static
. A static
local variable in a function definition exists for the program’s duration but is visible only in the function’s body.
We can apply static
to a local array
declaration so that it’s not created and initialized each time the program calls the function and is not destroyed each time the function terminates. This can improve performance, especially when using large array
s.
A program initializes static
local array
s when their declarations are first encountered. If a static
array
is not initialized explicitly by you, each element of that array
is initialized to zero by the compiler when the array
is created. Recall that C++ does not perform such default initialization for other local variables.
Figure 7.10 demonstrates functions staticArrayInit
(lines 23–40) with a static
local array
(line 25) and automaticArrayInit
(lines 43–60) with an automatic local array
(line 45)—local variables are sometimes called automatic variables because they’re automatically destroyed when the function finishes executing.
Function staticArrayInit
is called twice (lines 13 and 17). The static
local array1
is initialized to zero by the compiler the first time the function is called. The function prints the array
’s elements, then adds 5 to and prints each element again. The second time the function is called, the static
array
contains the modified values stored during the first function call. Function automaticArrayInit
also is called twice (lines 14 and 18). Automatic local array2
’s elements are initialized (line 45) with the values 1, 2 and 3. The function prints the array
, adds 5 to each element and prints the array
again. The second time the function is called, the array
elements are reinitialized to 1, 2 and 3. The array
is recreated and reinitialized during each call to automaticArrayInit
.