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 */
