pointers to arrays
Chris Torek
chris at mimsy.UUCP
Sat Feb 18 14:32:47 AEST 1989
In article <244 at tityus.UUCP> jim at athsys.uucp (Jim Becker) writes:
>... I wanted to return a pointer to an allocated array of char*
>pointers via a procedure call.
Probably not. You probably wanted a pointer that pointed *at* (not
`to') a block of memory (`array') containing a series of `char *'
objects each pointing at a block of memory containing a series of
`char's. The type of such a pointer is `char **'.
You might ask, `what is the difference between a pointer that points
``at'' a block of memory and one that points ``to'' an array?' The
distinction is somewhat artificial (and I made up the words for some
netnews posting in the past). Given a pointer to array pa:
int a[5];
int (*pa)[5] = &a; /* pANS C semantics for &a */
I can get a pointer that points `at' the array instead:
int *p = &a[0];
The latter is the more `natural' C version of the former: typically
a pointer points at the first element of a group (here 5). The rest
of the group can be reached via pointer arithmetic: *(p+3), aka p[3],
refers to the same location as a[3].
The pointer need not point at the first element, as long as it points
somewhere into the object:
p = &a[2];
Now p[1] refers to a[3]; p[-2] refers to a[0]. To use pa to get at
a[3] one must write (*pa)[3] (or, equivalently, pa[0][3]).
The thing that is most especially confusing, but that really makes
the difference, is that *pa, aka pa[0], refers to the entire array
`a'. *p refers only to one element of the array. This can be seen
in the result produced by `sizeof': (sizeof *p)==(sizeof(int)), but
(sizeof *pa)==(sizeof(int[5]))==(5 * sizeof(int)).
Pointers to entire arrays are not particularly useful unless there
are several arrays:
int twodim[3][5];
Now we can use pa to point to (not at) any of the three array-5-of-int
elements of twodim:
pa = &twodim[1]; /* or pa = twodim + 1, in Classic C */
and now (*pa)[3] (or pa[0][3]) is an alias for twodim[1][3]. Note
especially that since pa[0] names the *entire* array-5-of-int at
twodim[1], pa[-1] names the entire array-5-of-int at twodim[0].
\bold{Pointer arithmetic moves by whole elements, even if those
elements are aggregates.} Thus pa[-1][2] is an alias for twodim[0][2].
This is merely a convenience, for we can do the same with p:
p = &twodim[1][0];
Now p points to the 0'th element of the 1'th element of twodim---the
same place that pa[0][0] names. p[3] is an alias for twodim[1][3]. To
get at twodim[0][2], take p[(-1 * 5) + 2], or p[-3]. Arrays are are
stored in row-major order with the columns concatenated without gaps;
they can be `flattened' (viewed as linear, one-dimensional) with
impunity. (The flattening concept extends to arbitrarily deep
matrices, so that a six-dimensional array can be viewed as a string of
five-D arrays, each of which can be viewed as a string of four-D
arrays, and so forth, all the way down to a string of simple values.%)
Once you understand this, and see why C guarantees that p[-3],
pa[-1][2], and twodim[0][4] are all the same, you are well on your way
to understanding C's memory model (not `paradigm': that means
`example'). You will also see why pa can only point to objects of type
`array 5 of int', not `array 17 of int', and why the size of the array
is required.
-----
% For fun: the six-D array `char big[2][3][5][4][6][10]' occupies
7200 bytes (assuming one byte is one char). If the first byte is at
byte address 0xc400, find the byte address of big[1][0][3][1][5][5].
I hid my answer as a message-ID in the references line.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
More information about the Comp.lang.c
mailing list