Re: Is the syntax for multi-dimensional arrays counter-intuitive?

From: Lawrence Kirby (lknews_at_netactive.co.uk)
Date: 02/03/05


Date: Thu, 03 Feb 2005 11:11:08 +0000

On Thu, 03 Feb 2005 05:28:55 +0000, A. Bolmarcich wrote:

> ["Followup-To:" header set to comp.lang.c.]
> On 2005-02-03, masood.iqbal@lycos.com <masood.iqbal@lycos.com> wrote:
>> All this time I was under the illusion that I understand the concept of
>> multi-dimensional arrays well ---- however the following code snippet
>> belies my understanding.
>>
>> I had assumed all along that a declaration like:
>> int intArray[3][5]
>> means that there is an array of pointers to int with a size of 5, each
>> of whose elements is an array of int with a size of 3.

There are no pointers here, and pointers don't have elements arrays do.
Pointers point to OTHER objects and there is only one overall object here.
intArray would be laid out in memory as 15 contiguous int objects,
treated as 3 groups of 5 ints. If you output sizeof intArray you'll see it
is 15*sizeof(int).

>> This definition seemed intuitive to me since a declaration like
>> int intVar[5]
>> means that there is an array of integers with a size of 5.

That's fine, but it doesn't suggest anything about pointers in arrays of
arrays. In that case you're just replacing the element type int here with
a different element type that happens itself to be an array. An equivalent
way of defining intArray would be:

typedef int Int5[5];
Int5 intArray[3];

> In C multi-dimensioned arrays are arrays of arrays. With the above
> declarations, intVar in an expression is treated as pointer to an int.
> Similarily, intArray in an expression is treated as a pointer to an
> array of 5 ints.
>
>> In my "intuitive" thinking, to dynamically create a 2D array with 3
>> rows and 5 columns, we would do the following:
>>
>> Allocate memory for 5 pointers to int (i.e. pointer array)
>> For each entry in the pointer array
>> Do
>> Allocate memory for 3 ints
>> Done
>
> In C arrays are stored row-wise; the rightmost subscript varies the
> fastest. If the rightmost dimension is 5, you need to allocte memory
> for 5 ints for each occurrence of the next dimension to the left.
>
> To the designers of C to dynamically create a 2D array with 3 rows
> and 5 columns, you could use
>
> int (*intArray_p)[3][5] = malloc(sizeof(*intArray_p));

But typically you wouldn't, you would use

    int (*intArray_p)[5] = malloc(3 * sizeof *intArray_p);

> to declare and allocate the array and use (*intArray_p)[i][j] to refer
> to the i-th, j-th element.

And then you can refer to the elements using intArray_p[i][j]

> If you know all but the leftmost dimension at compile time, you could
> use
>
> int (*intArray_p)[][5] = malloc(leftDimCount*sizeof(**intArray_p));
>
> to declare and allocate the array and use (*intArray_p)[i][j] to refer
> to the i-th, j-th element.

The simpler version works here too.

> If you know neither of the dimensions at compile time, you could
> use
>
> int *int_p = malloc(leftDimCount*rightDimCount*sizeof(*int_p));
>
> to declare and allocate the array and use int_p[i*rightDimCount + j]
> to refer to the i-th, j-th element.

This is a case where using an intermediate array of pointers can help. If
you do that you can still use the int_p[i][j] syntax for accessing
elements.

>> My code had a bug, which was fixed by switching my logic to something
>> like this (as can be seen from the coding example):
>>
>> Allocate memory for 3 pointers to int (i.e. pointer array)
>
> You want to allocate memory for 3 pointers arrays of 5 ints. However,
> in most implementations a pointer to int and a pointer to and array of
> 5 ints have the same representation.

3 pointers to int is correct. When you access an array using a pointer you
use a pointer to the array's element type. So to access an array of 5 ints
you need a pointer of type pointer to int.

>> For each entry in the pointer array
>> Do
>> Allocate memory for 5 ints
>> Done
>>
>> This indicates to me that the correct interpretation of a declaration
>> like:
>>
>> int intArray[3][5]
>>
>> is that there is an array of pointers to int with a size of 3, each of
>> whose elements is an array of int with a size of 5. Is this a correct
>> interpretation?

Again, there are no pointers involved. You simply have a bunch of int
objects together in memory and the type of intArray supplies the
information the compiler needs to figure out the address of the correct
one by direct offset calculation.

>> This sounds counter intuitive to me (for reasons
>> mentioned above) but I have reconciled to this interpretation. I will
>> jump off the cliff if I am wrong again!

Then make it a very small cliff.

> The correct interpretation is that there is an array of 3 elements, each
> of whose elements is an array of 5 ints. When intArray appears in an
> expression, it is treated as a pointer to its first element, which is
> and array of 5 ints. However, intArray is not stored as an array of
> pointers.
> [snip]

Yes.

Lawrence



Relevant Pages

  • Re: [Lit.] Buffer overruns
    ... &x does not yield the same address as x when x is an array. ... "When two pointers are compared, the result depends on the relative ... tryit.c:6: warning: int format, long int arg ...
    (sci.crypt)
  • Re: performance of accessing array using indexes or pointers
    ... index or using pointers in C. ... int findex(int* array, int size) ...
    (comp.lang.asm.x86)
  • Re: PLEASE HELP - Fundamental C language question
    ... > int* doit{ ... > Since the array intArray is allocated on the stack ... the array intArray is an automatic object. ... At compile time, it doesn't point anywhere, because at compile time the ...
    (comp.lang.c)
  • (patch for Bash) regex case statement
    ... Following up on my previous patch for regex conditional tests, ... /* Return an array of strings; ... int dollarflag, zeropad, compareflag; ... SHELL_VAR *var; ...
    (comp.unix.shell)
  • Re: Strategy or Iterator?
    ... It would be possible to write a class that returns the variations ... GNU General Public License for more details. ... protected CombinatoricOperator(Telements, int r) { ... An integer array backing up the original one to keep track of the ...
    (comp.lang.java.programmer)