CSC 161 Schedule Readings Labs & Projects Homework Deadlines Resources

Arrays and the Scribbler 2

This reading supplements the textbook coverage of 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:

for (int 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 might 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 fwdSpeed0 = 1.0;
double fwdSpeed1 = 0.75;
double fwdSpeed2 = 0.25;
double fwdSpeed3 = 1.0;
double fwdSpeed4 = 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 fwdSpeed[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 fwdSpeed, the clause [5] indicates that there will be 5 values stored, labeled fwdSpeed[0], fwdSpeed[1], fwdSpeed[2], fwdSpeed[3], and fwdSpeed[4]. Next, the clause = { 1.0, 0.75, 0.25, 1.0, 0.45 } initializes the fwdSpeed array. Similar comments apply to the turnSpeed and time arrays.

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

for (int i = 0; i < 5; i++)
{
  rForward (fwdSpeed[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 (fwdSpeed[0], time[0]);

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

Array Declarations

In declaring double fwdSpeed[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 fwdSpeed[5];

  ...

fwdSpeed[0] = 1.0;
fwdSpeed[1] = 0.75;
fwdSpeed[2] = 0.25;
fwdSpeed[3] = 1.0; 
fwdSpeed[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 fwdSpeed[] = { 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 fwdSpeed[] 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 fwdSpeed 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 fwdSpeed[8] = { 1.0, 0.75, 0.25, 1.0, 0.45 };

Here the code allocates space for 8 double numbers, fwdSpeed[0], ... fwdSpeed[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 fwdSpeed[3] = { 1.0, 0.75, 0.25, 1.0, 0.45 }; 
/* error:  5 values given, but only space for 3 doubles */