int** to void**

Discussion in 'C Programming' started by John, Jan 6, 2010.

  1. John

    John Guest

    Hi All,

    I wrote a function in C and compiled in gcc, I got a warning such as:

    .../test/test.c:26: warning: passing arg 1 of `ORCdarrayfree' from
    incompatib
    le pointer type

    Then I goto 26th line, I found the function ORCdarrayfree have a
    parameter with type void**,
    but I passed int** to it.

    So anyone can explain it for me and help me avoid this warning?

    Thanks!
     
    John, Jan 6, 2010
    #1
    1. Advertising

  2. John

    Ralph Malph Guest

    int** i;
    void** v=(void**) i;

    John wrote:
    > Hi All,
    >
    > I wrote a function in C and compiled in gcc, I got a warning such as:
    >
    > ../test/test.c:26: warning: passing arg 1 of `ORCdarrayfree' from
    > incompatib
    > le pointer type
    >
    > Then I goto 26th line, I found the function ORCdarrayfree have a
    > parameter with type void**,
    > but I passed int** to it.
    >
    > So anyone can explain it for me and help me avoid this warning?
    >
    > Thanks!
     
    Ralph Malph, Jan 6, 2010
    #2
    1. Advertising

  3. John

    Seebs Guest

    On 2010-01-06, John <> wrote:
    > So anyone can explain it for me and help me avoid this warning?


    Quite simply, you can't do that.

    You can convert void* to int*, but not void** to int**.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Jan 6, 2010
    #3
  4. Ralph Malph <> writes:
    > John wrote:
    >> I wrote a function in C and compiled in gcc, I got a warning such as:
    >>
    >> ../test/test.c:26: warning: passing arg 1 of `ORCdarrayfree' from
    >> incompatib
    >> le pointer type
    >>
    >> Then I goto 26th line, I found the function ORCdarrayfree have a
    >> parameter with type void**,
    >> but I passed int** to it.
    >>
    >> So anyone can explain it for me and help me avoid this warning?

    >
    > int** i;
    > void** v=(void**) i;


    [top-posting corrected]

    Using a cast to silence a warning is almost never the right thing
    to do.

    void* is a generic pointer type, in the sense that you can convert
    from any pointer type (excluding pointer-to-function types) to void*
    and back again without loss of information.

    There is no generic pointer-to-pointer type.

    I don't know what ORCdarrayfree, but apparently it requires an
    argument of type void**, most likely pointing to the first element
    of an array of void*. The int** argument you're passing is probably
    a pointer to the first element of an array of int*. void* and int*
    are distinct and incompatible types.

    You need to pass a valid void** value to ORCdarrayfree. The question
    is how you can obtain such a value. We can't guess at an answer
    without knowing more about ORCdarrayfree and what you're trying to
    pass to it.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jan 6, 2010
    #4
  5. Seebs <> writes:
    > On 2010-01-06, John <> wrote:
    >> So anyone can explain it for me and help me avoid this warning?

    >
    > Quite simply, you can't do that.
    >
    > You can convert void* to int*, but not void** to int**.


    Correction: You *can* convert from void** to int** (or, in this case,
    from int** to void**) by using a cast, but you almost certainly
    shouldn't.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jan 6, 2010
    #5
  6. On 6.1.2010 6:03, Keith Thompson wrote:
    > Seebs<> writes:
    >> On 2010-01-06, John<> wrote:
    >>> So anyone can explain it for me and help me avoid this warning?

    >>
    >> Quite simply, you can't do that.
    >>
    >> You can convert void* to int*, but not void** to int**.

    >
    > Correction: You *can* convert from void** to int** (or, in this case,
    > from int** to void**) by using a cast, but you almost certainly
    > shouldn't.
    >


    Why not? If pointer arithmetic is not wanted, what do we miss? A pointer
    is pointer no matter what.

    --
    http://www.iki.fi/jarif/

    You will inherit millions of dollars.
     
    Donkey Hottie, Jan 6, 2010
    #6
  7. Donkey Hottie <> writes:
    > On 6.1.2010 6:03, Keith Thompson wrote:
    >> Seebs<> writes:
    >>> On 2010-01-06, John<> wrote:
    >>>> So anyone can explain it for me and help me avoid this warning?
    >>>
    >>> Quite simply, you can't do that.
    >>>
    >>> You can convert void* to int*, but not void** to int**.

    >>
    >> Correction: You *can* convert from void** to int** (or, in this case,
    >> from int** to void**) by using a cast, but you almost certainly
    >> shouldn't.

    >
    > Why not? If pointer arithmetic is not wanted, what do we miss? A
    > pointer is pointer no matter what.


    void* and int* are incompatible types.

    Consider an implementation where void* is 64 bits and int* is 32
    bits (such an implementation is certainly permitted, and there could
    be valid reasons for it). Then the function expects a void** that
    points to the first element of an array of void* objects, each of
    which is 64 bits -- but you're passing it an int** that points to the
    first element of an array of int* objects, each of which is 32 bits.

    Conversions from one pointer type to another can be safe in certain
    cases. Interpreting a stored object of one pointer type as if it
    were of a different type is not safe.

    And even if, as is the case on many implementations, all pointers
    happen to have the same representation, treating different pointer
    types as if they were interchangeable tends to be logically
    incorrect, even if you can get away with it.

    The ORCdarrayfree function that the OP is trying to call expects
    a void** argument. Presumably there's a good reason for that.
    Or perhaps ORCdarrayfree itself is poorly designed. We don't
    have enough information to know what the right solution is,
    but we can be reasonably sure that passing an int** to something
    expecting a void** isn't it.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jan 6, 2010
    #7
  8. John

    John Guest

    On Jan 6, 12:01 pm, Keith Thompson <> wrote:
    > Ralph Malph <> writes:
    > > John wrote:
    > >> I wrote a function in C and compiled in gcc, I got a warning such as:

    >
    > >> ../test/test.c:26: warning: passing arg 1 of `ORCdarrayfree' from
    > >> incompatib
    > >> le pointer type

    >
    > >> Then I goto 26th line, I found the function ORCdarrayfree have a
    > >> parameter with type void**,
    > >> but I passed int** to it.

    >
    > >> So anyone can explain it for me and help me avoid this warning?

    >
    > > int** i;
    > > void** v=(void**) i;

    >
    > [top-posting corrected]
    >
    > Using a cast to silence a warning is almost never the right thing
    > to do.
    >
    > void* is a generic pointer type, in the sense that you can convert
    > from any pointer type (excluding pointer-to-function types) to void*
    > and back again without loss of information.
    >
    > There is no generic pointer-to-pointer type.
    >
    > I don't know what ORCdarrayfree, but apparently it requires an
    > argument of type void**, most likely pointing to the first element
    > of an array of void*.  The int** argument you're passing is probably
    > a pointer to the first element of an array of int*.  void* and int*
    > are distinct and incompatible types.
    >
    > You need to pass a valid void** value to ORCdarrayfree.  The question
    > is how you can obtain such a value.  We can't guess at an answer
    > without knowing more about ORCdarrayfree and what you're trying to
    > pass to it.
    >


    ORCdarrayfree is used to free 2-d array allocated by malloc.
    The src is:

    /* ORCdarraynew function return void** ,
    and ORCdarrayfree should get void** to
    make these 2 functions to be used in
    allocating integer, char, and other
    customize type */

    void**
    ORCdarraynew (int row, int col, int size)
    {
    void **arr;

    arr = (void **) malloc (sizeof(void *) * row + size * row * col);
    if ( arr != NULL ) {
    void *head;

    head = (void *) arr + sizeof(void *) * row;
    memset (arr, 0, sizeof(void *) * row + size * row * col);
    while (row--) {
    arr[row] = head + size * row * col;
    }
    }

    return arr;
    } /* End of ORCdarraynew*/

    void
    ORCdarrayfree (void **arr)
    {
    if ( arr != NULL ) {
    free (arr);
    arr = NULL;
    }
    } /* End of ORCdarrayfree*/


    We can call them like:

    int **p;
    p = (int**)ORCdarraynew(nrows, ncols, sizeof(int));

    ORCdarrayfree(p);

    So the parameter of ORCdarrayfree will be converted from int** to
    void**.
    While, the gcc compiler give me a warning:

    warning: passing arg 1 of `ORCdarrayfree' from
    incompatib
    le pointer type

    So please help me.
     
    John, Jan 6, 2010
    #8
  9. John <> writes:
    > On Jan 6, 12:01 pm, Keith Thompson <> wrote:

    [...]
    >> You need to pass a valid void** value to ORCdarrayfree.  The question
    >> is how you can obtain such a value.  We can't guess at an answer
    >> without knowing more about ORCdarrayfree and what you're trying to
    >> pass to it.
    >>

    >
    > ORCdarrayfree is used to free 2-d array allocated by malloc.
    > The src is:
    >
    > /* ORCdarraynew function return void** ,
    > and ORCdarrayfree should get void** to
    > make these 2 functions to be used in
    > allocating integer, char, and other
    > customize type */
    >
    > void**
    > ORCdarraynew (int row, int col, int size)


    These should probably be size_t rather than int.

    > {
    > void **arr;
    >
    > arr = (void **) malloc (sizeof(void *) * row + size * row * col);


    Casting the result of malloc is unnecessary and can mask errors.

    > if ( arr != NULL ) {
    > void *head;
    >
    > head = (void *) arr + sizeof(void *) * row;
    > memset (arr, 0, sizeof(void *) * row + size * row * col);
    > while (row--) {
    > arr[row] = head + size * row * col;
    > }
    > }
    >
    > return arr;
    > } /* End of ORCdarraynew*/


    So you're allocating a chunk of memory consisting of an array of void*
    pointers, immediately followed by a 2-dimensional array of some
    arbitrary data, where each of the initial void* pointers points to a
    row in the 2d array. Interesting. Let's call these two sections the
    "index" and the "table", respectively.

    You're making some non-portable assumptions, though.

    The memset call zeros both the index and the table. The former is
    useless, since you immediately initialize the table anyway. Zeroing
    the table may or may not be sensiple, depending on what data you're
    storing. Remember that null pointers aren't necessarily all-bits-zero
    (though they commonly are).

    You're also assuming that the table will be properly aligned.
    Consider a system where void* is 32-bit aligned, double is 64-bit
    aligned, and you want to allocate a table of doubles with an odd
    number of rows.

    > void
    > ORCdarrayfree (void **arr)
    > {
    > if ( arr != NULL ) {
    > free (arr);
    > arr = NULL;
    > }
    > } /* End of ORCdarrayfree*/


    Note that the "arr != NULL" test is unnecessary; free() does nothing
    if you give it a null pointer argument. And setting arr to NULL is
    useless; you're just clobbering a local object. You might want to do
    "*arr = NULL;" -- or you might just want to leave it alone.

    >
    > We can call them like:
    >
    > int **p;
    > p = (int**)ORCdarraynew(nrows, ncols, sizeof(int));
    >
    > ORCdarrayfree(p);
    >
    > So the parameter of ORCdarrayfree will be converted from int** to
    > void**.
    > While, the gcc compiler give me a warning:
    >
    > warning: passing arg 1 of `ORCdarrayfree' from
    > incompatib
    > le pointer type


    gcc is correct; the pointer types are incompatible.

    > So please help me.


    I think you need to allocate the index and the table in two separate
    calls to malloc().

    Here's a thought. Allocate row+1 void* elements for the index.
    Allocate size*row*col bytes for the table; using a separate call to
    malloc guarantees proper alignment. Store the address of the table in
    the 0th element of the index, then return the address of the 1st
    element. ORCdarrayfree can then index backwards to obtain the address
    of the table, free the table, then free the index.

    I haven't completely thought this through. This approach should be
    type-safe, but I think you might have some problems with indexing
    (e.g., p[x][y]).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jan 6, 2010
    #9
  10. pete <> writes:
    > John wrote:

    [...]
    >> /* ORCdarraynew function return void** ,
    >> and ORCdarrayfree should get void** to
    >> make these 2 functions to be used in
    >> allocating integer, char, and other
    >> customize type */
    >>
    >> void**
    >> ORCdarraynew (int row, int col, int size)
    >> {

    [...]
    >> We can call them like:
    >>
    >> int **p;
    >> p = (int**)ORCdarraynew(nrows, ncols, sizeof(int));
    >>
    >> ORCdarrayfree(p);

    [...]
    > Why don't you rewrite ORCdarraynew to return type (int**) instead?


    Because it's intended to allocate a 2d array of any arbitrary type;
    that's what the "size" parameter is for.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jan 6, 2010
    #10
  11. John

    John Guest

    On Jan 6, 1:10 pm, Keith Thompson <> wrote:
    > John <> writes:
    > > On Jan 6, 12:01 pm, Keith Thompson <> wrote:

    > [...]
    > >> You need to pass a valid void** value to ORCdarrayfree.  The question
    > >> is how you can obtain such a value.  We can't guess at an answer
    > >> without knowing more about ORCdarrayfree and what you're trying to
    > >> pass to it.

    >
    > > ORCdarrayfree is used to free 2-d array allocated by malloc.
    > > The src is:

    >
    > > /* ORCdarraynew function return void** ,
    > >    and ORCdarrayfree should get void** to
    > >    make these 2 functions to be used in
    > >    allocating integer, char, and other
    > >    customize type */

    >
    > > void**
    > > ORCdarraynew (int row, int col, int size)

    >
    > These should probably be size_t rather than int.


    Why?

    >
    > > {
    > >    void **arr;

    >
    > >    arr = (void **) malloc (sizeof(void *) * row + size * row * col);

    >
    > Casting the result of malloc is unnecessary and can mask errors.


    In C, I think so. Thanks.

    >
    > >    if ( arr != NULL ) {
    > >       void *head;

    >
    > >       head = (void *) arr + sizeof(void *) * row;
    > >       memset (arr, 0, sizeof(void *) * row + size * row * col);
    > >       while (row--) {
    > >          arr[row] = head + size * row * col;
    > >       }
    > >    }

    >
    > >    return arr;
    > > } /* End of ORCdarraynew*/

    >
    > So you're allocating a chunk of memory consisting of an array of void*
    > pointers, immediately followed by a 2-dimensional array of some
    > arbitrary data, where each of the initial void* pointers points to a
    > row in the 2d array.  Interesting.  Let's call these two sections the
    > "index" and the "table", respectively.
    >
    > You're making some non-portable assumptions, though.
    >
    > The memset call zeros both the index and the table.  The former is
    > useless, since you immediately initialize the table anyway.  Zeroing
    > the table may or may not be sensiple, depending on what data you're
    > storing.  Remember that null pointers aren't necessarily all-bits-zero
    > (though they commonly are).


    memset is used to init the table and index, why is it wrong?

    >
    > You're also assuming that the table will be properly aligned.
    > Consider a system where void* is 32-bit aligned, double is 64-bit
    > aligned, and you want to allocate a table of doubles with an odd
    > number of rows.


    I think double* and double** and void* and void** have same length.
    then what is your concern?

    >
    > > void
    > > ORCdarrayfree (void **arr)
    > > {
    > >    if ( arr != NULL ) {
    > >       free (arr);
    > >       arr = NULL;
    > >    }
    > > } /* End of ORCdarrayfree*/

    >
    > Note that the "arr != NULL" test is unnecessary; free() does nothing
    > if you give it a null pointer argument.  And setting arr to NULL is
    > useless; you're just clobbering a local object.  You might want to do
    > "*arr = NULL;" -- or you might just want to leave it alone.


    free(arr) can free all space by malloc, but don't set arr to NULL.
    I add set arr to NULL is to make the statement after ORCdarrayfree
    can not use arr.

    And also, I don't think I need to set *arr to NULL if I set arr to
    NULL
    after ORCnarrayfree.

    >
    >
    >
    > > We can call them like:

    >
    > > int **p;
    > > p = (int**)ORCdarraynew(nrows, ncols, sizeof(int));

    >
    > > ORCdarrayfree(p);

    >
    > > So the parameter of ORCdarrayfree will be converted from int** to
    > > void**.
    > > While, the gcc compiler give me a warning:

    >
    > > warning: passing arg 1 of `ORCdarrayfree' from
    > > incompatib
    > > le pointer type

    >
    > gcc is correct; the pointer types are incompatible.
    >
    > > So please help me.

    >
    > I think you need to allocate the index and the table in two separate
    > calls to malloc().
    >
    > Here's a thought.  Allocate row+1 void* elements for the index.
    > Allocate size*row*col bytes for the table; using a separate call to
    > malloc guarantees proper alignment.  Store the address of the table in
    > the 0th element of the index, then return the address of the 1st
    > element.  ORCdarrayfree can then index backwards to obtain the address
    > of the table, free the table, then free the index.
    >
    > I haven't completely thought this through.  This approach should be
    > type-safe, but I think you might have some problems with indexing
    > (e.g., p[x][y]).
    >


    Bingo, cannot use p[x][y] is the reason why I don't use your way.
     
    John, Jan 6, 2010
    #11
  12. John

    Seebs Guest

    On 2010-01-06, John <> wrote:
    >> > ORCdarraynew (int row, int col, int size)

    >>
    >> These should probably be size_t rather than int.

    >
    > Why?


    Because they're sizes, and sizes should usually be represented in
    size_t. For instance, on some systems, you might find that size_t
    can represent values up to 2 billion, while int can only handle values
    up to 32,767.

    > memset is used to init the table and index, why is it wrong?


    Because using memset to "zero" a pointer is not guaranteed to produce
    null pointers.

    >> You're also assuming that the table will be properly aligned.
    >> Consider a system where void* is 32-bit aligned, double is 64-bit
    >> aligned, and you want to allocate a table of doubles with an odd
    >> number of rows.


    > I think double* and double** and void* and void** have same length.
    > then what is your concern?


    You missed the key case: Are "void *" and "double" (no *) the same length?
    Not on some fairly common systems. What this means is that since you
    start the doubles immediately after the index, if there's an odd number
    of rows, you're starting to store 8-byte-aligned values on a 4-byte-aligned
    address. That could fail.

    > And also, I don't think I need to set *arr to NULL if I set arr to
    > NULL
    > after ORCnarrayfree.


    Except that something else might still have a pointer to *arr, so you
    want to make sure the thing pointed to has been zeroed out.

    >> I haven't completely thought this through.  This approach should be
    >> type-safe, but I think you might have some problems with indexing
    >> (e.g., p[x][y]).


    > Bingo, cannot use p[x][y] is the reason why I don't use your way.


    There are ways to make that work which are more consistent with respecting
    the spirit of C.

    Here's the thing you're missing: It is better to write things according
    to the formal specification of the language than according to what you think
    you know about the specific machine you are using. It is more reliable,
    and more likely to work even if you are wrong about the machine, or if the
    machine gets changed suddenly.

    There are programs out there that, on a few days' notice, had to convert
    from 32-bit big-endian systems to 64-bit little-endian systems. If they were
    written portably, that was no trouble at all...

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Jan 6, 2010
    #12
  13. John

    John Guest

    On Jan 6, 3:18 pm, pete <> wrote:
    > pete wrote:
    > > Keith Thompson wrote:

    >
    > >> pete <> writes:

    > > void*
    > > ORCdarraynew(size_t row, size_t col, size_t size)
    > > {
    > >    char **arr;

    >
    > >    arr = malloc(row * sizeof *arr);
    > >    if (arr != NULL) {
    > >       while (row-- != 0) {
    > >          arr[row] = malloc(col * size);
    > >          if (arr[row] == NULL) {
    > >              ORCdarrayfree(arr, row);
    > >              arr = NULL;
    > >              break;
    > >          }
    > >       }
    > >    }
    > >    return arr;
    > > }

    >
    > The loop should count up, instead of down, because of
    > the way that ORCdarrayfree is called in case of malloc failure.
    >
    > void*
    > ORCdarraynew(size_t row, size_t col, size_t size)
    > {
    >     char **arr;
    >     size_t index;
    >
    >     arr = malloc(row * sizeof *arr);
    >     if (arr != NULL) {
    >
    >        for (index = 0; index != row; ++index) {
    >           arr[row] = malloc(col * size);
    >           if (arr[index] == NULL) {
    >               ORCdarrayfree(arr, index);
    >               arr = NULL;
    >               break;
    >           }
    >        }
    >     }
    >     return arr;
    >
    > }


    This kind new function can not allocate continues memory for 2-d
    array, do you think so?

    John Cui
     
    John, Jan 6, 2010
    #13
  14. John

    John Guest

    On Jan 6, 3:18 pm, pete <> wrote:
    > pete wrote:
    > > Keith Thompson wrote:

    >
    > >> pete <> writes:

    > > void*
    > > ORCdarraynew(size_t row, size_t col, size_t size)
    > > {
    > >    char **arr;

    >
    > >    arr = malloc(row * sizeof *arr);
    > >    if (arr != NULL) {
    > >       while (row-- != 0) {
    > >          arr[row] = malloc(col * size);
    > >          if (arr[row] == NULL) {
    > >              ORCdarrayfree(arr, row);
    > >              arr = NULL;
    > >              break;
    > >          }
    > >       }
    > >    }
    > >    return arr;
    > > }

    >
    > The loop should count up, instead of down, because of
    > the way that ORCdarrayfree is called in case of malloc failure.
    >
    > void*
    > ORCdarraynew(size_t row, size_t col, size_t size)
    > {
    >     char **arr;
    >     size_t index;
    >
    >     arr = malloc(row * sizeof *arr);
    >     if (arr != NULL) {
    >
    >        for (index = 0; index != row; ++index) {
    >           arr[row] = malloc(col * size);
    >           if (arr[index] == NULL) {
    >               ORCdarrayfree(arr, index);
    >               arr = NULL;
    >               break;
    >           }
    >        }
    >     }
    >     return arr;
    >
    > }


    This kind new function can not allocate continues memory for 2-d
    array, do you think so?

    John Cui
     
    John, Jan 6, 2010
    #14
  15. John

    John Guest

    On Jan 6, 3:36 pm, pete <> wrote:
    > John wrote:
    > > On Jan 6, 3:18 pm, pete <> wrote:

    >
    > >>pete wrote:

    >
    > >>>Keith Thompson wrote:

    >
    > >>>>pete <> writes:

    >
    > >>>void*
    > >>>ORCdarraynew(size_t row, size_t col, size_t size)
    > >>>{
    > >>>   char **arr;

    >
    > >>>   arr = malloc(row * sizeof *arr);
    > >>>   if (arr != NULL) {
    > >>>      while (row-- != 0) {
    > >>>         arr[row] = malloc(col * size);
    > >>>         if (arr[row] == NULL) {
    > >>>             ORCdarrayfree(arr, row);
    > >>>             arr = NULL;
    > >>>             break;
    > >>>         }
    > >>>      }
    > >>>   }
    > >>>   return arr;
    > >>>}

    >
    > >>The loop should count up, instead of down, because of
    > >>the way that ORCdarrayfree is called in case of malloc failure.

    >
    > >>void*
    > >>ORCdarraynew(size_t row, size_t col, size_t size)
    > >>{
    > >>    char **arr;
    > >>    size_t index;

    >
    > >>    arr = malloc(row * sizeof *arr);
    > >>    if (arr != NULL) {

    >
    > >>       for (index = 0; index != row; ++index) {
    > >>          arr[row] = malloc(col * size);
    > >>          if (arr[index] == NULL) {
    > >>              ORCdarrayfree(arr, index);
    > >>              arr = NULL;
    > >>              break;
    > >>          }
    > >>       }
    > >>    }
    > >>    return arr;

    >
    > >>}

    >
    > > This kind new function can not allocate continues memory for 2-d
    > > array, do you think so?

    >
    > No, but you can't do p[x][y] for arbitrary x and y,
    > with int **p;
    > unless p is pointing to a pointer.
    >


    arr = malloc(row * sizeof *arr); in your code
    allocate a space,

    arr[row] = malloc(col * size); in your code
    allocate another space.

    So I think these 2 spaces are not continues.

    John Cui
     
    John, Jan 6, 2010
    #15
  16. John

    John Guest

    On Jan 6, 3:25 pm, Seebs <> wrote:
    > On 2010-01-06, John <> wrote:
    >
    > >> > ORCdarraynew (int row, int col, int size)

    >
    > >> These should probably be size_t rather than int.

    >
    > > Why?

    >
    > Because they're sizes, and sizes should usually be represented in
    > size_t.  For instance, on some systems, you might find that size_t
    > can represent values up to 2 billion, while int can only handle values
    > up to 32,767.


    Thanks!

    >
    > > memset is used to init the table and index, why is it wrong?

    >
    > Because using memset to "zero" a pointer is not guaranteed to produce
    > null pointers.


    OK, then how to init the index pointers and table elements in the 2-d
    array?

    >
    > >> You're also assuming that the table will be properly aligned.
    > >> Consider a system where void* is 32-bit aligned, double is 64-bit
    > >> aligned, and you want to allocate a table of doubles with an odd
    > >> number of rows.

    > > I think double* and double** and void* and void** have same length.
    > > then what is your concern?

    >
    > You missed the key case:  Are "void *" and "double" (no *) the same length?
    > Not on some fairly common systems.  What this means is that since you
    > start the doubles immediately after the index, if there's an odd number
    > of rows, you're starting to store 8-byte-aligned values on a 4-byte-aligned
    > address.  That could fail.


    OK, I used viod* for supporting multiple data types, then how to
    handle both
    multiple data types and align issue?

    >
    > > And also, I don't think I need to set *arr to NULL if I set arr to
    > > NULL
    > > after ORCnarrayfree.

    >
    > Except that something else might still have a pointer to *arr, so you
    > want to make sure the thing pointed to has been zeroed out.


    hmmm, you are more safer.

    >
    > >> I haven't completely thought this through.  This approach should be
    > >> type-safe, but I think you might have some problems with indexing
    > >> (e.g., p[x][y]).

    > > Bingo, cannot use p[x][y] is the reason why I don't use your way.

    >
    > There are ways to make that work which are more consistent with respecting
    > the spirit of C.
    >
    > Here's the thing you're missing:  It is better to write things according
    > to the formal specification of the language than according to what you think
    > you know about the specific machine you are using.  It is more reliable,
    > and more likely to work even if you are wrong about the machine, or if the
    > machine gets changed suddenly.


    Anyway, the spirit of C is don't use p[][] kind?
    and in my way, I can allocate continues memory for 2-d array. I think
    it is better.

    John Cui
     
    John, Jan 6, 2010
    #16
  17. John

    Seebs Guest

    On 2010-01-06, John <> wrote:
    > OK, then how to init the index pointers and table elements in the 2-d
    > array?


    To zero pointers and floating point values:

    for (i = 0; i < n; ++i)
    a = 0;

    > OK, I used viod* for supporting multiple data types, then how to
    > handle both
    > multiple data types and align issue?


    Usually, you do it by allocating two tables; one table for your pointers,
    and another table for the data values they point to. If you do this right,
    you can do p[x][y], and you can still free both values. (Because p[0]
    will be the address of the whole data block you allocated, and p will
    be the address of the index block.)

    > Anyway, the spirit of C is don't use p[][] kind?


    No.

    > and in my way, I can allocate continues memory for 2-d array. I think
    > it is better.


    You still don't get it.

    You can allocate continuous memory for a 2D array separately from the
    table for it, and then p[x][y] works. (Only it's not really a 2D
    array; it's a 1D array of pointers to data. But it works like a 2D array.)

    int *rows;
    int *data;
    data = malloc(rows * columns * sizeof(int));
    rows = malloc(rows * sizeof(int *);
    for (i = 0; i < rows; ++i) {
    rows = data + (columns * i);
    for (j = 0; 0 < columns; ++j)
    rows[j] = 0;
    }

    Poof! rows[0][0] is the first integer in the data array, rows[3][4] is
    the 5th item in the 4th row of the array, and so on. To free it:

    free(rows[0]);
    free(rows);

    Two allocations, but the array contents are continuous.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Jan 6, 2010
    #17
  18. John

    John Guest

    On Jan 6, 4:09 pm, Seebs <> wrote:
    > On 2010-01-06, John <> wrote:
    >
    > > OK, then how to init the index pointers and table elements in the 2-d
    > > array?

    >
    > To zero pointers and floating point values:
    >
    >         for (i = 0; i < n; ++i)
    >                 a = 0;


    The reason you don't agree with memset is memset set the elements to
    integer?
    ++
    memset
    Syntax:
    #include <string.h>
    void *memset( void *buffer, int ch, size_t count );

    The function memset() copies ch into the first count characters of
    buffer, and returns buffer. memset() is useful for intializing a
    section of memory to some value. For example, this command:
    ++

    >
    > > OK, I used viod* for supporting multiple data types, then how to
    > > handle both
    > > multiple data types and align issue?

    >
    > Usually, you do it by allocating two tables; one table for your pointers,
    > and another table for the data values they point to.  If you do this right,
    > you can do p[x][y], and you can still free both values.  (Because p[0]
    > will be the address of the whole data block you allocated, and p will
    > be the address of the index block.)
    >
    > > Anyway, the spirit of C is don't use p[][] kind?

    >
    > No.
    >
    > > and in my way, I can allocate continues memory for 2-d array. I think
    > > it is better.

    >
    > You still don't get it.
    >
    > You can allocate continuous memory for a 2D array separately from the
    > table for it, and then p[x][y] works.  (Only it's not really a 2D
    > array; it's a 1D array of pointers to data.  But it works like a 2D array.)
    >
    >         int *rows;
    >         int *data;
    >         data = malloc(rows * columns * sizeof(int));
    >         rows = malloc(rows * sizeof(int *);


    2 malloc functions nearby means the space is continus?

    >         for (i = 0; i < rows; ++i) {
    >                  rows = data + (columns * i);
    >                  for (j = 0; 0 < columns; ++j)
    >                         rows[j] = 0;
    >         }
    >
    > Poof!  rows[0][0] is the first integer in the data array, rows[3][4] is
    > the 5th item in the 4th row of the array, and so on.  To free it:
    >
    >         free(rows[0]);
    >         free(rows);
    >
    > Two allocations, but the array contents are continuous.


    You code don't solve the multiple data type issue either, I think.

    John Cui
     
    John, Jan 6, 2010
    #18
  19. John <> writes:
    > On Jan 6, 1:10 pm, Keith Thompson <> wrote:
    >> John <> writes:
    >> > On Jan 6, 12:01 pm, Keith Thompson <> wrote:

    >> [...]
    >> >> You need to pass a valid void** value to ORCdarrayfree.  The question
    >> >> is how you can obtain such a value.  We can't guess at an answer
    >> >> without knowing more about ORCdarrayfree and what you're trying to
    >> >> pass to it.

    >>
    >> > ORCdarrayfree is used to free 2-d array allocated by malloc.
    >> > The src is:

    >>
    >> > /* ORCdarraynew function return void** ,
    >> >    and ORCdarrayfree should get void** to
    >> >    make these 2 functions to be used in
    >> >    allocating integer, char, and other
    >> >    customize type */

    >>
    >> > void**
    >> > ORCdarraynew (int row, int col, int size)

    >>
    >> These should probably be size_t rather than int.

    >
    > Why?


    Because size_t is the appropriate type to represent sizes. Type int
    could be a short as 16 bits, even on a 32-bit system.

    [...]

    >> >    if ( arr != NULL ) {
    >> >       void *head;

    >>
    >> >       head = (void *) arr + sizeof(void *) * row;
    >> >       memset (arr, 0, sizeof(void *) * row + size * row * col);
    >> >       while (row--) {
    >> >          arr[row] = head + size * row * col;
    >> >       }
    >> >    }

    >>
    >> >    return arr;
    >> > } /* End of ORCdarraynew*/

    >>
    >> So you're allocating a chunk of memory consisting of an array of void*
    >> pointers, immediately followed by a 2-dimensional array of some
    >> arbitrary data, where each of the initial void* pointers points to a
    >> row in the 2d array.  Interesting.  Let's call these two sections the
    >> "index" and the "table", respectively.
    >>
    >> You're making some non-portable assumptions, though.
    >>
    >> The memset call zeros both the index and the table.  The former is
    >> useless, since you immediately initialize the table anyway.  Zeroing
    >> the table may or may not be sensiple, depending on what data you're
    >> storing.  Remember that null pointers aren't necessarily all-bits-zero
    >> (though they commonly are).

    >
    > memset is used to init the table and index, why is it wrong?


    As I said, using memset to initialize the index is superfluous, since
    you immediately assign values to every element of the index anyway,
    overwriting all the zeros. As for the table, it can hold any
    arbitrary type. For integer types, memset will set the elements to zero.
    For other types, it may or may not.

    You might consider just leaving the table uninitialized. Typically
    the code that calls ORCdarraynew is going to assign values to it
    anyway.

    Or you can use memset to zero it, but keep in mind that, though this
    will give you consisten results on a given system, those results
    aren't necessarily meaningful.

    >> You're also assuming that the table will be properly aligned.
    >> Consider a system where void* is 32-bit aligned, double is 64-bit
    >> aligned, and you want to allocate a table of doubles with an odd
    >> number of rows.

    >
    > I think double* and double** and void* and void** have same length.
    > then what is your concern?


    Why do you think they have the same length? They very likely do on
    your system, but that's a non-portable assumption.

    Now you're free to write non-portable code if you want to. But
    personally, I find that portable code tends to be cleaner, even if
    it's never actually going to be ported.

    >>
    >> > void
    >> > ORCdarrayfree (void **arr)
    >> > {
    >> >    if ( arr != NULL ) {
    >> >       free (arr);
    >> >       arr = NULL;
    >> >    }
    >> > } /* End of ORCdarrayfree*/

    >>
    >> Note that the "arr != NULL" test is unnecessary; free() does nothing
    >> if you give it a null pointer argument.  And setting arr to NULL is
    >> useless; you're just clobbering a local object.  You might want to do
    >> "*arr = NULL;" -- or you might just want to leave it alone.

    >
    > free(arr) can free all space by malloc, but don't set arr to NULL.
    > I add set arr to NULL is to make the statement after ORCdarrayfree
    > can not use arr.


    arr is a parameter to ORCdarrayfree. It's a local object that ceases
    to exist immediately after you set it to NULL. It's a *copy* of the
    argument passed by the caller. Modifying it has no effect on the
    caller.

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jan 6, 2010
    #19
  20. John

    John Guest

    On Jan 6, 4:42 pm, Keith Thompson <> wrote:
    > John <> writes:
    > > On Jan 6, 1:10 pm, Keith Thompson <> wrote:
    > >> John <> writes:
    > >> > On Jan 6, 12:01 pm, Keith Thompson <> wrote:
    > >> [...]
    > >> >> You need to pass a valid void** value to ORCdarrayfree.  The question
    > >> >> is how you can obtain such a value.  We can't guess at an answer
    > >> >> without knowing more about ORCdarrayfree and what you're trying to
    > >> >> pass to it.

    >
    > >> > ORCdarrayfree is used to free 2-d array allocated by malloc.
    > >> > The src is:

    >
    > >> > /* ORCdarraynew function return void** ,
    > >> >    and ORCdarrayfree should get void** to
    > >> >    make these 2 functions to be used in
    > >> >    allocating integer, char, and other
    > >> >    customize type */

    >
    > >> > void**
    > >> > ORCdarraynew (int row, int col, int size)

    >
    > >> These should probably be size_t rather than int.

    >
    > > Why?

    >
    > Because size_t is the appropriate type to represent sizes.  Type int
    > could be a short as 16 bits, even on a 32-bit system.


    I agree now, thanks.

    >
    > [...]
    >
    >
    >
    > >> >    if ( arr != NULL ) {
    > >> >       void *head;

    >
    > >> >       head = (void *) arr + sizeof(void *) * row;
    > >> >       memset (arr, 0, sizeof(void *) * row + size * row * col);
    > >> >       while (row--) {
    > >> >          arr[row] = head + size * row * col;
    > >> >       }
    > >> >    }

    >
    > >> >    return arr;
    > >> > } /* End of ORCdarraynew*/

    >
    > >> So you're allocating a chunk of memory consisting of an array of void*
    > >> pointers, immediately followed by a 2-dimensional array of some
    > >> arbitrary data, where each of the initial void* pointers points to a
    > >> row in the 2d array.  Interesting.  Let's call these two sections the
    > >> "index" and the "table", respectively.

    >
    > >> You're making some non-portable assumptions, though.

    >
    > >> The memset call zeros both the index and the table.  The former is
    > >> useless, since you immediately initialize the table anyway.  Zeroing
    > >> the table may or may not be sensiple, depending on what data you're
    > >> storing.  Remember that null pointers aren't necessarily all-bits-zero
    > >> (though they commonly are).

    >
    > > memset is used to init the table and index, why is it wrong?

    >
    > As I said, using memset to initialize the index is superfluous, since
    > you immediately assign values to every element of the index anyway,
    > overwriting all the zeros.  As for the table, it can hold any
    > arbitrary type.  For integer types, memset will set the elements to zero.
    > For other types, it may or may not.
    >
    > You might consider just leaving the table uninitialized.  Typically
    > the code that calls ORCdarraynew is going to assign values to it
    > anyway.
    >
    > Or you can use memset to zero it, but keep in mind that, though this
    > will give you consisten results on a given system, those results
    > aren't necessarily meaningful.


    I think the concern here is assign integer 0 to pointer or double in C
    to
    init, Is it wrong?

    >
    > >> You're also assuming that the table will be properly aligned.
    > >> Consider a system where void* is 32-bit aligned, double is 64-bit
    > >> aligned, and you want to allocate a table of doubles with an odd
    > >> number of rows.

    >
    > > I think double* and double** and void* and void** have same length.
    > > then what is your concern?

    >
    > Why do you think they have the same length?  They very likely do on
    > your system, but that's a non-portable assumption.
    >
    > Now you're free to write non-portable code if you want to. But
    > personally, I find that portable code tends to be cleaner, even if
    > it's never actually going to be ported.


    I think in any platform, the pointer have the same length, do you
    think
    so?

    >
    >
    >
    >
    >
    > >> > void
    > >> > ORCdarrayfree (void **arr)
    > >> > {
    > >> >    if ( arr != NULL ) {
    > >> >       free (arr);
    > >> >       arr = NULL;
    > >> >    }
    > >> > } /* End of ORCdarrayfree*/

    >
    > >> Note that the "arr != NULL" test is unnecessary; free() does nothing
    > >> if you give it a null pointer argument.  And setting arr to NULL is
    > >> useless; you're just clobbering a local object.  You might want to do
    > >> "*arr = NULL;" -- or you might just want to leave it alone.

    >
    > > free(arr) can free all space by malloc, but don't set arr to NULL.
    > > I add set arr to NULL is to make the statement after ORCdarrayfree
    > > can not use arr.

    >
    > arr is a parameter to ORCdarrayfree.  It's a local object that ceases
    > to exist immediately after you set it to NULL.  It's a *copy* of the
    > argument passed by the caller.  Modifying it has no effect on the
    > caller.
    >


    Hmm, yes, arr is a local variable, just free(arr) is enough. thanks.


    John Cui
     
    John, Jan 6, 2010
    #20
    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. Ollej Reemt
    Replies:
    7
    Views:
    537
    Jack Klein
    Apr 22, 2005
  2. Schnoffos
    Replies:
    2
    Views:
    1,219
    Martien Verbruggen
    Jun 27, 2003
  3. Stig Brautaset

    `void **' revisited: void *pop(void **root)

    Stig Brautaset, Oct 25, 2003, in forum: C Programming
    Replies:
    15
    Views:
    791
    The Real OS/2 Guy
    Oct 28, 2003
  4. Replies:
    5
    Views:
    841
    S.Tobias
    Jul 22, 2005
  5. Replies:
    1
    Views:
    411
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page