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;
}