Reputation: 45
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
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
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
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