Objects First |
If all we could do in a C program was identify single objects, then many
programs would become extremely painful! For example, suppose we want to plot a
graph with 100 points: if we had to make our declaration like this:
double x0, x1, x2, x3, x4, ..., x99;
double y0, y1, y2, y3, y4, ..., y99;
Then not only will our fingers become rather tired just creating the
program, but we will become somewhat less than enthusiastic when someone asks us
to change the program to handle a 1000-point graph. Fortunately, C allows us to
declare an array:
/* Define a constant for the size of the array */
#define N 100
double x[N], y[N];
and to access elements of the array:
for(i=0;i<N;i++)
y[i] = f( x[i] );
which places in the elements of the array,
y, the value of
f(x)
evaluated at the points contained in the array,
x.
The declaration of an array consists of an identifier or name followed by square
brackets which enclose an expression giving the number of elements of an array.
Since the number of elements is given by an expression, we can use
declarations like:
int xy[N+1];
double y[M+5*N];
However, the expression must be able to be evaluated by the compiler, so
that all components of the expression must be able to be evaluated when the
program is compiled - there must be no unknowns! This means that the expression
must be composed of constants: so that in the examples above, identifiers
consisting of upper case letters have been used - the convention for symbols
defined with
#define directives.
x[4] a[j+1] blocks[4*i+k] table[f(i,j,k+m)]This expression is called the array index. In the last expression, a function, f, has been invoked to calculate the array index: this example was chosen to re-iterate that the index is an expression and that any legal expression will be accepted. However, it should be obvious that the expression must produce an integer result: in the example, f must be an int with specification:
int f( some_type1 i, some_type2 j, some_type3 k );Floating point expressions are not accepted by the compiler.
Rectangle rects[N];defines an array of N Rectangle objects. (The value of N will be supplied by a #define somewhere in the program.) The elements of rects are numbered from 0 to N-1. Thus the following expressions accessing elements of rects are sensible:
/* Give N a value so that the examples are concrete! */ #define N 20 Rectangle rects[N]; rects[0] rects[3] rects[9] rects[i*j+k] /* i*j+k evaluates to 5 */ rects[N-10] rects[N-1]but the following are not:
rects[-1] rects[N-21] rects[N+20] rects[N]The last example causes the most problems for new C programmers: you must remember that C array indices start at 0. Thus for an array with N elements, the last elements has index N-1. It may help to think of the array index as an offset from the beginning of the array, so that the first element (at offset 0 from the beginning) is rects[0] and the last must be at offset N-1 - rects[N-1].
| Warning
Unfortunately C never checks whether the array index is valid - either at compile time or when the program is running. Thus expressions like rects[N] are happily accepted by the compiler. (C compilers usually make the assumption that programmers know what they are doing!) The results of running such programs are entirely unpredictable, since the space at the end of the array may have arbitrary data in it. The results from your program may even vary from one run to another as the space in which the compiler assumes the (N+1)th Rectangle object is stored may well have been allocated to some other object. |
int x = 45; double y = 101.23; char c = 'A';When an array is declared, it may also be given a set of initial values:
int x[3] = {45, 0, 3 };
double y[5] = {1.,2.,4.,101.23,-34.3};
char c[4] = {'A','B','C','D'};
The initial values are provided as a comma separated list of values enclosed
in braces - {}.
This is particularly useful for setting up look-up
tables in programs:
for example a Date
class might contain an array giving the
number of days in each month:
int days_in_month[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
int days_to_first_of_month[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
There are many situations where we would like to construct tables (with rows and columns) or matrices with two dimensions. C allows us to declare arrays with more than one dimension by simply adding further dimensions in square brackets:
int a[N][M]; char c[N_ITEMS][LENGTH]; double m[N_ROWS][N_COLS];
Elements from these arrays are addressed or accessed with expressions that also have the second index in square brackets following the first:
a[i][j+1]; c[k][0]; m[0][N_COLS-1];
As before the index can be any expression that produces an integer result.
There are some further traps that await you when using arrays:
int b[N]; int c[M][P];
we can write
b
which is the address of b[0] and
c[3]
which is the address of the 4th row: remember that C indices start at 0, so that c[0] is the address of the first row of c.
These addresses are also known as pointers. We will meet pointers and all the traps they provide for you in a later section!
double sum( double a[], int n );Note the use of the empty square brackets [] to indicate a singly-dimensioned array of unspecified size. This allows us to write library functions which work on arrays of all sizes. In this example, we build a function that sums the elements of all singly-dimensioned double arrays, no matter how many elements they have.
The implementation is:
double sum( double a[], int n ) {
double s = 0.0;
int i;
for(i=0;i<n;i++) s = s + a[i];
return s;
}
we might invoke this function:
double x[N]; for(j=0;j<N;j++) x[j] = j; sum_ints = sum( x, N );
Key terms |
| Continue on to Loops | Back to the Table of Contents |