CSC 161 Grinnell College Spring, 2013
 
Imperative Problem Solving and Data Structures
 
 

Notes on Arrays

The following notes supplement the textbook reading on arrays.

Introduction

Consider the problem of repeated moving a robot and turning right. If the time for moving forward and the amount to turn right is the same throughout the activity, the relevant C code might be:

   int i;
   for (i = 0; i < 5; i++)
      {
          rForward (1.0, 0.5);  /* move forward at full speed for 1/2 second */
          rTurnRight (1.0, 0.5);/* turn right at full speed for 1/2 second */
      }

Although this works fine if the robot is to move the same amount forward and turn the same amount for each iteration. However, if the speed or time will change from one interval to the next, then we would need to store the specific values for each movement. Here is one approach:

  rForward (1.0, 0.5);
  rTurnRight (1.0, 0.5);
  
  rForward (0.75, 0.35);
  rTurnRight (0.6, 0.35);
  
  rForward (0.25, 0.4);
  rTurnRight (0.8, 0.4);
  
  rForward (1.0, 0.5);
  rTurnRight (0.4, 0.5);
  
  rForward (0.45, 0.65);
  rTurnRight (1.0, 0.65);

Although this approach works, the code can be somewhat hard to read, and the approach certainly does not generalize well. For example, in reading this code, it may not be apparent that the time devoted to moving forward is the same as the devoted to turning.

One way to make the code a little clearer would be to introduce variables for the various values:

  double forspeed0 = 1.0;
  double forspeed1 = 0.75;
  double forspeed2 = 0.25;
  double forspeed3 = 1.0;
  double forspeed4 = 0.45;

  double turnspeed0 = 1.0;
  double turnspeed1 = 0.6;
  double turnspeed2 = 0.8;
  double turnspeed3 = 0.4;
  double turnspeed4 = 1.0;

  double time0 = 0.5;
  double time1 = 0.35;
  double time2 = 0.4;
  double time3 = 0.5;
  double time4 = 0.65;

  rForward (forward0, time0);
  rTurnRight (turnspeed0, time0);
  
  rForward (forward1, time1);
  rTurnRight (turnspeed1, time1);
  
  rForward (forward2, time2);
  rTurnRight (turnspeed2, time2);
  
  rForward (forward3, time3);
  rTurnRight (turnspeed3, time3);
  
  rForward (forward4, time4);
  rTurnRight (turnspeed4, time4);

On the positive side, this code clarifies the meaning of the various numbers. On the negative side, this approach continues to be awkward for lengthy sequences of movements.

Arrays

Arrays allow similar types of data to be collected together and accessed using subscripts. For example, the following declarations place the same numbers from above into three arrays:

  double forspeed[5]  = { 1.0, 0.75, 0.25, 1.0, 0.45 };
  double turnspeed[5] = { 1.0, 0.6, 0.8, 0.4, 1.0 }; 
  double time[5]      = { 0.5, 0.35, 0.4, 0.5, 0.65 };

In the declaration for forspeed, the clause [5] indicates that there will be 5 values stored, labeled forspeed[0], forspeed[1], forspeed[2], forspeed[3], and forspeed[4]. Next, the clause = { 1.0, 0.75, 0.25, 1.0, 0.45 } initializes the forspeed array. Similar comments apply to the turnspeed and time arrays.

With these declarations, the above robot motion translates to the following code segment:

  int i;
  for (i = 0; i < 5; i++)
     {
       rForward (forspeed[i], time[i]);
       rTurnRight (turnspeed[i], time[i]);
     }

In this code segment, i takes on successive values 0, 1, ..., 4. Thus, the first time through the loop, i is 0, and the first command becomes

  rForward (forspeed[0], time[0]);

In this context, forspeed[0] is a double, and can be used as any double variable.

Array Declarations

In declaring double forspeed[5], the compiler sets aside space for five double numbers. As this suggests, when an array is first declared, the compiler must know how much space to allocate. The size of any array is determined when it is first declared.

As an alternative to declaring and initializing an array at the same time, arrays may be declared first and then assigned values sometime later:

 double forspeed[5];

  ...

 forspeed[0] = 1.0;
 forspeed[1] = 0.75;
 forspeed[2] = 0.25;
 forspeed[3] = 1.0; 
 forspeed[4] = 0.45;

As still another alternative, we can declare and initialize an array and let the compiler count how large the resulting array should be:

  double forspeed[] = { 1.0, 0.75, 0.25, 1.0, 0.45 };
  double turnspeed[] = { 1.0, 0.6, 0.8, 0.4, 1.0 }; 
  double time[] = { 0.5, 0.35, 0.4, 0.5, 0.65 };

In this setting, we have specified 5 values for each array, so each array will be allocated space for 5 double values.

Warning: The declaration double forspeed[] may seem to allow the array to be flexible in size, but this is an illusion. The C compiler counts the number of items given and allocates that amount of space. In this case, the size of forspeed will be 5, whether or not we specify the array size.

As another variation, we are allowed to allocate a large array and initialize only the first part of it:

  double forspeed[8] = { 1.0, 0.75, 0.25, 1.0, 0.45 };

Here the code allocates space for 8 double numbers, forspeed[0], ... forspeed[7]. The first five of these are initialized. The values of the last three are not specified and could be anything.

On the other hand, while C allows initialization of only part of an array, it does not allow declaration of an array that is too small for the initial values given:

  double forspeed[3] = { 1.0, 0.75, 0.25, 1.0, 0.45 }; 
      /* error:  5 values given, but only space for 3 doubles */

Feedback Welcome

Development of laboratory exercises is an interative process. Prof. Walker welcomes your feedback! Feel free to talk to him during class or stop by his office.