Reputation: 107
While trying to learn C by myself, I came across this simple program that I want to develop. It just tries to make use of pointer to pointer arrays to make something that resembles matrices. I'm compiling on Windows and when I run it, it just crashes, meanwhile, trying this code on Linux it says segmentation fault
, is this because of the function arguments that are arrays? What am I doing wrong here?
#include <stdio.h>
#include <stdlib.h>
void initializeArray(float** array, int size);
void printArray(float** array, int size);
int main()
{
float** array_1 = NULL;
int array_size = 3;
initializeArray(array_1, array_size);
// Free memory from array
for (int i = 0; i < array_size; i++)
{
free(array_1[i]);
}
free(array_1);
return 0;
}
void initializeArray(float** array, int size)
{
array = malloc(size * sizeof(float*));
if (array)
{
for (int i = 0; i < size; i++)
{
array[i] = malloc(size * sizeof(float));
if (!array[i])
{
exit(0);
}
}
}
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = 0;
}
}
}
void printArray(float** array, int size)
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
printf("%f\t", array[i][j]);
}
printf("\n");
}
}
Upvotes: 0
Views: 73
Reputation: 123448
If you want a function to modify the value of a parameter, you must pass a pointer to that parameter:
void foo( T *ptr )
{
*ptr = new_value(); // write a new value to the thing ptr points to
}
void bar( void )
{
T var;
foo( &var ); // write a new value to var
}
This is true for any type T
, including pointer types. Replace T
with P *
, and we get
void foo( P **ptr )
{
*ptr = new_value(); // write a new value to the thing ptr points to
}
void bar( void )
{
P *var;
foo( &var ); // write a new *pointer* value to var
}
Basically, whatever the type of var
, you need one more level of indirection for ptr
.
Applying that to your code:
void initializeArray(float*** array, int size)
{
*array = malloc(size * sizeof(float*));
if (*array)
{
for (int i = 0; i < size; i++)
{
(*array)[i] = malloc(size * sizeof(float)); // parens matter; you want
if (!(*array)[i]) // to index into what array *points
{ // to*, not array itself
exit(0);
}
}
}
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
(*array)[i][j] = 0;
}
}
}
which would be called from main
as:
initializeArray(&array_1, array_size);
A couple of suggestions:
First, when calling malloc
, make the operand of the sizeof
operator your dereferenced target, rather than a type name:
ptr = malloc( N * sizeof *ptr );
In your case, it would be
*array = malloc( size * sizeof **array ); // sizeof operand has one more level of
// indirection than target
and
(*array)[i] = malloc( size * sizeof *(*array)[i] );
This will protect you if you change the type of array
; you don't have to chase down every instance of sizeof (float)
or sizeof (float *)
and change those.
Secondly, what you're allocating isn't a 2D array - it's an array of pointers, each of which points to a separate array of float
. Which is perfectly fine, depending on what you're doing, just be aware that the rows are not adjacent in memory - the object following array[1][2]
is not going to be array[2][0]
.
If you want to allocate a contiguous, multi-dimensional array, you'd use something like
float (*array)[3] = malloc( 3 * sizeof *array );
That sets aside space for a contiguous 3x3 array. With VLA syntax, you could write a function like
void initializeArray( size_t rows, size_t cols, float (**array)[cols] )
{
*array = malloc( rows * sizeof **array );
if ( *array )
{
for ( size_t i = 0; i < rows; i++ )
for ( size_t j = 0; j < rows; j++ )
(*array)[i][j] = initial_value();
}
}
Upvotes: 0
Reputation: 140158
when doing:
void initializeArray(float** array, int size)
{
array = malloc(size * sizeof(float*));
you're not changing array
outside the function so array_1
points to NULL after (like before) the call (and creates a memory leak). You need to return it (or to pass it as triple ***
pointer and use it as *array
, but that's less convenient).
float **initializeArray(int size)
{
float** array = malloc(size * sizeof(float*));
...
return array;
}
and from main:
array_1 = initializeArray(array_size);
Upvotes: 1