home *** CD-ROM | disk | FTP | other *** search
-
- RUN-TIME ARRAYS IN C
-
- Dynamic Allocation and Usage of Array
- Structures Composed during Run-Time Operations
-
- Bill Forseth, Duluth MN
-
- One of the problems frequently faced by programmers is the fact that
- array allocation is a compile-time operation. If the size of an array is
- unknown during the compilation process one usually needs to implement some
- form of linked list, with all the attendant overhead and occasionally
- debugging grief.
-
- This need not be so. Conceptually, an array is a group of like items,
- (or records), with individual elements made available through sub-
- scripting. An array can be passed as a pointer, (which in fact it is),
- which can lead to speedy operations. Arrays need not be traversed, nor do
- they have to be freed. An array element contains only the space needed to
- hold the specified value(s), no pointers to next, last, head, tail, etc.
- nodes.
-
- These basic problems need to be overcome in creating run-time arrays:
- 1. declaring the basic element type
- 2. allocation for the array as a whole
- 3. element accessing
-
- The solution for the first problem, 99 out of a hundred times, is simple
- enough - hard-code the type, perhaps in a header file. For that hundredth
- time, (which we needn't get into for the purposes of this article), C's
- invaluable "sizeof" operator can be used.
-
- For the second problem, an example would be more instructive than my
- words. Given that the type is float, and the need is for an array of N
- elements, (where the value of N is determined, like any other variable, at
- run-time). An array called 'A' can be created with this simple operation:
-
- A = (float)malloc(sizeof(float)*N);
-
- (Note that A should be declared as a POINTER to a float in it's own
- declaration).
-
- Now A points to a memory location containing the number of bytes (in the
- system definition of a float) times N, which is our original working
- definition of an array's memory space.
-
- Number three says we need to solve the element accessibility problem,
- which given C's pointer arithmetic, is efficient and relatively painless.
- To access the i-th element of array A, all we need to do is use this simple
- formula:
-
- *(A + i)
-
- The compiler already knows that A is a float pointer, so *(A + 0) will
- access the first element. *(A + 1) will access the second, and so on.
-
- So far, so good. Now what about multi-dimensional arrays? The theory is
- the same, although the implementation may be a bit more complex.
-
- Problem one stays the same. Problem two demands only one more operation
- in the allocation phase. Say one needed an N by M array. The allocation
- could look like this:
-
- A=(float)malloc(sizeof(float) * N * M);
-
- Now the sticky part - not too bad, yet easy enough to mis-calculate,
- (especially in a computation-heavy program). The solution to number three
- in this case is two fold. First, say we want to access the element normally
- associated in array operations as A[i][j]. For our purposes this becomes:
-
- *(A + (N * i) + j);
-
- Which still doesn't look too bad - until you get a group on the left or
- right hand side of an operation. For that reason, I usually use a macro
- defined as the above. Or more specifically:
-
- #define A_(N,i,j) *(A+(N*i)+j)
-
- If 'N' is a variable globally accessible to all procedures needing to
- access elements, then the #define could be identified as simply:
-
- #define A_(i,j) . . .
-
- Which is much easier to read, and hence debug, than *(A+(N*i)+j).
-
- The same type of operations can be defined for multi-dimension arrays
- bigger that two, (although the memory does tend to get a bit stretched with
- these).