Review: 3D-Array

Discussion in 'C Programming' started by Vijay Kumar R Zanvar, Jan 30, 2004.

  1. 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 = malloc ( ROW * sizeof **ptr );

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

    Thanks.

    --
    "When you will be pleased to dine, Mr. Homles?" asked Mrs Hudson,
    the landlady, curiosly.
    "At seven thirty, the day after tomorrow." said he invovled in his work.
     
    Vijay Kumar R Zanvar, Jan 30, 2004
    #1
    1. Advertising

  2. "Vijay Kumar R Zanvar" <> wrote in message
    news:bvda2p$qt40s$-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 = malloc ( ROW * sizeof **ptr );
    >
    > for ( i = 0; i < MAT; i++ )
    > for ( j = 0; j < ROW; j++ )
    > ptr[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=malloc(ROW * sizeof *ptr);

    So now you have a bunch of ROW pointers to chars in each row of the array
    ptr 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[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
     
    Sean Kenwrick, Jan 30, 2004
    #2
    1. Advertising

  3. Vijay Kumar R Zanvar

    Thes Guest

    Sean Kenwrick wrote:
    > "Vijay Kumar R Zanvar" <> wrote in message
    > news:bvda2p$qt40s$-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 = malloc ( ROW * sizeof **ptr );
    >>
    >> for ( i = 0; i < MAT; i++ )
    >> for ( j = 0; j < ROW; j++ )
    >> ptr[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);
    here instead.


    >
    > 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=malloc(ROW * sizeof *ptr);


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

    >
    > So now you have a bunch of ROW pointers to chars in each row of the array
    > ptr 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[j] = malloc ( COL * sizeof char );


    And here:
    ptr[j] = malloc(COL * sizeof *(ptr[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...
     
    Thes, Jan 30, 2004
    #3
  4. Vijay Kumar R Zanvar

    nrk Guest

    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 = malloc ( ROW * sizeof **ptr );
    >
    > for ( i = 0; i < MAT; i++ )
    > for ( j = 0; j < ROW; j++ )
    > ptr[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, Jan 30, 2004
    #4
  5. Vijay Kumar R Zanvar

    nrk Guest

    Sean Kenwrick wrote:

    >
    > "Vijay Kumar R Zanvar" <> wrote in message
    > news:bvda2p$qt40s$-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 = malloc ( ROW * sizeof **ptr );
    >>
    >> for ( i = 0; i < MAT; i++ )
    >> for ( j = 0; j < ROW; j++ )
    >> ptr[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=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 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[j] = malloc ( COL * sizeof char );
    >


    Ok. But I would prefer:
    ptr[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
    about such dangerous and incorrect advice.

    > 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
     
    nrk, Jan 30, 2004
    #5
  6. "nrk" <> wrote in message
    news:kdvSb.155$...
    > Sean Kenwrick wrote:
    >
    > >
    > > "Vijay Kumar R Zanvar" <> wrote in message
    > > news:bvda2p$qt40s$-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 = malloc ( ROW * sizeof **ptr );
    > >>
    > >> for ( i = 0; i < MAT; i++ )
    > >> for ( j = 0; j < ROW; j++ )
    > >> ptr[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=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 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[j] = malloc ( COL * sizeof char );
    > >

    >
    > Ok. But I would prefer:
    > ptr[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
    > about such dangerous and incorrect advice.
    >


    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
     
    Sean Kenwrick, Jan 30, 2004
    #6
  7. On Fri, 30 Jan 2004, Sean Kenwrick wrote:
    >
    > "nrk" <> 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
    > > bandy about such dangerous and incorrect advice.

    >
    > 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, Jan 30, 2004
    #7
  8. 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 = malloc ( ROW * sizeof **ptr );


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

    ptr = malloc(ROW * sizeof *ptr);

    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[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 = malloc(ROW * sizeof *ptr);
    for (j=0; j < ROW; ++j)
    ptr[j] = malloc(COL * sizeof *ptr[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
     
    Arthur J. O'Dwyer, Jan 30, 2004
    #8
  9. 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.
     
    E. Robert Tisdale, Jan 30, 2004
    #9
  10. "Arthur J. O'Dwyer" <> wrote in message
    news:p...
    >
    > On Fri, 30 Jan 2004, Sean Kenwrick wrote:
    > >
    > > "nrk" <> 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
    readability of your code...

    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
     
    Sean Kenwrick, Jan 31, 2004
    #10
  11. Sean Kenwrick wrote:

    > This reason I got into trouble here is /EXACTLY/ because I used sizeof
    > (*foo) instead to sizeof(type).


    Er, no, the reason you got into trouble was that you used sizeof **foo
    instead of sizeof *foo.

    > 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!)).


    It's really, really easy. Whatever it is that's on the left of the = malloc,
    you do sizeof *whatever. Watch:

    T *p = malloc(n * sizeof *p); /* generic example */

    char *******************s = malloc(n * sizeof *s); /* easy, huh? */

    if(s == NULL) abort();

    for(i = 0; i < n; i++)
    {
    s = malloc(m * sizeof *s);
    if(s == NULL) abort();
    }

    Here, we see a possible way in which you can get tangled if you aren't
    simple-minded enough. The basic algorithm here is:

    1) write the pointer down - in this case, s
    2) write = malloc(numobjects * sizeof *
    3) copy the value you wrote in step 1, and paste it at the end of the
    line.
    4) add );

    Let's demonstrate by pointing this pointer: d[e].m[17]->o

    at some allocated space.

    Step 1: we write the pointer down:

    d[e].m[17]->o

    Step 2: Now we put " = malloc(numobjects * sizeof *", which gives us:

    d[e].m[17]->o = malloc(numobjects * sizeof *

    Step 3: We copy/paste the original pointer:

    d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o

    Step 4: make good:

    d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o);

    > Whereas with sizeof (char**) is immediately
    > clear what it is refering to.


    Please verify that this call is correct, using only information that is
    immediately clear:

    d[e].m[17]->o = malloc(numobjects * sizeof(int(*)(int, char **)));

    Can you verify that this code is correct? I certainly can't.

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
     
    Richard Heathfield, Jan 31, 2004
    #11
  12. Vijay Kumar R Zanvar

    Amos Leffler Guest

    Richard Heathfield wrote:
    >
    > Sean Kenwrick wrote:
    >
    > > This reason I got into trouble here is /EXACTLY/ because I used sizeof
    > > (*foo) instead to sizeof(type).

    >
    > Er, no, the reason you got into trouble was that you used sizeof **foo
    > instead of sizeof *foo.
    >
    > > 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!)).

    >
    > It's really, really easy. Whatever it is that's on the left of the = malloc,
    > you do sizeof *whatever. Watch:
    >
    > T *p = malloc(n * sizeof *p); /* generic example */
    >
    > char *******************s = malloc(n * sizeof *s); /* easy, huh? */
    >
    > if(s == NULL) abort();
    >
    > for(i = 0; i < n; i++)
    > {
    > s = malloc(m * sizeof *s);
    > if(s == NULL) abort();
    > }
    >
    > Here, we see a possible way in which you can get tangled if you aren't
    > simple-minded enough. The basic algorithm here is:
    >
    > 1) write the pointer down - in this case, s
    > 2) write = malloc(numobjects * sizeof *
    > 3) copy the value you wrote in step 1, and paste it at the end of the
    > line.
    > 4) add );
    >
    > Let's demonstrate by pointing this pointer: d[e].m[17]->o
    >
    > at some allocated space.
    >
    > Step 1: we write the pointer down:
    >
    > d[e].m[17]->o
    >
    > Step 2: Now we put " = malloc(numobjects * sizeof *", which gives us:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof *
    >
    > Step 3: We copy/paste the original pointer:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o
    >
    > Step 4: make good:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o);
    >
    > > Whereas with sizeof (char**) is immediately
    > > clear what it is refering to.

    >
    > Please verify that this call is correct, using only information that is
    > immediately clear:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof(int(*)(int, char **)));
    >
    > Can you verify that this code is correct? I certainly can't.
    >
    > --
    > Richard Heathfield :
    > "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    > C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    > K&R answers, C books, etc: http://users.powernet.co.uk/eton



    Hi,
    If anybody is interested there is a discussion of this problem in
    "Numerical Recipes in C", 2nd edn. It covers two dimensional arrays but
    can be extended if you are interested.
    Amos L.
     
    Amos Leffler, Feb 1, 2004
    #12
  13. "Richard Heathfield" <> wrote in message
    news:bvg068$erg$...
    > Sean Kenwrick wrote:
    >
    > > This reason I got into trouble here is /EXACTLY/ because I used sizeof
    > > (*foo) instead to sizeof(type).

    >
    > Er, no, the reason you got into trouble was that you used sizeof **foo
    > instead of sizeof *foo.
    >
    > > 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!)).

    >
    > It's really, really easy. Whatever it is that's on the left of the =

    malloc,
    > you do sizeof *whatever. Watch:
    >
    > T *p = malloc(n * sizeof *p); /* generic example */
    >
    > char *******************s = malloc(n * sizeof *s); /* easy, huh? */
    >
    > if(s == NULL) abort();
    >
    > for(i = 0; i < n; i++)
    > {
    > s = malloc(m * sizeof *s);
    > if(s == NULL) abort();
    > }
    >
    > Here, we see a possible way in which you can get tangled if you aren't
    > simple-minded enough. The basic algorithm here is:
    >
    > 1) write the pointer down - in this case, s
    > 2) write = malloc(numobjects * sizeof *
    > 3) copy the value you wrote in step 1, and paste it at the end of the
    > line.
    > 4) add );
    >
    > Let's demonstrate by pointing this pointer: d[e].m[17]->o
    >
    > at some allocated space.
    >
    > Step 1: we write the pointer down:
    >
    > d[e].m[17]->o
    >
    > Step 2: Now we put " = malloc(numobjects * sizeof *", which gives us:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof *
    >
    > Step 3: We copy/paste the original pointer:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o
    >
    > Step 4: make good:
    >
    > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o);
    >


    OK I'm sold!

    The OP had code like this:

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


    Which I was just going to use as a counter example to your point until I
    realised that ptr[j] dereferences to **ptr, so that malloc(COL*sizeof
    ***ptr) (following your rules) is correct without needing to know the
    original type of ptr.

    Sean
     
    Sean Kenwrick, Feb 2, 2004
    #13
  14. Vijay Kumar R Zanvar

    pete Guest

    Sean Kenwrick wrote:
    >
    > "Richard Heathfield" <> wrote in message
    > news:bvg068$erg$...


    > > It's really, really easy.
    > > Whatever it is that's on the left of the = malloc,
    > > you do sizeof *whatever. Watch:
    > >
    > > T *p = malloc(n * sizeof *p); /* generic example */
    > >
    > > char *******************s = malloc(n * sizeof *s);
    > > /* easy, huh? */
    > >
    > > if(s == NULL) abort();
    > >
    > > for(i = 0; i < n; i++)
    > > {
    > > s = malloc(m * sizeof *s);
    > > if(s == NULL) abort();
    > > }
    > >
    > > Here, we see a possible way in which you can get
    > > tangled if you aren't
    > > simple-minded enough. The basic algorithm here is:
    > >
    > > 1) write the pointer down - in this case, s
    > > 2) write = malloc(numobjects * sizeof *
    > > 3) copy the value you wrote in step 1,
    > > and paste it at the end of the line.
    > > 4) add );
    > >
    > > Let's demonstrate by pointing this pointer: d[e].m[17]->o
    > >
    > > at some allocated space.
    > >
    > > Step 1: we write the pointer down:
    > >
    > > d[e].m[17]->o
    > >
    > > Step 2: Now we put " = malloc(numobjects * sizeof *",
    > > which gives us:
    > >
    > > d[e].m[17]->o = malloc(numobjects * sizeof *
    > >
    > > Step 3: We copy/paste the original pointer:
    > >
    > > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o
    > >
    > > Step 4: make good:
    > >
    > > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o);
    > >

    >
    > OK I'm sold!


    It's good even if the left operand of the assignment has
    side effects, because sizeof doesn't evaluate it's operand.

    I like the idiom for allocations for arrays of all types,
    except when allocating bytes for strings.
    Then I like malloc(length + 1).

    --
    pete
     
    pete, Feb 2, 2004
    #14
  15. Vijay Kumar R Zanvar

    Old Wolf Guest

    > 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 = malloc ( ROW * sizeof **ptr );
    >
    > for ( i = 0; i < MAT; i++ )
    > for ( j = 0; j < ROW; j++ )
    > ptr[j] = malloc ( COL * sizeof ***ptr );
    >

    [note - code is even more voluminous when you include all the malloc
    NULL checks and free() calls]

    How is this any better than:
    char (*ptr)[ROW][COL] = malloc(MAT * sizeof *ptr);

    If your answer is that MAT, ROW and COL might not be compiletime
    constants after all, then you can go:
    char *ptr = malloc(MAT * ROW * COL * sizeof *ptr)
    and
    #define CELL(mat,row,col) ptr[(mat)*ROW*COL + (row)*COL + (col)]
    or similar

    If your answer is re. row-major vs. col-major order, then you can
    do a little syntax rearranging to fix that.
     
    Old Wolf, Feb 2, 2004
    #15
  16. On Mon, 2 Feb 2004, Sean Kenwrick wrote:
    >
    > "Richard Heathfield" <> wrote...
    > > Sean Kenwrick wrote:
    > >
    > > > This reason I got into trouble here is /EXACTLY/ because I used sizeof
    > > > (*foo) instead to sizeof(type).

    > >
    > > Er, no, the reason you got into trouble was that you used sizeof **foo
    > > instead of sizeof *foo.


    > > It's really, really easy. Whatever it is that's on the left of the
    > > = malloc, you do sizeof *whatever. Watch:


    > > Let's demonstrate by pointing this pointer: d[e].m[17]->o
    > > at some allocated space.


    > > d[e].m[17]->o = malloc(numobjects * sizeof *d[e].m[17]->o);

    >
    > OK I'm sold!
    >
    > The OP had code like this:
    >
    > for ( i = 0; i < MAT; i++ )
    > for ( j = 0; j < ROW; j++ )
    > ptr[j] = malloc ( COL * sizeof ***ptr );
    >
    >
    > Which I was just going to use as a counter example to your point until I
    > realised that ptr[j] dereferences to **ptr,


    That is meaningless. ptr[j] is the j'th element of the array
    whose first element is pointed to by the pointer expression ptr.
    **ptr is the object pointed to by the pointer expression *ptr.
    The two are very rarely the same object, although they do have the
    same size.

    > so that malloc(COL*sizeof ***ptr) (following your rules) is correct


    That it is, but I suspect most C programmers here would be even
    more comfortable if you had followed the simple "four-step" rule
    that Richard just told you, right above: write the pointer, write
    "= malloc(COL * sizeof *", write the pointer again, and then write
    ");". This foolproof method yields

    ptr[j] = malloc(COL * sizeof *ptr[j]);

    which really /is/ obviously correct, even to those lazy bums who
    don't want to waste precious debugging time comparing the numbers of
    asterisks and square brackets!
    [See my post farther up in this thread, which uses the "four-step"
    method exclusively.]

    -Arthur
     
    Arthur J. O'Dwyer, Feb 2, 2004
    #16
  17. Arthur J. O'Dwyer wrote:

    >
    > On Mon, 2 Feb 2004, Sean Kenwrick wrote:
    >>
    >> so that malloc(COL*sizeof ***ptr) (following your rules) is correct

    >
    > That it is, but I suspect most C programmers here would be even
    > more comfortable if you had followed the simple "four-step" rule
    > that Richard just told you, right above: write the pointer, write
    > "= malloc(COL * sizeof *", write the pointer again, and then write
    > ");". This foolproof method yields
    >
    > ptr[j] = malloc(COL * sizeof *ptr[j]);
    >
    > which really /is/ obviously correct, even to those lazy bums who
    > don't want to waste precious debugging time comparing the numbers of
    > asterisks and square brackets!
    > [See my post farther up in this thread, which uses the "four-step"
    > method exclusively.]


    "The four-step method" sounds terribly complicated, doesn't it?


    Coming soon: how to write "Hello, world." on the standard output device in
    only 85 steps!

    Preview:

    Step 1: Press #
    Step 2: Press i
    Step 3: Press n
    Step 4: Press c

    ...

    :)

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
     
    Richard Heathfield, Feb 3, 2004
    #17
  18. Amos Leffler wrote:

    > Hi,
    > If anybody is interested there is a discussion of this problem in
    > "Numerical Recipes in C", 2nd edn. It covers two dimensional arrays but
    > can be extended if you are interested.


    The C code in Numerical Recipes is a disaster. They've gone to huge lengths
    to keep the 1-based arrays from their Fortran code. This was a mistake
    which permeates almost all their code. If you were looking for undefined
    behaviour, look no further!

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
     
    Richard Heathfield, Feb 3, 2004
    #18
  19. On Fri, 30 Jan 2004 17:27:57 -0500 (EST), "Arthur J. O'Dwyer"
    <> wrote:
    <snip>
    > 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! :-(
    >

    It was there since pre-C89, when it was needed -- and in practice was
    often needed at least for portability for several years after 89. It
    was removed in Feb 1999 (there was discussion at the time) from the
    text version (periodically posted, rtfm and I believe faqs.org) but
    Steve has never (yet AFAIK!) gotten that version into the website.

    - David.Thompson1 at worldnet.att.net
     
    Dave Thompson, Feb 9, 2004
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Olcott
    Replies:
    9
    Views:
    335
    Axter
    Nov 28, 2005
  2. www
    Replies:
    51
    Views:
    1,485
  3. Mara Guida

    const and array of array (of array ...)

    Mara Guida, Sep 2, 2009, in forum: C Programming
    Replies:
    3
    Views:
    496
    David RF
    Sep 3, 2009
  4. Tom
    Replies:
    3
    Views:
    213
    salsablr
    Dec 20, 2004
  5. Tuan  Bui
    Replies:
    14
    Views:
    476
    it_says_BALLS_on_your forehead
    Jul 29, 2005
Loading...

Share This Page