Two-dimensional Arrays

If this is a required lab, you should answer questions (and write or modify code as needed) for questions/problems 1 through 8 inclusive. You may skip questions 9 and 10 (although they are fun). You may do questions 11 and 12 for extra credit.

You do NOT need to email anything to the grader account. Write or print your answers and code to hand in.

Working with Tables

  1. Copy city-precipitation.c to your account, compile it, and run it.
    1. How is the precip array declared and initialized?
      • What do the notations [NUM_DAYS] and [NUM_CITIES] represent?
      • How are the initial values for each row specified?
      • Could the number of rows be omitted (e.g., precip[][NUM_CITIES])? (An explanation is given later in this lab)
      • Could the number of columns be omitted (e.g., precip[NUM_DAYS][])? (An explanation is given later in this lab)
    2. How are the rows and columns referenced and printed? (Note that nested loops are common in processing a 2D array or table.)
    3. How is the array precip passed from the main procedure to computeCityPrecip?
    4. How is the 2D array specified in the signature for computeCityPrecip?
      • Could the number of rows be omitted (e.g., rain[][NUM_CITIES])? (An explanation is given later in this lab)
      • Could the number of columns be omitted (e.g., rain[NUM_DAYS][])? (An explanation is given later in this lab)
    5. How does processing proceed in computeCityPrecip and why? Explain briefly.
  2. Expand city-precipitation.c to add a function computeDayPrecip that computes and returns the total precipitation in all cities for a given day, given the day number (e.g., 0 through NUM_DAYS-1).
    • The function should have the following signature:
      double
      computeDayPrecip (double rain[NUM_DAYS][NUM_CITIES], int day);
    • The function should not print anything, but simply compute and return the desired value. (Printing should be done in the main procedure, where formatting needs for the output are known.)
    • Use the function within the main program by adding a column to the printed table (you do not need to modify the array) and also by adding a new section at the bottom of the output.
  3. As a separate section in the main program, use function computeCityPrecip to determine the city with the greatest amount of precipitation over the time range covered by the table.
  4. Write a function computeTotalPrecipitation that takes the precipitation array as a parameter and returns the total amount of precipitation from all of the cities over the full timespan covered by the table. Again, the procedure should compute and return the total, but printing should be done in the main program.

Experiments with Table Storage

  1. The layout of a table in memory impacts what data are accessed when a subscript is out of range, as illustrated in these experiments with the program city-precipitation.c from earlier in this lab.
    1. In city-precipitation.c, add a printf statement at the end of program to check that the table entry precip[5][5] gives the amount of rain for Seattle, WA on December 23.
    2. What values are printed when you change the entries to precip[5][6] and precip[5][8]? Explain why these values are printed, based on the layout of memory.
    3. What values are printed for precip[6][0] and precip[6][-1]? Again, explain why these values are obtained.
  2. Make a new copy of city-precipitation.c calling it city-precipitation-alt.c and change the declaration of the precip array to allow space for another city.
    1. Change the NUM_CITIES definition by one so it looks like the following:
      #define NUM_CITIES 7
      Do not change the initialization of the precip array, so values are given for 6 cities, even though space is allocated for 7 cities.
    2. What values are printed for the extra city? What can you hypothesize about how rows are initialized, if not all data are given to complete a row?
    3. Repeat Steps 5a, 5b, and 5c with this larger array. Explain what is printed.

Declaring Two-dimensional Arrays

The layout of a table in memory requires the computer to know the width of a table. Without knowing the width (number of columns), the location of entry table[i][j] cannot be computed. This is illustrated further in the following exercises.

  1. The following program will not compile. Copy the program 2D-array.c and look the various array declarations.

    The program is intended to print out the sizes (in bytes) of each of the valid arrays and all of their rows one by one. Note that an integer is 4 bytes, and arrays in the program are arrays of integers. Thus, to find the size of an array the program multiplies how many integers are in the array by the size of an integer, which is 4 bytes. This is why you get 4 times the number of things there are in the array.

    1. Which array declarations are invalid and preventing the program from compiling? Do you see a pattern of when it is invalid? Comment out the lines that are not working.
    2. Write comments next to each array indicating the size (in bytes) of the whole array is and what the size of each row is?
    3. How many elements does each array hold?
    4. Write loops to display the contents of each remaining array. You should use separate nested for loops for each array.
    5. Verify how many elements each array holds.
    6. Add another array, array6, which has the numbers (0, 1, 2, 3) in the first row, (2, 4, 6, 8) in the second row, and (3, 6, 9, 12) in the third row. Display the array once you have declared and initialized it.
  2. Returning to your modified program city-precipitation-alt.c and try making the following changes one by one. After making one change, revert to the original code before making the next change.
    Parameter(s) for computeCityPrecip Call in main
    (double rain[][6], int cityNum) (precip, col)
    (double rain[8][], int cityNum) (precip, col)
    (double rain[][], int cityNum) (precip, col)
    (int numCities, double rain[][numCities], int cityNum) (6, precip, col)
    (double rain[][numCities], int numCities, int cityNum) (precip, 6, col)
    In each case, indicate why the code works, or why the compiler generates an error message.

More Experiments with Declarations

  1. Consider the following code:
    int rabbit[2][3] = { 1, 2, 3, 4, 5, 6 };
    int r, c;
    
    for (r = 0; r < 2; r++)
      for (c = 0; c < 3; c++)
        printf ("rabbit[%d,%d] = %d\n", r, c, rabbit[r][c]);
    1. What do you expect to happen when you try to compile this code inside of a main() method?
    2. Check your answer experimentally.
    3. What do you expect to happen when you try to run this code?
    4. Check your answer experimentally.
  2. Now replace your display loops with the following code:
    for (c = 0; c < 3; c++)
      for (r = 0; r < 2; r++)
          printf ("rabbit[%d,%d] = %d\n", r, c, rabbit[r][c]);
    1. What do you expect to happen when you try to run this code?
    2. Check your answer experimentally.
    What is going on here is that two dimensional arrays are actually stored in memory as 1D arrays, laid out row after row. (As noted earlier, this is called row-major form.) This allows some convience when processing entire arrays. For example, we can store a Picture type as a two-dimensional array of Pixels and write functions that treats the Pixel[][] array as a 1D Pixel array. We expand this application in the next reading.

For Those With Extra Time ......

Inter-City Distances (May be turned in either individually or with your partner for 6 extra credit points)

Consider the following table that shows the distance, in miles, between eight cities in Iowa. (All distances are reported by the Iowa Department of Transportation.)

Cedar Rapids Council Bluffs Davenport Des Moines Grinnell Iowa City Mason City Sioux City
Cedar Rapids 245 72 114 71 24 134 273
Council Bluffs 245 301 131 182 242 238 95
Davenport 72 301 171 118 56 206 341
Des Moines 114 131 171 51 114 120 194
Grinnell 71 182 118 51 63 127 232
Iowa City 24 242 56 114 63 153 291
Mason City 134 238 206 120 127 153 204
Sioux City 273 95 341 194 232 291 204
  1. Write a program that
    • stores the names of the cities in a char * array,
    • stores the city distances in a 2-dimensional array,
    • prints the table,
    • computes the average distance from each city to all of the other cities,
    • prints the name of the city with the smallest average distance to the other cities,
    • prints the name of the city with the largest average distance to the other cities,
    • finds the maximum distance in the table, and prints names of the the two cities with that distance, and
    • asks the user to enter two city names and prints the distance between those cities.

  2. Step 11 asks you to store the cities in a char * array. Rewrite the program, so the cities are stored in a 2-dimensional array instead. That is, each row of the table will contain text for a city, and the letters will fill in the columns of each row.

    Notes:

    • You can make a series of spaces print by using a command such as printf("%*c", 13, ' ') to print a set of 13 spaces in order to get the first row of the table to align correctly.
    • Council Bluffs is the longest name. Counting the null character at the end of the string, this name requires space for at least 15 characters.
    • Changing a city char * array to a two-dimensional array will require editing only about 6 characters in your program. All of the rest of the program can remain unchanged!