Still having trouble with malloc

G

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;
}
 
J

Joona I Palaste

(e-mail address removed) 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 ([email protected]) ---------------------------\
| 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
 
G

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 said:
(e-mail address removed) 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 ([email protected]) ---------------------------\
| 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
 
J

Joona I Palaste

(e-mail address removed) 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 ([email protected]) ---------------------------\
| 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
 
G

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 said:
(e-mail address removed) 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 ([email protected]) ---------------------------\
| 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
 
J

Joona I Palaste

(e-mail address removed) 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.
Joona I Palaste said:
(e-mail address removed) 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 ([email protected]) ---------------------------\
| 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
 
N

Nick Austin

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.
 
B

Barry Schwarz

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>>
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,158
Latest member
Vinay_Kumar Nevatia
Top