Printing a matrix causes a segmentation fault - c

I tried to print a matrix based on this code but somehow it causes a segmentation fault.
I want to transfer the given arrays to the struct member data and then print them out by referecing to data.
I scanned through it but I cannot find my mistake. Maybe I messed up when allocating memory for the structure.
#include "base.h"
struct Matrix {
int rows; // number of rows
int cols; // number of columns
double** data; // a pointer to an array of n_rows pointers to rows; a row is an array of n_cols doubles
};
typedef struct Matrix Matrix;
Matrix* make_matrix(int n_rows, int n_cols) {
Matrix* mat = xcalloc(n_rows,sizeof(double*));
mat->rows = n_rows;
mat->cols = n_cols;
return mat;
}
Matrix* copy_matrix(double* data, int n_rows, int n_cols) {
Matrix* mat = make_matrix(n_rows, n_cols);
for(int i = 0; i < (mat->rows); i++)
{
for(int j = 0; j < (mat->cols); j++)
{
mat->data[i][j] = data[i] + j;
}
}
return mat;
}
void print_matrix(Matrix* m)
{
for(int i = 0; i < (m->rows); i++)
{
for(int j = 0; j < (m->cols); j++)
{
printf("%g", m->data[i][j]);
}
}
}
void matrix_test(void) {
double a[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9 };
Matrix* m1 = copy_matrix(a, 3, 3);
print_matrix(m1);
double a2[] = {
1, 2, 3,
4, 5, 6 };
Matrix* m2 = copy_matrix(a2, 2, 3);
print_matrix(m2);
double a3[] = {
1, 2,
3, 4,
5, 6 };
Matrix* m3 = copy_matrix(a3, 3, 2);
print_matrix(m3);
}

In this particular example, there is no obvious reason why you should allocate the struct itself dynamically, since it's just 3 items. Because this is plain wrong:
Matrix* mat = xcalloc(n_rows,sizeof(double*));
Either you have to allocate room for the struct and its pointer array separately, or you can just skip dynamic allocation of the struct and then only allocate room for the data member.
Furthermore xcalloc(n_rows,sizeof(double*)); only allocates room for an array of pointers, not what those pointers point at. So you need to allocate room for each data item too, in a separate loop.
Furthermore, using a pointer array for a matrix is almost certainly needlessly obscure and inefficient practice. Instead you should use a 2D array as shown here: Correctly allocating multi-dimensional arrays
You should also free() all memory that you allocated.
Here is a cleaned up example where I replaced the pointer to pointer with a so-called "flexible array member". This has the advantage of allocating the struct together with the data for faster access. Also all the problems with fragmented allocation will be gone.
The down side is that a flexible array member has to to be regarded as a flat 1D array, so we have to cast to a pointer to 2D array type before using it with array[i][j] syntax.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
size_t rows;
size_t cols;
double data[];
} Matrix;
Matrix* make_matrix (size_t n_rows, size_t n_cols) {
Matrix* mat = malloc(sizeof(Matrix) + sizeof(double[n_rows][n_cols]));
if(mat == NULL)
{
return NULL;
}
mat->rows = n_rows;
mat->cols = n_cols;
return mat;
}
Matrix* copy_matrix (const double* data, size_t n_rows, size_t n_cols) {
Matrix* mat = make_matrix(n_rows, n_cols);
double (*new_data)[mat->cols];
new_data = (double(*)[mat->cols]) mat->data;
for(size_t i = 0; i < mat->rows; i++)
{
for(size_t j = 0; j < mat->cols; j++)
{
new_data[i][j] = data[i] + j;
}
}
return mat;
}
void print_matrix (const Matrix* mat)
{
double (*data)[mat->cols];
data = (double(*)[mat->cols]) mat->data;
for(size_t i = 0; i < mat->rows; i++)
{
for(size_t j = 0; j < mat->cols; j++)
{
printf("%g ", data[i][j]);
}
printf("\n");
}
}
int main (void) {
double a[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9 };
Matrix* m1 = copy_matrix(a, 3, 3);
print_matrix(m1);
puts("");
double a2[] = {
1, 2, 3,
4, 5, 6 };
Matrix* m2 = copy_matrix(a2, 2, 3);
print_matrix(m2);
puts("");
double a3[] = {
1, 2,
3, 4,
5, 6 };
Matrix* m3 = copy_matrix(a3, 3, 2);
print_matrix(m3);
free(m1);
free(m2);
free(m3);
}

Related

how to implement matrix multiplication in C?

I was trying to create an algorithm to perform matrix multiplication.
I've designed matrix as follows:
// matrix.h
#pragma once
#include <stdlib.h>
#include <string.h>
struct matrix {
size_t rows, cols;
double* data;
};
extern struct matrix* mat_mul(const struct matrix* m1, const struct matrix* m2);
// matrix.c
#include "matrix.h"
void mat_constr(struct matrix* m, size_t rows, size_t cols) {
m->rows = rows; m->cols = cols;
m->data = calloc(rows * cols, sizeof(double));
if (!m->data) {
return;
}
}
void mat_destr(struct matrix* m) {
free(m->data);
}
mat_constr is matrix constructor, and mat_destr is mat_destructor. To test the algorithm I've used this main
// main
int main(void) {
struct matrix A;
mat_constr(&A, 2, 3);
memcpy(A.data, (double[6]) { 1, 2, 3, 4, 5, 6 }, 6 * sizeof(double));
struct matrix B;
mat_constr(&B, 3, 2);
memcpy(B.data, (double[6]) { 7, 8, 9, 10, 11, 12 }, 6 * sizeof(double));
struct matrix* C = mat_mul(&A, &B);
mat_destr(&A); mat_destr(&B);
mat_destr(C);
return 0;
}
and this is the mat_mul function
struct matrix* mat_mul(const struct matrix* m1, const struct matrix* m2) {
if ((m1 == NULL) || (m2 == NULL)) {
return NULL;
}
if (m1->cols != m2->rows) {
return NULL;
}
struct matrix* result = malloc(sizeof(struct matrix));
if (!result) {
return NULL;
}
mat_constr(result, m1->rows, m2->cols);
size_t k = 1;
for (size_t r = 0; r < m1->rows; r++) {
for (size_t c = 0; c < m1->cols; c++) {
result->data[r * result->cols + c] = m1->data[r * m1->cols + k] * m2->data[k * m2->cols + c];
}
k++;
}
return result;
}
in order to perform matrix multiplication, I have to use this sum: sum from k = 1 to m1->cols of a_i k-th column * a_j k-th row (in this forum I don't know how to write using mathjax, because symbols like this $$ $$ doesn't work here).
this is the minimal reproducible example:
// matrix.h
#pragma once
#include <stdlib.h>
#include <string.h>
struct matrix {
size_t rows, cols;
double* data;
};
extern struct matrix* mat_mul(const struct matrix* m1, const struct matrix* m2);
// matrix.c
#include "matrix.h"
void mat_constr(struct matrix* m, size_t rows, size_t cols) {
m->rows = rows; m->cols = cols;
m->data = calloc(rows * cols, sizeof(double));
if (!m->data) {
return;
}
}
void mat_destr(struct matrix* m) {
free(m->data);
}
struct matrix* mat_mul(const struct matrix* m1, const struct matrix* m2) {
if ((m1 == NULL) || (m2 == NULL)) {
return NULL;
}
if (m1->cols != m2->rows) {
return NULL;
}
struct matrix* result = malloc(sizeof(struct matrix));
if (!result) {
return NULL;
}
mat_constr(result, m1->rows, m2->cols);
size_t k = 1;
for (size_t r = 0; r < m1->rows; r++) {
for (size_t c = 0; c < m1->cols; c++) {
result->data[r * result->cols + c] = m1->data[r * m1->cols + k] * m2->data[k * m2->cols + c];
}
k++;
}
return result;
}
int main(void) {
struct matrix A;
mat_constr(&A, 2, 3);
memcpy(A.data, (double[6]) { 1, 2, 3, 4, 5, 6 }, 6 * sizeof(double));
struct matrix B;
mat_constr(&B, 3, 2);
memcpy(B.data, (double[6]) { 7, 8, 9, 10, 11, 12 }, 6 * sizeof(double));
struct matrix* C = mat_mul(&A, &B);
mat_destr(&A); mat_destr(&B);
mat_destr(C);
return 0;
}
this solution allocates enough memory, and return the pointer of the new allocated matrix correctly. But the problem is in the last for-loops. According to my linear algebra knowledge, I have to scroll columns by columns the first matrix, and scroll rows by rows the second matrix. But these for-loops are not correct.
I have only one question: "why is this method of computing matrix multiplication wrong? how can I solve it?"
note that r * cols + c gives exactly the index of the i-th entry of the matrix.
You are simply missing a nested for loop and a +=; The correct code for multiplying your 2 matrices would be something like:
for (size_t r = 0; r < m1->rows; ++r)
for (size_t c = 0; c < m2->cols; ++c)
for (size_t k = 0; k < m2->rows; ++k)
result->data[r * result->cols + c] += m1->data[r * m1->cols + k] * m2->data[k * m2->cols + c]

Array of Matrices with Different sizes in C

I am trying to make an array of say 3 matrices with different sizes:
Array ={ {{1, 2, 3}, {10, 20, 30}},
{{4, 5}, {40, 50}, {400, 500}},
{{6, 7}, {60, 70}} };
I need to use array indexing rather than pointer arithmetic for my codes.
I think I should create a 1-d array containing 3 pointers to matrices. Something like:
{ *ptr1[3], *ptr2[2], *ptr3[2]}
But how can I declare such an object? Also how can I assign values to that?
I am readying the actual data from a binary file using fread.
Thank you,
Jagged array is array of arrays such that member arrays can be of different sizes, i.e., we can create a 2-D array but with a variable number of columns in each row.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int Mat1row0[3] = { 1, 2, 3};
int Mat1row1[3] = {10, 20, 30};
int Mat2row0[2] = {4, 5};
int Mat2row1[2] = {40, 50};
int Mat2row2[2] = {400, 500};
int Mat3row0[2] = {6, 7};
int Mat3row1[2] = {60, 70};
int* jagged1[2] = {Mat1row0, Mat1row1 };
int* jagged2[3] = {Mat2row0, Mat2row1, Mat2row2};
int* jagged3[2] = {Mat3row0, Mat3row1 };
int** jaggedkk[3] = {jagged1, jagged2, jagged3};
printf("%d",jaggedkk[0][0][0]);
return 0;
}
The output is : 1
You could create a struct to represent a matrix and then create an array of that struct. Further, you would need a function for initializing a matrix (i.e. allocate memory) and also a function for deleting a matrix (i.e. free allocated memory).
Something like:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
size_t rows;
size_t columns;
int **data;
} Matrix;
void initMatrix(size_t rows, size_t columns, Matrix *m)
{
if (rows == 0 || columns == 0) exit(1); // error
// Allocate row pointers
m->data = malloc(rows * sizeof m->data[0]);
if (m->data == NULL) exit(1); // error
// Allocate data area, i.e. rows x columns ints
m->data[0] = malloc(rows * columns * sizeof m->data[0][0]);
if (m->data[0] == NULL) exit(1); // error
// Initialize the remaining row pointers
for (size_t i=1; i < rows; ++i)
{
m->data[i] = m->data[0] + i * columns;
}
m->rows = rows;
m->columns = columns;
}
void deleteMatrix(Matrix *m)
{
free(m->data[0]);
free(m->data);
m->rows = 0;
m->columns = 0;
m->data = NULL;
}
void printMatrix(Matrix *m)
{
printf("---------------------------\n");
printf("rows=%zu columns=%zu\n", m->rows, m->columns);
for (size_t i=0; i < m->rows; ++i)
{
printf("row[%zu] at %p\t", i, (void*)m->data[i]);
for (size_t j=0; j < m->columns; ++j)
{
printf("%d\t", m->data[i][j]);
}
printf("\n");
}
printf("---------------------------\n");
}
int main(void)
{
Matrix m[2];
initMatrix(2, 5, &m[0]);
for(size_t i=0; i < 2; ++i)
{
for(size_t j=0; j < 5; ++j)
{
m[0].data[i][j] = 10*i + j;
}
}
initMatrix(3, 2, &m[1]);
for(size_t i=0; i < 3; ++i)
{
for(size_t j=0; j < 2; ++j)
{
m[1].data[i][j] = 100 + 10*i + j;
}
}
for(size_t i=0; i < 2; ++i)
{
printMatrix(&m[i]);
}
for(size_t i=0; i < 2; ++i)
{
deleteMatrix(&m[i]);
}
return 0;
}
Possible output:
---------------------------
rows=2 columns=5
row[0] at 0x1979030 0 1 2 3 4
row[1] at 0x1979044 10 11 12 13 14
---------------------------
---------------------------
rows=3 columns=2
row[0] at 0x1979080 100 101
row[1] at 0x1979088 110 111
row[2] at 0x1979090 120 121
---------------------------
A 'short/simple' solution could be just to write:
int *** Array =(int**[]){ (int*[]){(int[]){1, 2, 3}, (int[]){10, 20, 30}},
(int*[]){(int[]){4, 5}, (int[]){40, 50}, (int[]){400, 500}},
(int*[]){(int[]){6, 7}, (int[]){60, 70}} };
Now Array[0][0][0] will be 1, Array[2][1][1] will be 70, etc;
If you need to do it dynamically, you can do it the following way:
int *** Array;
Array = malloc(sizeof(int**)*3);
Array[0] = malloc(sizeof(int*)*2);
Array[0][0] = malloc(sizeof(int)*3);
Array[0][0][0] = 1;
...
(and so on)

Transpose Matrix Using Pointer in C

I was doing the assignment to use pointer to transpose matrices. My code can successfully transpose the first row of the matrix but fail to transpose other rows and columns. I suspect there's some problems with for loops but I cannot find where the problem is. The following attached is my code.
void transposeMatrix(int matrix[ROWS][COLS]){
int** transpose=(int **)malloc(ROWS*sizeof(int*));
for(int i=0; i< ROWS; i++)
transpose[i]=(int*)malloc(COLS*sizeof(int));
for(int i=0; i<ROWS;i++){
puts("");
for(int j=0; j<COLS;j++){
*(transpose+i*ROWS+j)= *(matrix+j*COLS+i);
printf("%d ",transpose[j][i]);
}
puts("");
}
}
The matrix generates random numbers and the problems looks like this:
Original Matrix:
10 20 30
40 50 60
70 80 90
Transpose Matrix:
10 0 43009213
20 3401401 910429
30 0 134910124
I cannot attach the image so the above is just an elaboration of the problem I faced, the real situation is not exactly like that but very similar.
Thank you for your help!
*(transpose+i*ROWS+j) is not the correct way to access elements of an array of pointers. That's the way to access a 2-dimensional array that's stored contiguously in row-major order in an int[] array or through an int* pointer.
The way to access an element of a 2-dimensional array that's implemented as an array of pointers is with *(*(transpose + i)+j). *(transpose + i) returns the pointer to row i, adding j to that returns the address of the j'th column in the row, and deferencing that gets or sets the value.
This will also work with an array declared as
int matrix[ROWS][COLS];
because of the way arrays decay to pointers.
So your assignment line should be:
*(*(transpose + i)+j) = *(*(matrix + j)+i);
Then you need to change the printf() line, because it's not printing the same element you just assigned. It should be:
printf("%d ", transpose[i][j]);
The full working function is:
void transposeMatrix(int matrix[ROWS][COLS]){
int** transpose=(int **)malloc(ROWS*sizeof(int*));
for(int i=0; i< ROWS; i++)
transpose[i]=(int*)malloc(COLS*sizeof(int));
for(int i=0; i<ROWS;i++){
puts("");
for(int j=0; j<COLS;j++){
*(*(transpose + i)+j) = *(*(matrix + j)+i);
printf("%d ",transpose[i][j]);
}
puts("");
}
}
You have problem with identifying memory location for row and col of each cells
Here is the way using them:
i-th rows of transpose = *(transpose + i)
j-th col in i-th row of transpose = *(*(transpose+i) + j)
Similar to matrix:
i-th rows of matrix= *(matrix + i)
j-th col in i-th row of matrix = *(*(matrix+i) + j)
So here is my solution:
void transposeMatrix(int matrix[ROWS][COLS]) {
int** transpose = (int **)malloc(ROWS * sizeof(int*));
for (int i = 0; i < ROWS; i++)
transpose[i] = (int*)malloc(COLS * sizeof(int));
for (int i = 0; i < ROWS; i++) {
puts("");
for (int j = 0; j < COLS; j++) {
*(*(transpose + i) + j) = *(*(matrix + j) + i);
printf("%d ", transpose[i][j]);
}
puts("");
}
}
It's not necessary for you to allocate a new matrix row by row. Also, the functions that do the transpose and printing can be passed straight int * rather than preshaped arrays like int [3][2] etc.
It's even possible to reshape the matrix in place (i.e. without allocating new space). If you like I can post example code for that later.
For instance:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int M[2][3] = { {1, 2, 3}, {7, 8, 9} };
int N[3][3] = { {1, 2, 3}, { 4, 5, 6 }, {7, 8, 9} };
int *alloc_transpose(const int *matrix, size_t rows, size_t cols);
void print_matrix(const int *matrix, size_t rows, size_t cols);
int main()
{
int *t_matrix;
print_matrix(&M[0][0], 2, 3);
fprintf(stderr, "----\n");
t_matrix = alloc_transpose(&M[0][0], 2, 3);
if (t_matrix) {
print_matrix(t_matrix, 3, 2);
}
free(t_matrix);
t_matrix = alloc_transpose(&N[0][0], 3, 3);
if (t_matrix) {
fprintf(stderr, "----\n");
print_matrix(t_matrix, 3, 3);
}
free(t_matrix);
return 0;
}
void print_matrix(const int *matrix, size_t rows, size_t cols)
{
size_t r, c;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("%d ", *((matrix + r * cols) + c));
}
putchar('\n');
}
}
int *alloc_transpose(const int *matrix, size_t rows, size_t cols)
{
int *tm;
int r, c; /* relative to transposed matrix */
tm = malloc(sizeof(int) * cols * rows); /* contiguous is okay */
if (!tm)
return NULL;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
*((tm + c * rows) + r) =
*((matrix + r * cols) + c);
}
}
return tm;
}

How do I assign values to a matrix inside a struct?

I have a header file with this type definition:
typedef struct {
int rows;
int columns;
int **values;
} bidimensional_matrix;
As an example, If I instantiate the matrix from a main function I'd just do:
int matrix[][] = {{1, 2, 3}, {1, 1, 1}, {5, 5, 5}};
How would you generate the same matrix but with the typedef provided previously? (I mean, with pointers and malloc)
Is the approach correct? Maybe I'm a little object oriented biased and in c it's not convenient to handle it that way. I've defined the struct that way so I can just pass two bidimensional_matrix by parameter and do a multiplication.
I propose you to use flexible member array, exemple:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
size_t n;
size_t m;
int matrix[];
} bidimensional_matrix;
bidimensional_matrix *new_bidimensional_matrix(size_t n, size_t m) {
bidimensional_matrix *bm = malloc(sizeof *bm + sizeof *bm->matrix * n * m);
if (!bm) {
return NULL;
}
*bm = (bidimensional_matrix){ .n = n, .m = m };
return bm;
}
int get_bidimensional_matrix(bidimensional_matrix *bm, size_t i, size_t j) {
return bm->matrix[i * bm->m + j];
}
int set_bidimensional_matrix(bidimensional_matrix *bm, size_t i, size_t j, int x) {
return bm->matrix[i * bm->m + j] = x;
}
int main(void) {
bidimensional_matrix *bm = new_bidimensional_matrix(5, 10);
if (!bm) {
return EXIT_FAILURE;
}
for (size_t i = 0; i < bm->n * bm->m; i++) {
bm->matrix[i] = i;
}
printf("sample value %d\n", get_bidimensional_matrix(bm, 4, 5));
set_bidimensional_matrix(bm, 4, 5, 42);
printf("sample value %d\n", get_bidimensional_matrix(bm, 4, 5));
free(bm);
}
But you could use this too, that have other avantage but generally is more slow:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
size_t n;
size_t m;
int **matrix;
} bidimensional_matrix;
int main(void) {
bidimensional_matrix bm = { .n = 5, .m = 10, .matrix = malloc(sizeof *bm.matrix * bm.n) };
if (!bm.matrix) {
return EXIT_FAILURE;
}
for (size_t i = 0; i < bm.n; i++) {
bm.matrix[i] = malloc(sizeof *bm.matrix[i] * bm.m);
if (!bm.matrix[i]) {
return EXIT_FAILURE;
}
for (size_t j = 0; j < bm.m; j++) {
bm.matrix[i][j] = i * bm.m + j;
}
}
printf("sample value %d\n", bm.matrix[4][5]);
for (size_t i = 0; i < bm.n; i++) {
free(bm.matrix[i]);
}
free(bm.matrix);
}
If you need to swap rows the second could be a little faster cause swap row are O(1). But like you see the first one has only one malloc(), in practice with the cache of the processor it should be a lot more faster than the second implementation.

Matrix product cause error: subscripted value is neither array nor pointer nor vector

I have a Java method that multiplies 2 matrices. I have tried to port the same method in C without success.
Here is my attempt to write a method that should multiply 2 matrices in C:
float **multiply(int m1, int n1, float Xy1[], int m2, int n2, float Xy2[]) {
int i, j, k;
float **result = allocate_mem_mtrx(m1, n2);
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
for (k = 0; k < n1; k++) {
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
At this line
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
I receive the error:
subscripted value is neither array nor pointer nor vector
Clearly my syntax is wrong, but I haven't understood how I should fix this line of code, to solve my problem.
In my main I have:
float matrix1[3][2] = {{0, 1}, {3, 4}, {6, 7}};
float matrix2[2][3] = {{5, 1, 2}, {3, 4, 5}};
with the actual signature I invoke the method in this way:
multiply(3, 2, &matrix1, 2, 3, &matrix2);
My original Java method
public static int[][] multiply(int[][] Xy1, int[][] Xy2) {
int rowsInXy1 = Xy1.length;
int columnsInXy1 = Xy1[0].length; // same as rows in B
int columnsInXy2 = Xy2.length;
int[][] result = new int[rowsInXy1][columnsInXy2];
for (int i = 0; i < rowsInXy1; i++) {
for (int j = 0; j < columnsInXy2; j++) {
for (int k = 0; k < columnsInXy1; k++) {
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
You have float Xy1[]
but you treat it as 2D
Xy1[i][k]
Same for Xy2.
You should change float Xy1[] to float** Xy1.
Also another thing, in your loop I feel that you are sure that result 2D array is initialized in your function that says allocate. If that functions just mallocs the array, then this array will have garbage inside.
For more.
[EDIT]
Also I see in one other answer that they cast what malloc returns. Ouch!
Do not cast the return value of malloc in C.
[EDIT.2]
SO, you could something like this:
#include <stdlib.h>
// We return the pointer
float **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
float **table;
table = malloc(N*sizeof(float *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(float) );
return table;
}
void free2Darray(int** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}
// do not forget to FREE what multiply returns
float **multiply(int m1, int n1, float** Xy1,int m2, int n2, float** Xy2) {
int i,j,k;
float **result = get(m1,n2);
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
for (k = 0; k < n1; k++) {
// this line is correct, the prototype of the function
// was not OK
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
int main(void) {
float** A = get(5, 5); // arrays declared as double pointers
float** B = get(5, 5);
float** C = get(5, 5);
C = multiply(5, 5, A, 5, 5, B);
// free2Darray function defined below
free2Darray(A, 5);
free2Darray(B, 5);
free2Darray(C, 5);
return 0;
}
[EDIT.3]
Another way, if you now the columns apriori, which you probably don't as your function implies, you could do that:
#include <stdlib.h>
#include <stdio.h>
// We return the pointer
float **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
float **table;
table = malloc(N*sizeof(float *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(float) );
return table;
}
float **multiply(int m1, int n1, float Xy1[][2],int m2, int n2, float Xy2[][2]) {
int i,j,k;
float **result = get(m1,n2);
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
for (k = 0; k < n1; k++) {
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
int main() {
float matrix1[2][2] = {{0, 1}, {3, 4}};
float matrix2[2][2] = {{0, 1}, {3, 4}};
float** C;
C = multiply(2, 2, matrix1, 2, 2, matrix2);
free2Darray(C, 2);
printf("ok\n");
return 0;
}
I got the get() function from my pseudo-site.
float Xy1[]
is not a two dimensional array, so to write
Xy1[i][k]
is an error.
In C you can use a pointer to pointer notation:
float** multiply( int m1, int n1, float** Xy1,int m2, int n2, float** Xy2) {
//...
}
or you can take advantage of the variable-length array feature in the C language and write
functions that can take multidimensional arrays of varying sizes:
float** multiply( int m1, int n1, float Xy1[m1][n1],
int m2, int n2, float Xy2[m2][n2]) {
float **result, i, j;
result = malloc( m1 * sizeof *result); // remember to free this memory
for( i = 0; i < m1; ++i)
result[i] = malloc( n2 * sizeof float);
//... I don't continue since there seems to be an issue with your indices
// however now you can use result this way:
// result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j]; i, j, k integers
return result;
}
In C++ use a std::vector< std::vector<float> >:
typedef std::vector<std::vector<float> > array; // shorten notation
array multiply( const array& Xy1, const array& Xy2) {
//...
}
In addition
int[][] result = new int[rowsInXy1][columnsInXy2];
is not correct way to create two dimensional array. Such array is an array of pointers and correct way to create this is:
C
int **a, i;
a = malloc( rowsInXy1 * sizeof *a);
for( i = 0; i < rowsInXy1; ++i)
a[i] = malloc( columnsInXy2 * sizeof int);
C++
int** result = new int*[rowsInXy1];
for( int i = 0; i < rowsInXy1; ++i)
result[i] = new int[columnsInXy2];
I see you have already chosen a solution but here is some additional info about arrays in C.
In C there is no equivalent of Java's int[][] type. Java array storage also includes storage of how many items are in the array. However, C's array storage is purely the values in the array contiguous in memory; and you have to keep track of the size either as compile-time constants, or by storing a variable that holds the length.
Further; originally in C, arrays (using the [] syntax) had to have their size known at compile-time. There is an optional feature called variable-length array which means that the array size can be specified at runtime -- however the size can't be changed once the array is created. The major compiler vendors all support VLA, I think.
The VLA uses contiguous storage, however it is not possible to return one via a function's return value. But you can "return" them using an "out" parameter.
It's probably going to turn into a jumble if your code sometimes uses VLAs and sometimes uses dynamically-allocated arrays of pointers.
Another point: in both cases you have to store both array dimensions separately from the array, so that's 3 variables to pass around for each matrix. I'd like to suggest wrapping all of this up in a struct. Since VLAs can't live in a struct, and the compiler might not support them anyway, your best bet may be to use the dynamic allocation version.
Even though we are in C, if you are planning to do more than just a throwaway program, my recommendation would be to use an object-oriented approach for the matrix. Here's an example framework (where all Matrices are to have the Matrix be dynamically allocated, as well as the cells):
// Matrix.h
typedef struct
{
size_t y_dim, x_dim;
float **cells;
} Matrix;
Matrix *matrix_construct(size_t y_dim, size_t x_dim);
void matrix_free(Matrix *m); // frees m as well as cells
void matrix_assign(Matrix *dst, Matrix const *src); // may re-size dst
void matrix_set_values(Matrix *dst, float *row_major);
bool matrix_is_equal(Matrix const *m1, Matrix const *m2);
typedef Matrix *MatrixBinaryOperator(Matrix const *m1, Matrix const *m2);
MatrixBinaryOperator matrix_multiply;
Example usage:
float mat1_array[3][2] = {{0, 1}, {3, 4}, {6, 7}};
float mat2_array[2][3] = {{5, 1, 2}, {3, 4, 5}};
Matrix *mat1 = matrix_construct(3, 2);
Matrix *mat2 = matrix_construct(2, 3);
matrix_set_values(mat1, (float *)&mat1_array);
matrix_set_values(mat2, (float *)&mat2_array);
Matrix *mat3 = matrix_multiply(mat1, mat2);
matrix_free(mat1);
matrix_free(mat2);
matrix_free(mat3);
See it working - disclaimer: this code doesn't check for malloc failure and I have only done the most basic testing; and a lot of optimization is possible.

Resources