Home > Back-end >  How to copy values in a 2D VLA to a dynamic array (which I called a matrix) in C
How to copy values in a 2D VLA to a dynamic array (which I called a matrix) in C

Time:08-22

I am trying to create a Linear Algebra library from scratch in C. At first, I created a matrix with struct. The dimension and size of the matrix are allocated dynamically. I want to create such a function so I can copy the data in a 2D array and save it in the matrix.

The code that I have written so far has been shown below:

#include <stdio.h>
#include <stdlib.h>

typedef struct matrix {
    int rows, cols;
    int** data;
} matrix;

void initmatrix(matrix* mat) {
    mat->data = (int**) malloc(mat->rows * sizeof(int*));
    for (int i = 0; i < mat->rows; i  ) {
        *(mat->data i) = (int*) malloc(mat->cols * sizeof(int));
    } 
}  

void fillwith_0(matrix* mat) {
    for (int i = 0; i < mat->rows; i  ) {
        for (int j = 0; j < mat->cols; j  ) {
            *(*(mat->data i) j) = 0;
        } 
    } 
} 

void printmatrix(matrix* mat) {
    for (int i = 0; i < mat->rows; i  ) {
        for (int j = 0; j < mat->cols; j  ) {
            printf("%d", *(*(mat->data i) j));
        }
        printf("\n");
    }
}

I want to implement a setvalue function that takes two arguments, one is the pointer to the matrix, and the other is a 2D array, so I can copy the data in it inside the matrix.

How would I do so?

CodePudding user response:

You can #include <string.h> and use the memcpy function(or memmove which results the same in this scenario) to copy the values of the matrix to another matrix. Here's a simple program copys the value from your matrix struct to a 2D-array.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define row 5
#define col 10

void print_matrix(int **matrix)
{
    //print the address of the first element in the matrix. 
    printf("address: %p\n", matrix);
    for(int i = 0; i < row; i  )
    {
        //print the address of the first element of each row
        printf("address: %p   ", matrix[i]);
        for(int j = 0; j < col; j  )
        {
            printf("]", matrix[i][j]);
        }
        puts("");
    }
}

void free_matrix(int **matrix)
{
    for(int i = 0; i < row; i  )
    {
        free(matrix[i]);
        matrix[i] = NULL; //this step is somewhat important since the first copy methods will introduce double free.
    }
    free(matrix);
    matrix = NULL;
}

//your struct
typedef struct matrix
{
    int rows, cols;
    int** data;
}matrix;

int main(void)
{
    //declare matrix1
    int num = 0;    //this number is just for 
    matrix matrix1 = { .rows = row, .cols = col };
    matrix1.data = malloc(sizeof(int *) * matrix1.rows);
    for(int i = 0; i < matrix1.rows; i  )
    {
        //I used calloc because calloc will initialize the value of those block to 0, and it is for demonstration purpose, malloc would work just fine
        matrix1.data[i] = calloc(matrix1.cols, sizeof(int));
        for(int j = 0; j < matrix1.cols; j  )
        {
            matrix1.data[i][j] = num  ;
        }
    }

    //initialize matrix2
    int **matrix2 = malloc(sizeof(int *) * row);
    for(int i = 0; i < row; i  )
    {
        matrix2[i] = calloc(col, sizeof(int));
    }

    //copy matrix1 to matrix2
    //both methods work, but the first one just copys the address of each single dimension array, I think methods 2 is what you are asking for?
    //methods 1: 
    memcpy(matrix2, matrix1.data, sizeof (int) * row * col);

    //methods 2: 
    //for(int i = 0; i < row; i  ) memcpy(matrix2[i], matrix1.data[i], sizeof(int) * col);

    //print
    print_matrix(matrix1.data);
    puts("");
    print_matrix(matrix2);

    //free memory
    free_matrix(matrix1.data);
    free_matrix(matrix2);
    EXIT_SUCCESS;
}

And the output of this program should be like this if you used the second methods(the address of the matrix will be vary):

address: 00ba1610
address: 00ba1630       0    1    2    3    4    5    6    7    8    9
address: 00ba2368      10   11   12   13   14   15   16   17   18   19
address: 00ba2398      20   21   22   23   24   25   26   27   28   29
address: 00ba23c8      30   31   32   33   34   35   36   37   38   39
address: 00ba23f8      40   41   42   43   44   45   46   47   48   49

address: 00ba2428
address: 00ba2448       0    1    2    3    4    5    6    7    8    9
address: 00ba2478      10   11   12   13   14   15   16   17   18   19
address: 00ba24a8      20   21   22   23   24   25   26   27   28   29
address: 00ba24d8      30   31   32   33   34   35   36   37   38   39
address: 00ba2508      40   41   42   43   44   45   46   47   48   49

And like this if you used the first one(do not use this method):

address: 01521610
address: 01521630       0    1    2    3    4    5    6    7    8    9
address: 01522368      10   11   12   13   14   15   16   17   18   19
address: 01522398      20   21   22   23   24   25   26   27   28   29
address: 015223c8      30   31   32   33   34   35   36   37   38   39
address: 015223f8      40   41   42   43   44   45   46   47   48   49

address: 01522428
address: 01521630       0    1    2    3    4    5    6    7    8    9
address: 01522368      10   11   12   13   14   15   16   17   18   19
address: 01522398      20   21   22   23   24   25   26   27   28   29
address: 015223c8      30   31   32   33   34   35   36   37   38   39
address: 015223f8      40   41   42   43   44   45   46   47   48   49

CodePudding user response:

A possible solution is to use a void* in the structure to store the array.
It is fairly simple to use an array to fill the void* as would filling an array from the void*.
Changing the allocation of rows would be fairly simple.
It should be possible to change the allocation of columns too.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct matrix mtrx;
struct matrix {
    int rows;
    int cols;
    void *pvla;
};

void initmatrix ( mtrx *mat) {
    if ( mat->pvla) { // already allocated
        fprintf ( stderr, "pvla not NULL\n");
        return;
    }
    if ( ! mat->cols || ! mat->rows) {
        fprintf ( stderr, "cols zero or rows zero\n");
        return;
    }
    int (*tmp)[mat->cols];
    if ( NULL == ( tmp = calloc ( sizeof *tmp, mat->rows))) {
        fprintf ( stderr, "calloc problem\n");
        exit ( 1);
    }
    mat->pvla = tmp;
}

void freematrix ( mtrx *mat) {
    mat->rows = 0;
    mat->cols = 0;
    free ( mat->pvla);
    mat->pvla = NULL;
}

void setcolsmatrix ( mtrx *mat, int cols) {
    if ( mat->pvla) { // already allocated
        fprintf ( stderr, "pvla not NULL\n");
        return;
    }
    mat->cols = cols;
}

void setrowsmatrix ( mtrx *mat, int rows) {
    if ( ! mat->pvla && rows > 0) {
        mat->rows = rows;
        return;
    }
    fprintf ( stderr, "unable at this time to reallocate rows");
}

void setvaluematrix ( mtrx *mat, int row, int col, int value) {
    if ( row >= mat->rows || row < 0 || col >= mat->cols || col < 0) {
        fprintf ( stderr, "row or col out of range\n");
        return;
    }
    int (*tmp)[mat->cols] = mat->pvla;
    tmp[row][col] = value;
}

void fillmatrix ( mtrx *mat, int (*fill)[]) {
    if ( ! mat->rows || ! mat->cols || ! mat->pvla) {
        fprintf ( stderr, "rows or cols zero or pvla NULL\n");
        return;
    }
    int (*tmp)[mat->cols] = mat->pvla;
    memcpy ( tmp, fill, sizeof *tmp * mat->rows);
}

void printmatrix(mtrx *mat, int width) {
    if ( ! mat->rows || ! mat->cols || ! mat->pvla) {
        fprintf ( stderr, "rows or cols zero or pvla NULL\n");
        return;
    }
    int (*tmp)[mat->cols] = mat->pvla;
    for ( int rw = 0; rw < mat->rows;   rw) {
        for ( int cl = 0; cl < mat->cols;   cl) {
            printf ( "%*d", width, tmp[rw][cl]);
        }
        printf ( "\n");
    }
}

int main ( void) {
    int xy[4][10] = { { 0}};
    mtrx arr = { 0, 0, NULL};

    xy[0][0] = 2;
    xy[1][1] = 22;
    xy[2][2] = 222;
    xy[3][3] = 333;
    xy[3][9] = 456;

    setrowsmatrix ( &arr, sizeof xy / sizeof *xy);
    setcolsmatrix ( &arr, sizeof *xy / sizeof **xy);

    initmatrix ( &arr); // initialize matrix
    fillmatrix ( &arr, xy); // use array to fill matrix

    setvaluematrix ( &arr, 0, 9, 987); // assign a value to a row/col in matrix

    printmatrix ( &arr, 7);
    printf ( "\n");

    freematrix ( &arr);

    return 0;
}
  • Related