I l @ ve RuBoard |
Tempest Cloud, a weather person who takes her subject cirrusly, wants to analyze 5 years of monthly rainfall data. One of her first decisions is how to represent the data. One choice is to use 60 variables , one for each data item. (We mentioned this choice once before, and it is as senseless now as it was then.) Using an array with 60 elements would be an improvement, but it would be nicer still if she could keep each year's data separate. She could use five arrays, each with 12 elements, but that is clumsy and could get really awkward if Tempest decides to study 50 years' worth of rainfall instead of 5. She needs something better.
The better approach is to use an array of arrays. The master array would have five elements, one for each year. Each of those elements, in turn , would be a 12-element array, one for each month. This is how to declare such an array:
float rain[5][12]; /* array of 5 arrays of 12 floats */
You can also visualize this rain array as a two-dimensional array consisting of five rows, each of 12 columns , as shown in Figure 10.3. By changing the second subscript, you move along a row, month by month. By changing the first subscript, you move vertically along a column, year by year.
The two-dimensional view is merely a convenient way of visualizing an array with two indices. Internally, such an array is stored sequentially, beginning with the first 12-element array, followed by the second 12-element array, and so on.8
Let's use this two-dimensional array in a weather program. The program goal is to find the total rainfall for each year, the average yearly rainfall, and the average rainfall for each month. To find the total rainfall for a year, you have to add all the data in a given row. To find the average rainfall for a given month, you have to add all the data in a given column. The two-dimensional array makes it easy to visualize and execute these activities. Listing 10.12 shows the program.
/* rain.c -- finds yearly totals, yearly average, and monthly average for several years of rainfall data */ #include <stdio.h> #define MONTHS 12 /* number of months in a year */ #define YRS 5 /* number of years of data */ int main(void) { /* initializing rainfall data for 1990 - 1994 */ const float rain[YRS][MONTHS] = { {10.2, 8.1, 6.8, 4.2, 2.1, 1.8, 0.2, 0.3, 1.1, 2.3, 6.1, 7.4}, {9.2, 9.8, 4.4, 3.3, 2.2, 0.8, 0.4, 0.0, 0.6, 1.7, 4.3, 5.2}, {6.6, 5.5, 3.8, 2.8, 1.6, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 4.2}, {4.3, 4.3, 4.3, 3.0, 2.0, 1.0, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6}, {8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.2} }; int year, month; float subtot, total; printf(" YEAR RAINFALL (inches)\n"); for (year = 0, total = 0; year < YRS; year++) { /* for each year, sum rainfall for each month */ for (month = 0, subtot = 0; month < MONTHS; month++) subtot += rain[year][month]; printf("%5d %15.1f\n", 1990 + year, subtot); total += subtot; /* total for all years */ } printf("\nThe yearly average is %.1f inches.\n\n", total/YRS); printf("MONTHLY AVERAGES:\n\n"); printf(" Jan Feb Mar Apr May Jun Jul Aug Sep Oct "); printf(" Nov Dec\n"); for (month = 0; month < MONTHS; month++) { /* for each month, sum rainfall over years */ for (year = 0, subtot =0; year < YRS; year++) subtot += rain[year][month]; printf("%4.1f ", subtot/YRS); } printf("\n"); return 0; }
Here is the output:
YEAR RAINFALL (inches) 1990 50.6 1991 41.9 1992 28.6 1993 32.2 1994 37.8 The yearly average is 38.2 inches. MONTHLY AVERAGES: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 7.8 7.2 4.1 3.0 2.1 0.8 1.2 0.3 0.5 1.7 3.6 6.1
As you study this program, concentrate on the initialization and on the computation scheme. The initialization is the more involved of the two, so let's look at the computation first.
To find the total for a given year, keep year constant and let month go over its full range. This is the inner for loop of the first part of the program. Then repeat the process for the next value of year . This is the outer loop of the first part of the program. A nested loop structure like this one is natural for handling a two-dimensional array. One loop handles the first subscript, and the other loop handles the second subscript.
The second part of the program has the same structure, but now it changes year with the inner loop and month with the outer. Remember, each time the outer loop cycles once, the inner loop cycles its full allotment. Therefore, this arrangement cycles through all the years before changing months. You get a 5-year average for the first month, and so on.
For the initialization, we included five embraced lists of numbers, all enclosed by one outer set of braces. The data in the first interior set of braces is assigned to the first row of the array, the data in the second interior set goes to the second row, and so on. The rules we discussed about mismatches between data and array sizes apply to each row. That is, if the first inner set of braces encloses 10 numbers, only the first 10 elements of the first row are affected. The last two elements in that row are then initialized by default to zero. If there are too many numbers, it is an error; the numbers do not get shoved into the next row.
We could have left out the interior braces and just retained the two outermost braces. As long as you have the right number of entries, the effect is the same. If you are short of entries, however, the array is filled sequentially row by row until the data runs out. Then the remaining elements are initialized to . Figure 10.4 shows both ways of initializing an array.
Because the rain array holds data that should not be modified, the program uses the const modifier when declaring the array.
Everything we have said about two-dimensional arrays can be generalized to three-dimensional arrays and further. You can declare a three-dimensional array this way:
int box[10][20][30];
You can visualize this array as 10 two-dimensional arrays (each 20 — 30) stacked atop each other, or you can think of it as an array of arrays of arrays. That is, it is a 10-element array, each element of which is a 20-element array. Each 20-element array then has elements that are 30-element arrays. Or you can simply think of arrays in terms of the number of indices needed. We'll stick to two dimensions in our examples.
I l @ ve RuBoard |