Velocity Reviews > Review: 3D-Array

# Review: 3D-Array

Vijay Kumar R Zanvar
Guest
Posts: n/a

 01-30-2004
Hi c.l.c,

Is this a correct method of allocating a 3-dimensional
array?

/* assume all malloc's succeed */
#define MAT 2
#define ROW 2
#define COL 2

char ***ptr = malloc ( MAT * sizeof *ptr );

for ( i = 0; i < MAT; i++ )
ptr[i] = malloc ( ROW * sizeof **ptr );

for ( i = 0; i < MAT; i++ )
for ( j = 0; j < ROW; j++ )
ptr[i][j] = malloc ( COL * sizeof ***ptr );

Thanks.

--
"When you will be pleased to dine, Mr. Homles?" asked Mrs Hudson,
"At seven thirty, the day after tomorrow." said he invovled in his work.

Sean Kenwrick
Guest
Posts: n/a

 01-30-2004

"Vijay Kumar R Zanvar" <(E-Mail Removed)> wrote in message
news:bvda2p\$qt40s\$(E-Mail Removed)-berlin.de...
> Hi c.l.c,
>
> Is this a correct method of allocating a 3-dimensional
> array?
>
> /* assume all malloc's succeed */
> #define MAT 2
> #define ROW 2
> #define COL 2
>
> char ***ptr = malloc ( MAT * sizeof *ptr );
>
> for ( i = 0; i < MAT; i++ )
> ptr[i] = malloc ( ROW * sizeof **ptr );
>
> for ( i = 0; i < MAT; i++ )
> for ( j = 0; j < ROW; j++ )
> ptr[i][j] = malloc ( COL * sizeof ***ptr );
>
> Thanks.
>

You define a pointer to a pointer to a pointer to a char. So your first
malloc() should create the space for several 'pointer to a pointer to a
char' and make ptr (which is a pointer to a "pointer to a pointer to char"
point to it through the malloc call)

char *** ptr=malloc(MAT * sizeof **ptr);

For each of the entries in this array of pointers to pointers to a char you
now need to point to a 'pointer to a char' type:

for(i=0;i<MAT;i++)
ptr[i]=malloc(ROW * sizeof *ptr);

So now you have a bunch of ROW pointers to chars in each row of the array
ptr[i] so now you must point these to the 'char' (or the first char in an
array of char)

for ( i = 0; i < MAT; i++ )
for ( j = 0; j < ROW; j++ )
ptr[i][j] = malloc ( COL * sizeof char );

You can think of it more clearly like this:

char array[MAT][ROW][COL];

char * array[MAT][ROW]

char ** array[MAT]

char *** array;

In practice the sizeof ***ptr and sizeof ** ptr etc will all be the same.
Therefore what you end up with in your original code is a three dimentional
array of the type char * as follows:

char * array[MAT][ROW][COL];

Which might be what you wanted, but all the char * array entries you created
do not yet point anywhere and when you do point them somewhere you will in
fact end up with a 4 dimensional array like this for example:

char array[MAT][ROW][COL][STRLEN+1];

Hope this helps you clarify this...

Sean

Thes
Guest
Posts: n/a

 01-30-2004

Sean Kenwrick wrote:
> "Vijay Kumar R Zanvar" <(E-Mail Removed)> wrote in message
> news:bvda2p\$qt40s\$(E-Mail Removed)-berlin.de...
>
>>Hi c.l.c,
>>
>> Is this a correct method of allocating a 3-dimensional
>>array?
>>
>>/* assume all malloc's succeed */
>>#define MAT 2
>>#define ROW 2
>>#define COL 2
>>
>> char ***ptr = malloc ( MAT * sizeof *ptr );
>>
>> for ( i = 0; i < MAT; i++ )
>> ptr[i] = malloc ( ROW * sizeof **ptr );
>>
>> for ( i = 0; i < MAT; i++ )
>> for ( j = 0; j < ROW; j++ )
>> ptr[i][j] = malloc ( COL * sizeof ***ptr );
>>
>>Thanks.
>>

>
>
>
> You define a pointer to a pointer to a pointer to a char. So your first
> malloc() should create the space for several 'pointer to a pointer to a
> char' and make ptr (which is a pointer to a "pointer to a pointer to char"
> point to it through the malloc call)
>
> char *** ptr=malloc(MAT * sizeof **ptr);

Are you sure about that? Isn't sizeof **ptr equivalent to sizeof char*
seeing as ptr is of type char***? Perhaps you are confusing "**ptr" with
"char**"?

I think you should use
char*** ptr = malloc(MAT * sizeof *ptr);

>
> For each of the entries in this array of pointers to pointers to a char you
> now need to point to a 'pointer to a char' type:
>
> for(i=0;i<MAT;i++)
> ptr[i]=malloc(ROW * sizeof *ptr);

Similarly "*ptr" is not the same as "char*". Use:
ptr[i] = malloc(ROW * sizeof *(ptr[i]));

>
> So now you have a bunch of ROW pointers to chars in each row of the array
> ptr[i] so now you must point these to the 'char' (or the first char in an
> array of char)
>
> for ( i = 0; i < MAT; i++ )
> for ( j = 0; j < ROW; j++ )
> ptr[i][j] = malloc ( COL * sizeof char );

And here:
ptr[i][j] = malloc(COL * sizeof *(ptr[i][j]));

>
>
> You can think of it more clearly like this:
>
> char array[MAT][ROW][COL];
>
> char * array[MAT][ROW]
>
> char ** array[MAT]
>
> char *** array;
>
> In practice the sizeof ***ptr and sizeof ** ptr etc will all be the same.
> Therefore what you end up with in your original code is a three dimentional
> array of the type char * as follows:
>
> char * array[MAT][ROW][COL];

I'd have though it was more like char array[MAT][ROW][COL];
The array has three sets of braces so it decays to a triple pointer
right? Which is exactly what the OP started with.

>
> Which might be what you wanted, but all the char * array entries you created
> do not yet point anywhere and when you do point them somewhere you will in
> fact end up with a 4 dimensional array like this for example:
>
> char array[MAT][ROW][COL][STRLEN+1];
>
> Hope this helps you clarify this...
>
> Sean
>

Hmmm - I'm a bit confused by all this...

nrk
Guest
Posts: n/a

 01-30-2004
Vijay Kumar R Zanvar wrote:

> Hi c.l.c,
>
> Is this a correct method of allocating a 3-dimensional
> array?
>
> /* assume all malloc's succeed */
> #define MAT 2
> #define ROW 2
> #define COL 2
>
> char ***ptr = malloc ( MAT * sizeof *ptr );
>
> for ( i = 0; i < MAT; i++ )
> ptr[i] = malloc ( ROW * sizeof **ptr );
>
> for ( i = 0; i < MAT; i++ )
> for ( j = 0; j < ROW; j++ )
> ptr[i][j] = malloc ( COL * sizeof ***ptr );
>
> Thanks.
>

Correct. Note that as someone who's posted here more than once before, you
must know this is answered in the FAQ. Specifically Q6.16:
http://www.eskimo.com/~scs/C-faq/q6.16.html

-nrk.

--
Remove devnull for email

nrk
Guest
Posts: n/a

 01-30-2004
Sean Kenwrick wrote:

>
> "Vijay Kumar R Zanvar" <(E-Mail Removed)> wrote in message
> news:bvda2p\$qt40s\$(E-Mail Removed)-berlin.de...
>> Hi c.l.c,
>>
>> Is this a correct method of allocating a 3-dimensional
>> array?
>>
>> /* assume all malloc's succeed */
>> #define MAT 2
>> #define ROW 2
>> #define COL 2
>>
>> char ***ptr = malloc ( MAT * sizeof *ptr );
>>
>> for ( i = 0; i < MAT; i++ )
>> ptr[i] = malloc ( ROW * sizeof **ptr );
>>
>> for ( i = 0; i < MAT; i++ )
>> for ( j = 0; j < ROW; j++ )
>> ptr[i][j] = malloc ( COL * sizeof ***ptr );
>>
>> Thanks.
>>

>
>
> You define a pointer to a pointer to a pointer to a char. So your
> first malloc() should create the space for several 'pointer to a pointer
> to a
> char' and make ptr (which is a pointer to a "pointer to a pointer to
> char" point to it through the malloc call)
>
> char *** ptr=malloc(MAT * sizeof **ptr);
>

Wrong. OP was correct. **ptr has type pointer-to-char, and you need sizeof
pointer-to-pointer-to-char.

> For each of the entries in this array of pointers to pointers to a char
> you now need to point to a 'pointer to a char' type:
>
> for(i=0;i<MAT;i++)
> ptr[i]=malloc(ROW * sizeof *ptr);
>

Wrong again. *ptr has type pointer-to-pointer-to-char, and you need sizeof
pointer-to-char.

> So now you have a bunch of ROW pointers to chars in each row of the array
> ptr[i] so now you must point these to the 'char' (or the first char in an
> array of char)
>
> for ( i = 0; i < MAT; i++ )
> for ( j = 0; j < ROW; j++ )
> ptr[i][j] = malloc ( COL * sizeof char );
>

Ok. But I would prefer:
ptr[i][j] = malloc(COL * sizeof ***ptr);

>
> You can think of it more clearly like this:
>
> char array[MAT][ROW][COL];
>
> char * array[MAT][ROW]
>
> char ** array[MAT]
>
> char *** array;
>
> In practice the sizeof ***ptr and sizeof ** ptr etc will all be the same.

Absolute nonsense, particularly given OP's declaration of ptr. Don't bandy

> Therefore what you end up with in your original code is a three
> dimentional array of the type char * as follows:
>
> char * array[MAT][ROW][COL];
>

OP wants a two dimensional array of pointer-to-char.

> Which might be what you wanted, but all the char * array entries you
> created
> do not yet point anywhere and when you do point them somewhere you will
> in fact end up with a 4 dimensional array like this for example:
>
> char array[MAT][ROW][COL][STRLEN+1];
>

Wrong again. OP's code is fine.

> Hope this helps you clarify this...
>

No. It certainly doesn't.

-nrk.

> Sean

--
Remove devnull for email

Sean Kenwrick
Guest
Posts: n/a

 01-30-2004

"nrk" <(E-Mail Removed)> wrote in message
news:kdvSb.155\$(E-Mail Removed)...
> Sean Kenwrick wrote:
>
> >
> > "Vijay Kumar R Zanvar" <(E-Mail Removed)> wrote in message
> > news:bvda2p\$qt40s\$(E-Mail Removed)-berlin.de...
> >> Hi c.l.c,
> >>
> >> Is this a correct method of allocating a 3-dimensional
> >> array?
> >>
> >> /* assume all malloc's succeed */
> >> #define MAT 2
> >> #define ROW 2
> >> #define COL 2
> >>
> >> char ***ptr = malloc ( MAT * sizeof *ptr );
> >>
> >> for ( i = 0; i < MAT; i++ )
> >> ptr[i] = malloc ( ROW * sizeof **ptr );
> >>
> >> for ( i = 0; i < MAT; i++ )
> >> for ( j = 0; j < ROW; j++ )
> >> ptr[i][j] = malloc ( COL * sizeof ***ptr );
> >>
> >> Thanks.
> >>

> >
> >
> > You define a pointer to a pointer to a pointer to a char. So your
> > first malloc() should create the space for several 'pointer to a pointer
> > to a
> > char' and make ptr (which is a pointer to a "pointer to a pointer to
> > char" point to it through the malloc call)
> >
> > char *** ptr=malloc(MAT * sizeof **ptr);
> >

>
> Wrong. OP was correct. **ptr has type pointer-to-char, and you need

sizeof
> pointer-to-pointer-to-char.

Yeh, I meant to use the TYPE not the object here so it would be:

char *** ptr=malloc(MAT * sizeof (char**));

Hence the two '**' which was wrong when I used them with sizeof **ptr...

>
> > For each of the entries in this array of pointers to pointers to a char
> > you now need to point to a 'pointer to a char' type:
> >
> > for(i=0;i<MAT;i++)
> > ptr[i]=malloc(ROW * sizeof *ptr);
> >

>
> Wrong again. *ptr has type pointer-to-pointer-to-char, and you need

sizeof
> pointer-to-char.

Again I meant 'char *' not *ptr - very careless...

>
> > So now you have a bunch of ROW pointers to chars in each row of the

array
> > ptr[i] so now you must point these to the 'char' (or the first char in

an
> > array of char)
> >
> > for ( i = 0; i < MAT; i++ )
> > for ( j = 0; j < ROW; j++ )
> > ptr[i][j] = malloc ( COL * sizeof char );
> >

>
> Ok. But I would prefer:
> ptr[i][j] = malloc(COL * sizeof ***ptr);
>
> >
> > You can think of it more clearly like this:
> >
> > char array[MAT][ROW][COL];
> >
> > char * array[MAT][ROW]
> >
> > char ** array[MAT]
> >
> > char *** array;
> >
> > In practice the sizeof ***ptr and sizeof ** ptr etc will all be the

same.
>
> Absolute nonsense, particularly given OP's declaration of ptr. Don't

bandy
>

Again I meant sizeof(char ***) and sizeof(char **) would be the same in
practice ...

I think my brain suffered a temporary blue screen of death...

Sean

Arthur J. O'Dwyer
Guest
Posts: n/a

 01-30-2004

On Fri, 30 Jan 2004, Sean Kenwrick wrote:
>
> "nrk" <(E-Mail Removed)> wrote...
> > Sean Kenwrick wrote:
> > >
> > > You define a pointer to a pointer to a pointer to a char. So
> > > your first malloc() should create the space for several 'pointer
> > > to a pointer to a char' and make ptr (which is a pointer to a
> > > "pointer to a pointer to char" point to it through the malloc call)
> > >
> > > char *** ptr=malloc(MAT * sizeof **ptr);

> >
> > Wrong. OP was correct. **ptr has type pointer-to-char, and you need
> > sizeof pointer-to-pointer-to-char.

>
> Yeh, I meant to use the TYPE not the object here so it would be:
>
> char *** ptr=malloc(MAT * sizeof (char**));
>
> Hence the two '**' which was wrong when I used them with sizeof **ptr...

This is /EXACTLY/ why we here in c.l.c don't try to foist the
ridiculous "sizeof (char **)" nonsense on newbies (or even oldbies,
for that matter). If you stick to "sizeof *foo" for every malloc
call you ever write, you will /never/ commit such a serious blunder,
and the regulars won't have to waste time correcting you.

> > > You can think of it more clearly like this:
> > >
> > > char array[MAT][ROW][COL];
> > > char * array[MAT][ROW]
> > > char ** array[MAT]
> > > char *** array;

Maybe *you* can; but an experienced C programmer might look at
that list of declarations and see immediately that they're all of
different types, stored and accessed by different methods; and then
he might accuse you of either oversimplification or ignorance -- and
we wouldn't want that, now would we?

> > > In practice the sizeof ***ptr and sizeof ** ptr etc will all be
> > > the same.

> >
> > Absolute nonsense, particularly given OP's declaration of ptr. Don't

>
> Again I meant sizeof(char ***) and sizeof(char **) would be the same in
> practice ...

Still wrong, as far as C is concerned. (char ***) and (char **) are
not compatible types, nor do they necessarily have the same size.

> I think my brain suffered a temporary blue screen of death...

I think you're still working through the stage that comes right after
wide-eyed newbieness, which is 1337|\|355. ("Don't assume that just
because you can kick the TV and make it work, that you are an
uber-TV-repairman.") Keep reading c.l.c, though, and you'll pull
through.

-Arthur

Arthur J. O'Dwyer
Guest
Posts: n/a

 01-30-2004

On Fri, 30 Jan 2004, Vijay Kumar R Zanvar wrote:
>
> Is this a correct method of allocating a 3-dimensional
> array?
>
> /* assume all malloc's succeed */

No! Definitely not! ;-D

> #define MAT 2
> #define ROW 2
> #define COL 2
>
> char ***ptr = malloc ( MAT * sizeof *ptr );
>
> for ( i = 0; i < MAT; i++ )
> ptr[i] = malloc ( ROW * sizeof **ptr );

I would stick to the c.l.c idiom here, and write

ptr[i] = malloc(ROW * sizeof *ptr[i]);

just to avoid any lingering doubts about how many asterisks
are supposed to go there.

> for ( i = 0; i < MAT; i++ )
> for ( j = 0; j < ROW; j++ )
> ptr[i][j] = malloc ( COL * sizeof ***ptr );

Ditto on this malloc. Except that in practice, I'd fold
these two loops into one, making the finished product look
like this:

char ***new_array_without_error_checking(int MAT, int ROW, int COL)
{
char ***ptr;
int i, j;

ptr = malloc(MAT * sizeof *ptr);
for (i=0; i < MAT; ++i) {
ptr[i] = malloc(ROW * sizeof *ptr[i]);
for (j=0; j < ROW; ++j)
ptr[i][j] = malloc(COL * sizeof *ptr[i][j]);
}

return ptr;
}

Incidentally, I see that the FAQ (q6.16) uses malloc casting,
which it actually POINTS OUT reaches a point where "the syntax
starts getting horrific," so I don't know why Steve Summit added
it in the first place!

HTH,
-Arthur

E. Robert Tisdale
Guest
Posts: n/a

 01-30-2004
Arthur J. O'Dwyer wrote:

> Incidentally, I see that the FAQ (q6.16) uses malloc casting,
> which it actually POINTS OUT reaches a point
> where "the syntax starts getting horrific," so
> I don't know why Steve Summit added it in the first place!

Snicker, snicker. Chortle, chortle. Gloat, gloat.

Sean Kenwrick
Guest
Posts: n/a

 01-31-2004

"Arthur J. O'Dwyer" <(E-Mail Removed)> wrote in message
news(E-Mail Removed)...
>
> On Fri, 30 Jan 2004, Sean Kenwrick wrote:
> >
> > "nrk" <(E-Mail Removed)> wrote...
> > > Sean Kenwrick wrote:
> > > >
> > > > You define a pointer to a pointer to a pointer to a char. So
> > > > your first malloc() should create the space for several 'pointer
> > > > to a pointer to a char' and make ptr (which is a pointer to a
> > > > "pointer to a pointer to char" point to it through the malloc call)
> > > >
> > > > char *** ptr=malloc(MAT * sizeof **ptr);
> > >
> > > Wrong. OP was correct. **ptr has type pointer-to-char, and you need
> > > sizeof pointer-to-pointer-to-char.

> >
> > Yeh, I meant to use the TYPE not the object here so it would be:
> >
> > char *** ptr=malloc(MAT * sizeof (char**));
> >
> > Hence the two '**' which was wrong when I used them with sizeof **ptr...

>
> This is /EXACTLY/ why we here in c.l.c don't try to foist the
> ridiculous "sizeof (char **)" nonsense on newbies (or even oldbies,
> for that matter). If you stick to "sizeof *foo" for every malloc
> call you ever write, you will /never/ commit such a serious blunder,
> and the regulars won't have to waste time correcting you.
>

This reason I got into trouble here is /EXACTLY/ because I used sizeof
(*foo) instead to sizeof(type). When you see a statement like sizeof
***foo or sizeof **foo you cannot immediately descern from the code what is
going on without hunting back to track down the declaration of foo then
figuring out it's indirection so that you can know what ***foo is refering
to (is it the object, a pointer to the object or a pointer to a pointer ot
the object??? (horrible!)). Whereas with sizeof (char**) is immediately
clear what it is refering to.

The only advantage I can see of using sizeof *foo is that it protects you
from the case where you might change the fundamental type of foo in the
future, but this is a very rare occurance for something that destroys the

I'm sure you will enlighten me as to othjer reasons why you prefer sizeof
*foo here in c.l.c and I might yet be converted if you present a good enough
case

Sean