6

I am working on a homework assignment to do matrix multiplication with dynamically allocated 2d arrays. I have written the following function to load the matrix:

void loadMatrix(FILE* fp, int** matrix, int rowSize, int colSize) {

    for (int i = 0; i < rowSize; i++) {
        for (int j = 0; j < colSize; j++) {
            fscanf(fp, "%d", &matrix[i][j]);
        }
    }
}

I declare my matrix as a global variable as follows:

int **a;

and then initialize and load it as follows:

// allocate memory for the array rows
a = (int **) malloc(m * sizeof(int*));

// allocate memory for array columns
for (int i = 0; i < m; i++) {
    a[i] = malloc(k * sizeof(int));
}

loadMatrix(fp, a, m, k);

Everything works as expected, however the function signature that the teacher provided is the following:

void loadMatrix(FILE*, int ***, int, int);

I tried using that signature, and pass in the address of the matrix using &, and removing the & from my loadMatrix function, thinking that the outputs should be the same, but using *** does not work as expected. What am I missing? Also what would be the advantage of using triple pointers if there is one?

Luke LaFountaine
  • 768
  • 1
  • 5
  • 16
  • 3
    `loadMatrix(fp, &a, m, k);` and do malloc'd inside function. – BLUEPIXY Feb 22 '16 at 05:37
  • 3
    Just change `&matrix[i][j]` to `&(*matrix)[i][j]` in `fprintf` and function call to `loadMatrix(fp, &a, m, k);`. – haccks Feb 22 '16 at 05:38
  • @haccks wow that worked fine. So why is that? I feel like the & and * should in a sense cancel each other out. What am I misunderstanding? – Luke LaFountaine Feb 22 '16 at 05:41
  • [Don't cast the result of `malloc` in C](http://stackoverflow.com/q/605845/995714) – phuclv Feb 22 '16 at 05:44
  • 2
    @LukeLaFountaine Here operator precedence will also matter . Direct `&*a` in this expression it will result in `a` itself . But in haccks's expression parenthesis will make difference. – ameyCU Feb 22 '16 at 05:44
  • 2
    @LukeLaFountaine; `*` and `&` cancels each other only when they applied on the same object. In this case `*` is applied on `matrix` which is an `int ***` object while `&` is applied on `(*matrix)[i][j]` which is an `int` object. Therefore, no cancellation!! – haccks Feb 22 '16 at 05:44
  • 2
    @LukeLaFountaine, two comments for the future: (1) do NOT cast the return of `malloc` (e.g. `a = malloc(m * sizeof *a);` is all that is required) and (2) C generally avoids the use of `CameCase` names (e.g `camelcase` is fine), see: [**NASA C Style Guide**](http://homepages.inf.ed.ac.uk/dts/pm/Papers/nasa-c-style.pdf) (Goddard Spaceflight Center 1994) – David C. Rankin Feb 22 '16 at 05:49
  • @haccks Thanks a lot! That cleared it all up! – Luke LaFountaine Feb 22 '16 at 06:07
  • @DavidC.Rankin thanks for the tips, I will keep that in mind. – Luke LaFountaine Feb 22 '16 at 06:07
  • @DavidC.Rankin Ok. I'll make sure I follow that guide when I accept that job at NASA. ;-) – 2501 Feb 22 '16 at 08:30

1 Answers1

1

Your code has the following problems:

  • You are not allocating 2D arrays, but rather pointer-to-pointer based look-up tables segmented all over the heap. This is widespread but poor practice: there is never a reason to segment your 2D array and allocate it in multiple places. The code turns complex and the program turns slow, for no benefit.

  • There is no reason to declare the matrix as a global variable.

  • There is never a reason to have 3 levels of indirection in C. This is known as "three star programming" and is a certain sign of fundamentally flawed program design. Unfortunately, this means that your teacher is not a trustworthy source of C knowledge.

Instead, you should be allocating 2D arrays:

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

void loadMatrix(FILE* fp, int rowSize, int colSize, int matrix[rowSize][colSize]) 
{
    for (int i = 0; i < rowSize; i++) {
        for (int j = 0; j < colSize; j++) {
            fscanf(fp, "%d", &matrix[i][j]);
        }
    }
}


int main (void)
{
  const int ROWS = 4;
  const int COLS = 5;
  int (*matrix)[ROWS][COLS]; // array pointer to variable-length array

  matrix = malloc( sizeof(int[ROWS][COLS]) );
  if(matrix == NULL)
  {
    // error handling
  }

  FILE* fp = ...;
  loadMatrix(fp, ROWS, COLS, *matrix); // contents of what the pointer points at is the array

  free(matrix);
}

To fully understand the above, I recommend studying variable-length arrays and how arrays decay into pointers to the first element.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Lundin
  • 195,001
  • 40
  • 254
  • 396