This section presents many examples that demonstrate how to declare arrays, how to initialize arrays and how to perform many common array manipulations.
Declaring an Array and Using a Loop to Initialize the Array's Elements
The program in Fig. 7.3 declares 10-element integer array n (line 12). Lines 1516 use a for statement to initialize the array elements to zeros. The first output statement (line 18) displays the column headings for the columns printed in the subsequent for statement (lines 2122), which prints the array in tabular format. Remember that setw specifies the field width in which only the next value is to be output.
Figure 7.3. Initializing an array's elements to zeros and printing the array.
(This item is displayed on page 331 in the print version)
1 // Fig. 7.3: fig07_03.cpp 2 // Initializing an array. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 int main() 11 { 12 int n[ 10 ]; // n is an array of 10 integers 13 14 // initialize elements of array n to 0 15 for ( int i = 0; i < 10; i++ ) 16 n[ i ] = 0; // set element at location i to 0 17 18 cout << "Element" << setw( 13 ) << "Value" << endl; 19 20 // output each array element's value 21 for ( int j = 0; j < 10; j++ ) 22 cout << setw( 7 ) << j << setw( 13 ) << n[ j ] << endl; 23 24 return 0; // indicates successful termination 25 } // end main
|
Initializing an Array in a Declaration with an Initializer List
The elements of an array also can be initialized in the array declaration by following the array name with an equals sign and a comma-separated list (enclosed in braces) of initializers. The program in Fig. 7.4 uses an initializer list to initialize an integer array with 10 values (line 13) and prints the array in tabular format (lines 1519).
Figure 7.4. Initializing the elements of an array in its declaration.
(This item is displayed on pages 331 - 332 in the print version)
1 // Fig. 7.4: fig07_04.cpp 2 // Initializing an array in a declaration. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 int main() 11 { 12 // use initializer list to initialize array n 13 int n[ 10 ] = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37 }; 14 15 cout << "Element" << setw( 13 ) << "Value" << endl; 16 17 // output each array element's value 18 for ( int i = 0; i < 10; i++ ) 19 cout << setw( 7 ) << i << setw( 13 ) << n[ i ] << endl; 20 21 return 0; // indicates successful termination 22 } // end main
|
If there are fewer initializers than elements in the array, 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
int n[ 10 ] = { 0 }; // initialize elements of array n to 0
The declaration explicitly initializes the first element to zero and implicitly initializes the remaining nine elements to zero, because there are fewer initializers than elements in the array. Automatic arrays are not implicitly initialized to zero although static arrays are. The programmer must at least initialize the first element to zero with an initializer list for the remaining elements to be implicitly set to zero. The initialization method shown in Fig. 7.3 can be performed repeatedly as a program executes.
If the array size is omitted from a declaration with an initializer list, the compiler determines the number of elements in the array by counting the number of elements in the initializer list. For example,
int n[] = { 1, 2, 3, 4, 5 };
creates a five-element array.
If the array size and an initializer list are specified in an array declaration, the number of initializers must be less than or equal to the array size. The array declaration
int n[ 5 ] = { 32, 27, 64, 18, 95, 14 };
causes a compilation error, because there are six initializers and only five array elements.
Common Programming Error 7.2
Providing more initializers in an array initializer list than there are elements in the array is a compilation error. |
Common Programming Error 7.3
Forgetting to initialize the elements of an array whose elements should be initialized is a logic error. |
Specifying an Array's Size with a Constant Variable and Setting Array Elements with Calculations
Figure 7.5 sets the elements of a 10-element array s to the even integers 2, 4, 6, ..., 20 (lines 1718) and prints the array in tabular format (lines 2024). These numbers are generated (line 18) by multiplying each successive value of the loop counter by 2 and adding 2.
Figure 7.5. Generating values to be placed into elements of an array.
1 // Fig. 7.5: fig07_05.cpp 2 // Set array s to the even integers from 2 to 20. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 int main() 11 { 12 // constant variable can be used to specify array size 13 const int arraySize = 10; 14 15 int s[ arraySize ]; // array s has 10 elements 16 17 for ( int i = 0; i < arraySize; i++ ) // set the values 18 s[ i ] = 2 + 2 * i; 19 20 cout << "Element" << setw( 13 ) << "Value" << endl; 21 22 // output contents of array s in tabular format 23 for ( int j = 0; j < arraySize; j++ ) 24 cout << setw( 7 ) << j << setw( 13 ) << s[ j ] << endl; 25 26 return 0; // indicates successful termination 27 } // end main
|
Line 13 uses the const qualifier to declare a so-called constant variable arraySize with the value 10. Constant variables must be initialized with a constant expression when they are declared and cannot be modified thereafter (as shown in Fig. 7.6 and Fig. 7.7). Constant variables are also called named constants or read-only variables.
Figure 7.6. Initializing and using a constant variable.
(This item is displayed on page 334 in the print version)
1 // Fig. 7.6: fig07_06.cpp 2 // Using a properly initialized constant variable. 3 #include 4 using std::cout; 5 using std::endl; 6 7 int main() 8 { 9 const int x = 7; // initialized constant variable 10 11 cout << "The value of constant variable x is: " << x << endl; 12 13 return 0; // indicates successful termination 14 } // end main
|
Figure 7.7. const variables must be initialized.
(This item is displayed on page 334 in the print version)
1 // Fig. 7.7: fig07_07.cpp 2 // A const variable must be initialized. 3 4 int main() 5 { 6 const int x; // Error: x must be initialized 7 8 x = 7; // Error: cannot modify a const variable 9 10 return 0; // indicates successful termination 11 } // end main Borland C++ command-line compiler error message:
Microsoft Visual C++ .NET compiler error message:
GNU C++ compiler error message:
|
Common Programming Error 7.4
Not assigning a value to a constant variable when it is declared is a compilation error. |
Common Programming Error 7.5
Assigning a value to a constant variable in an executable statement is a compilation error. |
Constant variables can be placed anywhere a constant expression is expected. In Fig. 7.5, constant variable arraySize specifies the size of array s in line 15.
Common Programming Error 7.6
Only constants can be used to declare the size of automatic and static arrays. Not using a constant for this purpose is a compilation error. |
Using constant variables to specify array sizes makes programs more scalable. In Fig. 7.5, the first for statement could fill a 1000-element array by simply changing the value of arraySize in its declaration from 10 to 1000. If the constant variable arraySize had not been used, we would have to change lines 15, 17 and 23 of the program to scale the program to handle 1000 array elements. As programs get larger, this technique becomes more useful for writing clearer, easier-to-modify programs.
Software Engineering Observation 7.1
Defining the size of each array as a constant variable instead of a literal constant can make programs more scalable. |
Good Programming Practice 7.2
Defining the size of an array as a constant variable instead of a literal constant makes programs clearer. This technique eliminates so-called magic numbers. For example, repeatedly mentioning the size 10 in array-processing code for a 10-element array gives the number 10 an artificial significance and can unfortunately confuse the reader when the program includes other 10s that have nothing to do with the array size. |
Summing the Elements of an 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 examples using class GradeBook later in the chapter, namely Figs. 7.167.17 and Figs. 7.237.24, use this technique.
The program in Fig. 7.8 sums the values contained in the 10-element integer array a. The program declares, creates and initializes the array at line 10. The for statement (lines 1415) performs the calculations. The values being supplied as initializers for array a also could be read into the program from the user at the keyboard, or from a file on disk (see Chapter 17, File Processing). For example, the for statement
for ( int j = 0; j < arraySize; j++ ) cin >> a[ j ];
reads one value at a time from the keyboard and stores the value in element a[ j ].
Figure 7.8. Computing the sum of the elements of an array.
(This item is displayed on pages 335 - 336 in the print version)
1 // Fig. 7.8: fig07_08.cpp 2 // Compute the sum of the elements of the array. 3 #include 4 using std::cout; 5 using std::endl; 6 7 int main() 8 { 9 const int arraySize = 10; // constant variable indicating size of array 10 int a[ arraySize ] = { 87, 68, 94, 100, 83, 78, 85, 91, 76, 87 }; 11 int total = 0; 12 13 // sum contents of array a 14 for ( int i = 0; i < arraySize; i++ ) 15 total += a[ i ]; 16 17 cout << "Total of array elements: " << total << endl; 18 19 return 0; // indicates successful termination 20 } // end main
|
Using Bar Charts to Display Array Data Graphically
Many programs present data to users in a graphical manner. For example, numeric values are often displayed as bars in a bar chart. In such a chart, longer bars represent 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 the distribution of grades 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. Note that 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.9) stores this grade distribution data in an array of 11 elements, each corresponding to a category of grades. For example, n[ 0 ] indicates the number of grades in the range 09, n[ 7 ] indicates the number of grades in the range 7079 and n[ 10 ] indicates the number of grades of 100. The two versions of class GradeBook later in the chapter (Figs. 7.167.17 and Figs. 7.237.24) contain code that calculates these grade frequencies based on a set of grades. For now, we manually create the array by looking at the set of grades.
Figure 7.9. Bar chart printing program.
(This item is displayed on pages 336 - 337 in the print version)
1 // Fig. 7.9: fig07_09.cpp 2 // Bar chart printing program. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 int main() 11 { 12 const int arraySize = 11; 13 int n[ arraySize ] = { 0, 0, 0, 0, 0, 0, 1, 2, 4, 2, 1 }; 14 15 cout << "Grade distribution:" << endl; 16 17 // for each element of array n, output a bar of the chart 18 for ( int i = 0; i < arraySize; i++ ) 19 { 20 // output bar labels ("0-9:", ..., "90-99:", "100:" ) 21 if ( i == 0 ) 22 cout << " 0-9: "; 23 else if ( i == 10 ) 24 cout << " 100: "; 25 else 26 cout << i * 10 << "-" << ( i * 10 ) + 9 << ": "; 27 28 // print bar of asterisks 29 for ( int stars = 0; stars < n[ i ]; stars++ ) 30 cout << '*'; 31 32 cout << endl; // start a new line of output 33 } // end outer for 34 35 return 0; // indicates successful termination 36 } // end main
|
The program reads the numbers from the array and graphs the information as a bar chart. The program displays each grade range followed by a bar of asterisks indicating the number of grades in that range. To label each bar, lines 2126 output a grade range (e.g., "70-79: ") based on the current value of counter variable i. The nested for statement (lines 2930) outputs the bars. Note the loop-continuation condition at line 29 (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.
Common Programming Error 7.7
Although it is possible to use the same control variable in a for statement and a second for statement nested inside, this is confusing and can lead to logic errors. |
Using the Elements of an Array as Counters
Sometimes, programs use counter variables to summarize data, such as the results of a survey. In Fig. 6.9, 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 6,000,000 times. An array version of this program is shown in Fig. 7.10.
Figure 7.10. Die-rolling program using an array instead of switch.
1 // Fig. 7.10: fig07_10.cpp 2 // Roll a six-sided die 6,000,000 times. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 #include 11 using std::rand; 12 using std::srand; 13 14 #include 15 using std::time; 16 17 int main() 18 { 19 const int arraySize = 7; // ignore element zero 20 int frequency[ arraySize ] = { 0 }; 21 22 srand( time( 0 ) ); // seed random number generator 23 24 // roll die 6,000,000 times; use die value as frequency index 25 for ( int roll = 1; roll <= 6000000; roll++ ) 26 frequency[ 1 + rand() % 6 ]++; 27 28 cout << "Face" << setw( 13 ) << "Frequency" << endl; 29 30 // output each array element's value 31 for ( int face = 1; face < arraySize; face++ ) 32 cout << setw( 4 ) << face << setw( 13 ) << frequency[ face ] 33 << endl; 34 35 return 0; // indicates successful termination 36 } // end main
|
Figure 7.10 uses the array frequency (line 20) to count the occurrences of each side of the die. The single statement in line 26 of this program replaces the switch statement in lines 3052 of Fig. 6.9. Line 26 uses a random value to determine which frequency element to increment during each iteration of the loop. The calculation in line 26 produces a random subscript from 1 to 6, so array frequency must be large enough to store six counters. However, we use a seven-element array in which we ignore frequency[ 0 ]it is more logical to have the die face value 1 increment frequency[ 1 ] than frequency[ 0 ]. Thus, each face value is used as a subscript for array frequency. We also replace lines 5661 of Fig. 6.9 by looping through array frequency to output the results (lines 3133).
Using Arrays to Summarize Survey Results
Our next example (Fig. 7.11) uses arrays to summarize the results of data collected in a survey. Consider the following problem statement:
Forty students were asked to rate the quality of the food in the student cafeteria on a scale of 1 to 10 (1 meaning awful and 10 meaning excellent). Place the 40 responses in an integer array and summarize the results of the poll.
Figure 7.11. Poll analysis program.
(This item is displayed on pages 339 - 340 in the print version)
1 // Fig. 7.11: fig07_11.cpp 2 // Student poll program. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 int main() 11 { 12 // define array sizes 13 const int responseSize = 40; // size of array responses 14 const int frequencySize = 11; // size of array frequency 15 16 // place survey responses in array responses 17 const int responses[ responseSize ] = { 1, 2, 6, 4, 8, 5, 9, 7, 8, 18 10, 1, 6, 3, 8, 6, 10, 3, 8, 2, 7, 6, 5, 7, 6, 8, 6, 7, 19 5, 6, 6, 5, 6, 7, 5, 6, 4, 8, 6, 8, 10 }; 20 21 // initialize frequency counters to 0 22 int frequency[ frequencySize ] = { 0 }; 23 24 // for each answer, select responses element and use that value 25 // as frequency subscript to determine element to increment 26 for ( int answer = 0; answer < responseSize; answer++ ) 27 frequency[ responses[ answer ] ]++; 28 29 cout << "Rating" << setw( 17 ) << "Frequency" << endl; 30 31 // output each array element's value 32 for ( int rating = 1; rating < frequencySize; rating++ ) 33 cout << setw( 6 ) << rating << setw( 17 ) << frequency[ rating ] 34 << endl; 35 36 return 0; // indicates successful termination 37 } // end main
|
This is a typical array-processing application. We wish to summarize the number of responses of each type (i.e., 1 through 10). The array responses (lines 1719) is a 40-element integer array of the students' responses to the survey. Note that array responses is declared const, as its values do not (and should not) change. We use an 11-element array frequency (line 22) 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.10, we ignore frequency[ 0 ].
Software Engineering Observation 7.2
The const qualifier should be used to enforce the principle of least privilege. Using the principle of least privilege to properly design software can greatly reduce debugging time and improper side effects and can make a program easier to modify and maintain. |
Good Programming Practice 7.3
Strive for program clarity. It is sometimes worthwhile to trade off the most efficient use of memory or processor time in favor of writing clearer programs. |
Performance Tip 7.1
Sometimes performance considerations far outweigh clarity considerations. |
The first for statement (lines 2627) takes the responses one at a time from the array responses and increments one of the 10 counters in the frequency array (frequency[ 1 ] to frequency[ 10 ]). The key statement in the loop is line 27, 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 17), so the program interprets frequency[ responses[ answer ] ]++ as
frequency[ 1 ]++
which increments the value in array element 1. To evaluate the expression, start with the value in the innermost set of square brackets (answer). Once you know answer's value (which is the value of the loop control variable in line 26), plug it into the expression and evaluate the next outer set of square brackets (i.e., responses[ answer ], which is a value selected from the responses array in lines 1719). 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 6, so the program interprets frequency[ responses[ answer ] ]++ as
frequency[ 6 ]++
which increments array element 6, and so on. Regardless of the number of responses processed in the survey, the program requires only an 11-element array (ignoring element zero) to summarize the results, because all the response values are between 1 and 10 and the subscript values for an 11-element array are 0 through 10.
If the data in the responses array had 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. C++ has no array bounds checking to prevent the computer from referring to an element that does not exist. Thus, an executing program can "walk off" either end of an array without warning. The programmer should ensure that all array references remain within the bounds of the array.
Common Programming Error 7.8
Referring to an element outside the array bounds is an execution-time logic error. It is not a syntax error. |
Error-Prevention Tip 7.1
When looping through an array, the array subscript should never go below 0 and should always be less than the total number of elements in the array (one less than the size of the array). Make sure that the loop-termination condition prevents accessing elements outside this range. |
Portability Tip 7.1
The (normally serious) effects of referencing elements outside the array bounds are system dependent. Often this results in changes to the value of an unrelated variable or a fatal error that terminates program execution. |
C++ is an extensible language. Section 7.11 presents C++ Standard Library class template vector, which enables programmers to perform many operations that are not available for C++'s built-in arrays. For example, we will be able to compare vectors directly and assign one vector to another. In Chapter 11, we extend C++ further by implementing an array as a user-defined class of our own. This new array definition will enable us to input and output entire arrays with cin and cout, initialize arrays when they are created, prevent access to out-of-range array elements and change the range of subscripts (and even their subscript type) so that the first element of an array is not required to be element 0. We will even be able to use noninteger subscripts.
Error-Prevention Tip 7.2
In Chapter 11, we will see how to develop a class representing a "smart array," which checks that all subscript references are in bounds at runtime. Using such smart data types helps eliminate bugs. |
Using Character Arrays to Store and Manipulate Strings
To this point, we have discussed only integer arrays. However, arrays may be of any type. We now introduce storing character strings in character arrays. Recall that, starting in Chapter 3, we have been using string objects to store character strings, such as the course name in our GradeBook class. A string such as "hello" is actually an array of characters. While string objects are convenient to use and reduce the potential for errors, character arrays that represent strings have several unique features, which we discuss in this section. As you continue your study of C++, you may encounter C++ capabilities that require you to use character arrays in preference to string objects. You may also be asked to update existing code using character arrays.
A character array can be initialized using a string literal. For example, the declaration
char string1[] = "first";
initializes the elements of array string1 to the individual characters in the string literal "first". The size of array string1 in the preceding declaration is determined by the compiler based on the length of the string. It is important to note that the string "first" contains five characters plus a special string-termination character called the null character. Thus, array string1 actually contains six elements. The character constant representation of the null character is '