0

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");
    }
}

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

3 Comments

(and being a triple-star programmer isn't a compliment)
yes, three star programmer: you tend to avoid that.
@Jean-FrançoisFabre ah, I see, didn't notice that, but after that, how should I call the function inside main()? Is it enough to assign it to array_1?
0

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();
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.