Zni
Zni

Reputation: 45

C: Initializing a dynamic array inside a struct

I'm trying to implement my own basic version of matrix multiplication in C and based on another implementation, I have made a matrix data type. The code works, but being a C novice, I do not understand why.

The issue: The I have a struct with a dynamic array inside it and I am initializing the pointer. See below:

// Matrix data type
typedef struct
{
    int rows, columns;      // Number of rows and columns in the matrix
    double *array;          // Matrix elements as a 1-D array
} matrix_t, *matrix;

// Create a new matrix with specified number of rows and columns
// The matrix itself is still empty, however
matrix new_matrix(int rows, int columns)
{
    matrix M = malloc(sizeof(matrix_t) + sizeof(double) * rows * columns);
    M->rows = rows;
    M->columns = columns;
    M->array = (double*)(M+1); // INITIALIZE POINTER
    return M;
}

Why do I need to initialize the array to (double*)(M+1)? It seems that also (double*)(M+100) works ok, but e.g. (double *)(M+10000) does not work anymore, when I run my matrix multiplication function.

Upvotes: 3

Views: 6716

Answers (3)

Medinoc
Medinoc

Reputation: 6618

The recommended method for this kind of stuff is unsized array used in conjunction with offsetof. It ensures correct alignment.

#include <stddef.h>
#include <stdlib.h>

// Matrix data type
typedef struct s_matrix
{
    int rows, columns;      // Number of rows and columns in the matrix
    double array[];         // Matrix elements as a 1-D array
} matrix;

// Create a new matrix with specified number of rows and columns
// The matrix itself is still empty, however
matrix* new_matrix(int rows, int columns)
{
    size_t size = offsetof(matrix_t, array) + sizeof(double) * rows * columns;
    matrix* M = malloc(size);
    M->rows = rows;
    M->columns = columns;
    return M;
}

Upvotes: 3

unwind
unwind

Reputation: 400109

You need to initialize it because otherwise (wait for it) it's uninitialized!

And you can't use an uninitialized pointer for anything, except to generate undefined behavior.

Initializing it to M + 1 is precisely right, and very good code. Any other value would fail to use the memory you allocated for this exact purpose.

My point is that the double * at the end of struct won't "automatically" point at this memory, which is the implied belief in your question why it should be initialized. Thus, it has to be set to the proper address.

Upvotes: 0

NPE
NPE

Reputation: 500893

M+1 points to the memory that immediately follows M (i.e. that follows the two int and the double*). This is the memory you've allocated for the matrix data:

matrix M = malloc(sizeof(matrix_t) + sizeof(double) * rows * columns);
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Using M+100 or M+10000 and then attempting to populate the matrix will result in undefined behaviour. This could result in a program that crashes, or a program that appears to work (but in reality is broken), or anything in between.

Upvotes: 2

Related Questions