Still having trouble with malloc

Discussion in 'C Programming' started by Guest, Oct 6, 2003.

  1. Guest

    Guest Guest

    I fail to understand why that the memory allocated in the void
    create(int **matrix) does not remain. I passed the address of matrix so
    shouldn't it still have the allocated memory when it returns to main.
    The problem i am having is understanding why the printf statement in the
    code below gives the value. I would have expected it to be 123 which is
    the value I set it to in the create. Thanx in advance.

    void create(int **matrix);

    int main(void)
    {
    int **matrix;
    create(matrix);

    printf("%d", matrix[1][1]); /* ? */
    }

    void create(int **matrix)
    { /*allocating mem for 2 by 3 int matrix*/
    matrix = (int **)malloc(2*sizeof(int *));
    matrix[0] = (int *)malloc(3*sizeof(int));
    matrix[1] = (int *)malloc(3*sizeof(int));

    matrix[1][1] = 123;
    }
     
    Guest, Oct 6, 2003
    #1
    1. Advertising

  2. scribbled the following:
    > I fail to understand why that the memory allocated in the void
    > create(int **matrix) does not remain. I passed the address of matrix so
    > shouldn't it still have the allocated memory when it returns to main.
    > The problem i am having is understanding why the printf statement in the
    > code below gives the value. I would have expected it to be 123 which is
    > the value I set it to in the create. Thanx in advance.


    > void create(int **matrix);


    > int main(void)
    > {
    > int **matrix;
    > create(matrix);


    > printf("%d", matrix[1][1]); /* ? */
    > }


    > void create(int **matrix)
    > { /*allocating mem for 2 by 3 int matrix*/
    > matrix = (int **)malloc(2*sizeof(int *));


    This line above should be a clear indication of what is wrong.

    > matrix[0] = (int *)malloc(3*sizeof(int));
    > matrix[1] = (int *)malloc(3*sizeof(int));


    > matrix[1][1] = 123;
    > }


    You are experiencing the C parameter passing model. In C, all parameters
    are passed by value. Without exception. The fact that the value's type
    is a pointer (such as in this case) does not magically transform pass by
    value into pass by reference.
    If you find yourself assigning a new value to a function parameter in
    the function, such as you are doing above, it's pretty darn near certain
    that you have a design fault. The assignment will have exactly zilch
    effect outside the function, as the parameter is a separate entity from
    what was inside the parantheses in the call statement.
    Instead, pass a pointer to your matrix like this:
    create(&matrix);
    And write your create function like this:
    void create(int ***matrix) /* note three * signs, not two */
    { /*allocating mem for 2 by 3 int matrix*/
    *matrix = (int **)malloc(2*sizeof(int *));
    (*matrix)[0] = (int *)malloc(3*sizeof(int));
    (*matrix)[1] = (int *)malloc(3*sizeof(int));
    (*matrix)[1][1] = 123;
    }
    Also remember to #include <stdlib.h>, in which case you can safely
    drop the casts.

    --
    /-- Joona Palaste () ---------------------------\
    | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    | http://www.helsinki.fi/~palaste W++ B OP+ |
    \----------------------------------------- Finland rules! ------------/
    "The large yellow ships hung in the sky in exactly the same way that bricks
    don't."
    - Douglas Adams
     
    Joona I Palaste, Oct 6, 2003
    #2
    1. Advertising

  3. Guest

    Guest Guest

    I thought I was passing by pointer when I call the function create(matrix).
    Isn't matrix by itself the first element address of matrix
    (&matrix[0][0]).Thanx again in advance.

    Joseph

    "Joona I Palaste" <> wrote in message
    news:bls22e$5u6$...
    > scribbled the following:
    > > I fail to understand why that the memory allocated in the void
    > > create(int **matrix) does not remain. I passed the address of matrix so
    > > shouldn't it still have the allocated memory when it returns to main.
    > > The problem i am having is understanding why the printf statement in the
    > > code below gives the value. I would have expected it to be 123 which is
    > > the value I set it to in the create. Thanx in advance.

    >
    > > void create(int **matrix);

    >
    > > int main(void)
    > > {
    > > int **matrix;
    > > create(matrix);

    >
    > > printf("%d", matrix[1][1]); /* ? */
    > > }

    >
    > > void create(int **matrix)
    > > { /*allocating mem for 2 by 3 int matrix*/
    > > matrix = (int **)malloc(2*sizeof(int *));

    >
    > This line above should be a clear indication of what is wrong.
    >
    > > matrix[0] = (int *)malloc(3*sizeof(int));
    > > matrix[1] = (int *)malloc(3*sizeof(int));

    >
    > > matrix[1][1] = 123;
    > > }

    >
    > You are experiencing the C parameter passing model. In C, all parameters
    > are passed by value. Without exception. The fact that the value's type
    > is a pointer (such as in this case) does not magically transform pass by
    > value into pass by reference.
    > If you find yourself assigning a new value to a function parameter in
    > the function, such as you are doing above, it's pretty darn near certain
    > that you have a design fault. The assignment will have exactly zilch
    > effect outside the function, as the parameter is a separate entity from
    > what was inside the parantheses in the call statement.
    > Instead, pass a pointer to your matrix like this:
    > create(&matrix);
    > And write your create function like this:
    > void create(int ***matrix) /* note three * signs, not two */
    > { /*allocating mem for 2 by 3 int matrix*/
    > *matrix = (int **)malloc(2*sizeof(int *));
    > (*matrix)[0] = (int *)malloc(3*sizeof(int));
    > (*matrix)[1] = (int *)malloc(3*sizeof(int));
    > (*matrix)[1][1] = 123;
    > }
    > Also remember to #include <stdlib.h>, in which case you can safely
    > drop the casts.
    >
    > --
    > /-- Joona Palaste () ---------------------------\
    > | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    > | http://www.helsinki.fi/~palaste W++ B OP+ |
    > \----------------------------------------- Finland rules! ------------/
    > "The large yellow ships hung in the sky in exactly the same way that

    bricks
    > don't."
    > - Douglas Adams
     
    Guest, Oct 6, 2003
    #3
  4. scribbled the following:
    > I thought I was passing by pointer when I call the function create(matrix).


    You are passing a value. That value's type is a pointer.

    > Isn't matrix by itself the first element address of matrix
    > (&matrix[0][0]).Thanx again in advance.


    No. It begins at the same address but its type is different.
    matrix is of type int **
    matrix[0] is of type int *
    matrix[0][0] is of type int
    &matrix[0][0] is of type int *

    (void *)matrix == (void *)&matrix[0][0] is guaranteed to equal true
    but that doesn't mean that they are the same thing. They aren't even
    assignment-compatible.

    You seem to bestow some magical properties on the fact that your
    function parameter has a pointer type. You need to get rid of those.
    It helps to think of the function parameter as a variable, like
    "matrix" in your main() function.
    Consider this code:
    int **matrix;
    int **matrix_backup;
    matrix_backup = matrix;
    matrix_backup = malloc(100 * sizeof(int *));
    matrix[0] = malloc(100 * sizeof(int));
    Assume (for the sake of simplicity) that malloc() always succeeds.
    What do you think this sample code does, and why? The code you
    submitted is doing the equivalent of this.

    (snip)

    --
    /-- Joona Palaste () ---------------------------\
    | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    | http://www.helsinki.fi/~palaste W++ B OP+ |
    \----------------------------------------- Finland rules! ------------/
    "Normal is what everyone else is, and you're not."
    - Dr. Tolian Soran
     
    Joona I Palaste, Oct 6, 2003
    #4
  5. Guest

    Guest Guest

    matrix_backup is getting allocated memory for 100 int * and matrix[0] is
    getting memory allocated for 100 int. But there is no relation between
    matrix_backup and matrix. The matrix_backup = matrix is a redundant
    statement. Am I correct? It still all fuzzy for me.

    Joseph

    "Joona I Palaste" <> wrote in message
    news:bls48p$77m$...
    > scribbled the following:
    > > I thought I was passing by pointer when I call the function

    create(matrix).
    >
    > You are passing a value. That value's type is a pointer.
    >
    > > Isn't matrix by itself the first element address of matrix
    > > (&matrix[0][0]).Thanx again in advance.

    >
    > No. It begins at the same address but its type is different.
    > matrix is of type int **
    > matrix[0] is of type int *
    > matrix[0][0] is of type int
    > &matrix[0][0] is of type int *
    >
    > (void *)matrix == (void *)&matrix[0][0] is guaranteed to equal true
    > but that doesn't mean that they are the same thing. They aren't even
    > assignment-compatible.
    >
    > You seem to bestow some magical properties on the fact that your
    > function parameter has a pointer type. You need to get rid of those.
    > It helps to think of the function parameter as a variable, like
    > "matrix" in your main() function.
    > Consider this code:
    > int **matrix;
    > int **matrix_backup;
    > matrix_backup = matrix;
    > matrix_backup = malloc(100 * sizeof(int *));
    > matrix[0] = malloc(100 * sizeof(int));
    > Assume (for the sake of simplicity) that malloc() always succeeds.
    > What do you think this sample code does, and why? The code you
    > submitted is doing the equivalent of this.
    >
    > (snip)
    >
    > --
    > /-- Joona Palaste () ---------------------------\
    > | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    > | http://www.helsinki.fi/~palaste W++ B OP+ |
    > \----------------------------------------- Finland rules! ------------/
    > "Normal is what everyone else is, and you're not."
    > - Dr. Tolian Soran
     
    Guest, Oct 6, 2003
    #5
  6. scribbled the following:
    > matrix_backup is getting allocated memory for 100 int * and matrix[0] is
    > getting memory allocated for 100 int. But there is no relation between
    > matrix_backup and matrix. The matrix_backup = matrix is a redundant
    > statement. Am I correct? It still all fuzzy for me.


    You are sort of correct here. There is no inherent relation between
    matrix and matrix_backup. So the operation matrix[0] = malloc(100 *
    sizeof(int)) will cause undefined behaviour, since what has been
    previously allocated is matrix_backup, not matrix.
    Now the gist of the thing: Calling the create() function is doing the
    same! The parameter "matrix" in the create() function is pretty much
    like matrix_backup in the example code I posted. This is a crucial thing
    to understand when writing C functions.

    > Joseph


    > "Joona I Palaste" <> wrote in message
    > news:bls48p$77m$...
    >> scribbled the following:
    >> > I thought I was passing by pointer when I call the function

    > create(matrix).
    >>
    >> You are passing a value. That value's type is a pointer.
    >>
    >> > Isn't matrix by itself the first element address of matrix
    >> > (&matrix[0][0]).Thanx again in advance.

    >>
    >> No. It begins at the same address but its type is different.
    >> matrix is of type int **
    >> matrix[0] is of type int *
    >> matrix[0][0] is of type int
    >> &matrix[0][0] is of type int *
    >>
    >> (void *)matrix == (void *)&matrix[0][0] is guaranteed to equal true
    >> but that doesn't mean that they are the same thing. They aren't even
    >> assignment-compatible.
    >>
    >> You seem to bestow some magical properties on the fact that your
    >> function parameter has a pointer type. You need to get rid of those.
    >> It helps to think of the function parameter as a variable, like
    >> "matrix" in your main() function.
    >> Consider this code:
    >> int **matrix;
    >> int **matrix_backup;
    >> matrix_backup = matrix;
    >> matrix_backup = malloc(100 * sizeof(int *));
    >> matrix[0] = malloc(100 * sizeof(int));
    >> Assume (for the sake of simplicity) that malloc() always succeeds.
    >> What do you think this sample code does, and why? The code you
    >> submitted is doing the equivalent of this.


    --
    /-- Joona Palaste () ---------------------------\
    | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    | http://www.helsinki.fi/~palaste W++ B OP+ |
    \----------------------------------------- Finland rules! ------------/
    "The obvious mathematical breakthrough would be development of an easy way to
    factor large prime numbers."
    - Bill Gates
     
    Joona I Palaste, Oct 6, 2003
    #6
  7. Guest

    Nick Austin Guest

    On Mon, 06 Oct 2003 15:23:44 GMT, <> wrote:

    >I fail to understand why that the memory allocated in the void
    >create(int **matrix) does not remain. I passed the address of matrix so
    >shouldn't it still have the allocated memory when it returns to main.
    >The problem i am having is understanding why the printf statement in the
    >code below gives the value. I would have expected it to be 123 which is
    >the value I set it to in the create. Thanx in advance.
    >
    >void create(int **matrix);
    >
    >int main(void)
    >{
    >int **matrix;
    >create(matrix);


    First problem. This passes the value of an argument to the
    function create. In this case it is an unitialised pointer
    so its value is useless.

    >printf("%d", matrix[1][1]); /* ? */


    Second problem. The array dimensions of matrix are unknown
    at this point. At the very least matrix needs to be defined
    so that the second array dimension is known.

    >}
    >
    >void create(int **matrix)
    >{ /*allocating mem for 2 by 3 int matrix*/
    >matrix = (int **)malloc(2*sizeof(int *));
    >matrix[0] = (int *)malloc(3*sizeof(int));
    >matrix[1] = (int *)malloc(3*sizeof(int));


    This is also confused. It looks as though you are attempting
    to create an array of two pointers each of which points to an
    array of three ints.

    >matrix[1][1] = 123;
    >}


    Personally I don't see the advantage of passing via a function
    argument, so I'd rewrite it to use the return value instead:

    #include <stdio.h>
    #include <stdlib.h>

    int (*create(void))[2][3];

    int main(void)
    {
    int (*matrix)[][3];

    matrix = create();

    if ( matrix )
    printf( "%d", (*matrix)[1][1] );
    else
    printf( "Cannot allocate memory\n" );
    return 0;
    }

    int (*create(void))[2][3]
    {
    int (*matrix)[][3];

    /*allocating mem for 2 by 3 int matrix*/
    matrix = malloc( 2*3*sizeof(int) );

    if ( matrix )
    {
    (*matrix)[1][1] = 123;
    }
    return matrix;
    }

    Nick.
     
    Nick Austin, Oct 6, 2003
    #7
  8. On Mon, 06 Oct 2003 18:01:00 +0100, Nick Austin
    <> wrote:

    >On Mon, 06 Oct 2003 15:23:44 GMT, <> wrote:
    >
    >>I fail to understand why that the memory allocated in the void
    >>create(int **matrix) does not remain. I passed the address of matrix so
    >>shouldn't it still have the allocated memory when it returns to main.
    >>The problem i am having is understanding why the printf statement in the
    >>code below gives the value. I would have expected it to be 123 which is
    >>the value I set it to in the create. Thanx in advance.
    >>
    >>void create(int **matrix);
    >>
    >>int main(void)
    >>{
    >>int **matrix;
    >>create(matrix);

    >
    >First problem. This passes the value of an argument to the
    >function create. In this case it is an unitialised pointer
    >so its value is useless.


    It is worse than useless. Passing an uninitialized value to a
    function invokes undefined behavior.

    >
    >>printf("%d", matrix[1][1]); /* ? */

    >
    >Second problem. The array dimensions of matrix are unknown
    >at this point. At the very least matrix needs to be defined
    >so that the second array dimension is known.


    Since matrix is not an array, it doesn't have dimensions and the
    compiler doesn't need to know them. The successful evaluation of
    matrix[1][1] requires only the following:
    matrix point to an area properly aligned and having enough space
    for two pointers to int.
    matrix[1], which is the second pointer to int in the area
    describe above, contain a value, actually the address, of an area
    properly aligned and having enough space for two int.
    matrix[1][1] contain a valid int value.

    While it is not part of the OP's question, one of the potential
    advantages of using an int** is that the dimension of each row can be
    different, sometimes called a jagged matrix or jagged array.

    snip


    <<Remove the del for email>>
     
    Barry Schwarz, Oct 7, 2003
    #8
    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. bjg
    Replies:
    15
    Views:
    569
    kchayka
    Dec 14, 2003
  2. John
    Replies:
    13
    Views:
    723
  3. ravi
    Replies:
    0
    Views:
    471
  4. Peter
    Replies:
    34
    Views:
    2,024
    Richard Tobin
    Oct 22, 2004
  5. porting non-malloc code to malloc

    , Feb 18, 2005, in forum: C Programming
    Replies:
    3
    Views:
    492
    Walter Roberson
    Feb 19, 2005
Loading...

Share This Page