What do I want to do?
I'm working on a project on dynamic matrix multiplication. I want to input from the user that on how many matrices, he/she wants to perform multiplication and based on that I want to create a struct something like below:
typedef struct
{
size_t rows, columns;
int table[];
} Matrix;
And after that, check for the validation of the matrices to be multiplied (using very simple maths).
Then create an array of Matrix
types and allocate memory to it depending on the number of matrices the user wants to multiply.
+---------------------------------------------------------------------------------------------------+
| +------------------------------+ +---------------------------------------------------------+ |
| | Matrix struct type array | | ..... More arrays depending on the number of matrices. | |
| +------------------------------+ +---------------------------------------------------------+ |
+---------------------------------------------------------------------------------------------------+
Eg. 2 Matrices [2][2] & [2][1]
+----------------> rows <-------------+
| |
| +------------> columns <-----------|--+
| | | |
| | +------------------------+ | | +------------------+
{ { 2, 2, | { { 1, 2 }, { 2, 1 } } | }, { 2, 1, | { { 1 }, { 3 } } | } }
+------------------------+ +------------------+
| |
| |
| |
v v
| 1 2 | | 1 |
| | | |
| 2 1 | | 3 |
Reasons for creating an array of struct type
There is one thing that might seem odd to some of my fellow readers of this question, which is, why I want to make an array of types struct Matrix
, instead of creating 2 different objects of the type and performing the multiplication on "user_defined_matrix"->table
. Well, the reasons are listed below:
- Scalability, as every constraint is user-defined I want things to be as flexible as possible. One way of thinking about this is, suppose the user wants multiplication between 15 matrices, then you don't want to declare 15 objects of types
struct Matrix
. - Accessibility, accessing every matrix would become so easy with the help of for loop.
Now back to the topic, after allocation of memory, I want the user to fill each slot of the matrix and then perform the multiplication on them and generate the result.
What I have done so far
Note: I know that you cannot declare a true 2d VLA inside a struct, you have to first declare a 1d array which later becomes a mangled version of a 2d array and before using it typecast it to a 2d array as shown in this answer.
I have made a true 2d array to store user-inputted rows and columns.
int dimensions[NUMBER_OF_MATRIX][2];
Then using these dimensions
, I calculated how much memory I have to allocate.
int total_matrix_size = 0;
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
total_matrix_size += (dimensions[i][0] * dimensions[i][1]);
}
And then use the total_matrix_size
to allocate memory to the array of types struct Martix
.
Matrix *matrix = malloc(((sizeof *matrix) * NUMBER_OF_MATRIX) + sizeof(int[total_matrix_size]));
After that, I am asking the user to fill the matrix, before filling the matrix I'm typecasting the array to a 2d array with the help of a macro in the code below.
Note: I'll be referring to the below code block many times so for the sake of simplicity, let's name this input block.
#define get_array(arr) \
_Generic((arr), \
Matrix \
: (int(*)[(arr).columns])(arr).table)
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
matrix[i].rows = dimensions[i][0];
matrix[i].columns = dimensions[i][1];
for (uint x = 0; x < matrix[i].rows; x++)
{
for (uint y = 0; y < matrix[i].columns; y++)
{
printf("Enter values of matrix %d a[%dx%d] : ", i + 1, x + 1, y + 1);
scanf("%d", &get_array(matrix[i])[x][y]);
printf("%d\n", get_array(matrix[i])[x][y]); // print statement 1
}
}
}
Then just for testing purposes, I'm printing all the matrices.
Note: I'll be referring to the below code block many times so for the sake of simplicity, let's name this output block.
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
printf("Matrix %d\n", i+1);
for (uint x = 0; x < matrix[i].rows; x++)
{
for (uint y = 0; y < matrix[i].columns; y++)
{
printf("%d ", get_array(matrix[i])[x][y]); // print statement 2
}
printf("\n");
}
}
So, where is the problem?
As you can see I've written 2 exactly the same print statements in the above 2 code blocks, input and output blocks.
printf("%d ", get_array(matrix[i])[x][y]);
But both of them are generating different outputs. Output generated by input block.
Enter the rows of matrix 1 : 2 2
Enter the rows of matrix 2 : 2 2
Enter values of matrix 1 a[1x1] : 1
1
Enter values of matrix 1 a[1x2] : 0
0
Enter values of matrix 1 a[2x1] : 1
1
Enter values of matrix 1 a[2x2] : 0
0
Enter values of matrix 2 a[1x1] : 2
2
Enter values of matrix 2 a[1x2] : 3
3
Enter values of matrix 2 a[2x1] : 2
2
Enter values of matrix 2 a[2x2] : 3
3
Printed everything as expected.
But not the same for output block.
Matrix 1
2 2
2 3
Matrix 2
2 3
2 3
What do I expect from the answers?
Nothing but a deep dive explanation for :
- Why print statement is working in the input block & why not in the output block.
- If this is not the correct way of allocating memory, then what is?
- If my approach is totally wrong then what should it be?
Please keep the format somewhat like this answer.
Here is the whole code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// TODO Preprocessors
#define get_array(arr) \
_Generic((arr), \
Matrix \
: (int(*)[(arr).columns])(arr).table)
// TODO Custom types
typedef unsigned int uint;
// TODO Structs
typedef struct
{
uint rows, columns;
int table[];
} Matrix;
// TODO Function Declarations
void flushBuffer(void);
int main(void)
{
int NUMBER_OF_MATRIX = 2;
int dimensions[NUMBER_OF_MATRIX][2];
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
printf("Enter the rows of matrix %d : ", i + 1);
scanf("%d %d", &dimensions[i][0], &dimensions[i][1]);
flushBuffer();
}
if (dimensions[0][1] != dimensions[1][0])
{
printf("Matrix multiplication not possible.");
}
else
{
int total_matrix_size = 0;
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
total_matrix_size += (dimensions[i][0] * dimensions[i][1]);
}
Matrix *matrix = malloc(((sizeof *matrix) * NUMBER_OF_MATRIX) + sizeof(int[total_matrix_size]));
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
matrix[i].rows = dimensions[i][0];
matrix[i].columns = dimensions[i][1];
for (uint x = 0; x < matrix[i].rows; x++)
{
for (uint y = 0; y < matrix[i].columns; y++)
{
printf("Enter values of matrix %d a[%dx%d] : ", i + 1, x + 1, y + 1);
scanf("%d", &get_array(matrix[i])[x][y]);
printf("%d\n", get_array(matrix[i])[x][y]);
}
}
}
for (uint i = 0; i < NUMBER_OF_MATRIX; i++)
{
printf("Matrix divider\n");
for (uint x = 0; x < matrix[i].rows; x++)
{
for (uint y = 0; y < matrix[i].columns; y++)
{
printf("%d ", get_array(matrix[i])[x][y]);
}
printf("\n");
}
}
}
return 0;
}
// TODO Function Definitions
void flushBuffer(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
;
}