2

I started to learn C and started a new argument: the matrices. I saw that you can define a matrix in two different ways

WAY 1

The first way using the subscript operator[]

const int N = 3, M = 4;
int matrix[N][M];

but as this it is difficlt to pass the arguments in the functions becouse the the compiler has to know the matrix number of columns when it compiles the program. so you have to do a function that works only for matrices with n columns

int my_func( int matrix[][3], const int num_lines){...}

WAY 2

The second way: use an array of arrays

const int N = 3, M = 4;
int** m = (int**) calloc(N, sizeof(int*))
for (int i = 0; i < N; i++){
    m[i] = (int*) calloc(M, sizeof(int))
}

So doing so you can easily pass the matrix pointer to a function an work fluently with it but the only problem is the efficency in the memory allocation and the the recall of values.

WAY 3?

Actually i thought that there can be a third way and i was wondering if it was correct doing this

const int N = 3, M = 4;
int array[N*M];
for (int i=0; i<N; i++){
    for (int j = 0; j<M; j++){
        printf("%d%d: %d\n", i, j, array[ i * M + j ]);
    }
}

Doing so by my point of view should be as efficency as the first way that i wrote but u can work with it more fluently in the functions becouse you need only to pass the lines and the columns as arguments

int my_func( const int* matrix, const int num_lines, const int num_columns){...}

Is the way 3 right?

Tarek Dakhran
  • 2,021
  • 11
  • 21
Mat.C
  • 1,379
  • 2
  • 21
  • 43
  • 1
    Yes; in fact, the rows and columns could be part of a `struct` with the array, then you'd only have to pass one value. – Neil Feb 15 '20 at 17:36
  • So am i correct by sayng that the third way is the 'best' one? @Neil – Mat.C Feb 15 '20 at 17:38
  • It depends on what you are using it for. Of the three, it is the most abstract. – Neil Feb 15 '20 at 17:43
  • 1
    Way 1 and 3, as you have coded them, are only guaranteed defined in `C99`, `C89` you could only use [integer constants](https://en.cppreference.com/w/c/language/integer_constant) and `C11` made variable-sized arrays an [optional feature](https://stackoverflow.com/questions/22914206/where-are-c11-optional-feature-macros/22914369). – Neil Feb 15 '20 at 18:39
  • _Viz_, if one replaced `const int` with `#define` then they would work on all versions of `C`. – Neil Feb 15 '20 at 19:04

1 Answers1

4

Is the way 3 right?

From the memory management system, the way 3 is cheaper as you don't have too many allocations as in way 2. But it is also limiting you in terms of maximum matrix size, which can be placed on the stack.

If you take the best from way 2 and way 3, you will end up with something like

typedef struct  {
    unsigned M;
    unsigned N;
    int *data;
} Matrix;

Matrix create_matrix(unsigned M, unsigned N) {
    Matrix matrix;
    matrix.M = M;
    matrix.N = N;
    matrix.data = (int*) calloc(M * N, sizeof(int));
    return matrix;
}

int* get_matrix_element(Matrix *matrix, unsigned m, unsigned n) {
    return matrix->data + m * matrix->N + n;
}

void delete_matrix(Matrix *matrix) {
    free(matrix->data);
}
Tarek Dakhran
  • 2,021
  • 11
  • 21
  • 2
    Note that an array does not have to be on the stack; it can be global or static. You can also assign the result of malloc to a pointer to array and then use it like a 2-dimensional array: `int (*arr)[3] = malloc(12*sizeof(int)); arr[3][2] = 1;` for a 4x3 matrix. – Peter - Reinstate Monica Feb 15 '20 at 18:01
  • Essentialy (that's a link for a fork, original library harder to link directly) https://github.com/yageek/Meschach/blob/master/matrix.h. Meshach got an extended structure because they support some kind of sparse matrices, I think. – Swift - Friday Pie Feb 15 '20 at 18:05
  • You can save a redirect if you store the array after the dimensions, but that's probably more work. – Neil Feb 15 '20 at 18:07