3

I am trying to pass a matrix to a function by reference. The function will replace every element A[i][j] of the matrix by -A[i][j]. I first create the matrix:

float a[3][4] =
{
    {1.0f, 0.0f, 0.0f, 0.0f},
    {0.0f, 1.0f, 0.0f, 0.0f},
    {1.0f, 1.0f, 0.0f, 0.0f},
};

Then, I obtain the pointer to this matrix:

float*** pa = &a;

Then, I introduce the following function:

void process(float ***matrix, int nRows, int nCols){
 short i;
 short j;
 for (i=0 ; i<nRows; i++){
   for (j=0 ; j<nCols ; j++){
     (*matrix)[i][j] *= -1;
   }
 }
}

which I call as follows:

process(pa,3,4);

My program fails to execute and returns:

Segmentation fault: 11

Any ideas?

Summary of the answers: Some notes based on the questions this question received:

I. The aforementioned function can be used, provided that a is initialized a bit differently so as to be a float**. In particular:

int numberOfRows = 3;
int numberOfColumns = 4;
float **a = (float **) malloc(sizeof (float *) * numberOfRows);
for (i = 0; i < numberOfRows; ++i) {
    a[i] = (float *) malloc(sizeof (float) * numberOfColumns);
}

and then, it is passed to the function process as process(&a, 3,4);.

II. Alternatively, one may use the function:

void multi_by_minus(float *matrix, int nRows, int nCols) {
  short i,j;
  for (i = 0; i < nRows; i++) {
      for (j = 0; j < nCols; j++) {
          matrix[i * nCols + j] *= -1;
      }
  }
}

which treats the matrix as an one-dimensional array. In that case we simply invoke it as multi_by_minus(&a, 3, 4);

III. Finally, we may use the method:

void process2(int nRows, int nCols, float (*matrix)[nCols]) {
  short i, j;
  for (i = 0; i < nRows; i++) {
    for (j = 0; j < nCols; j++) {
        matrix[i][j] *= -1;
    }
  }
}

to which we provide a pointer to a, i.e., we invoke it like process2(3,4,&a);. In this way, we acquire access to the elements of the matrix in 2D.

Pantelis Sopasakis
  • 1,902
  • 5
  • 26
  • 45
  • http://stackoverflow.com/questions/16004668/c-allocating-a-matrix-in-a-function/27366086#27366086 Above you will find a program that I have made with functions allocating and manipulating matrices in any possible way for C (gcc C11/C99). – 42n4 Dec 08 '14 at 20:28
  • 1
    [Don't cast the result of `malloc` in C](http://stackoverflow.com/q/605845/995714) – phuclv Jan 18 '17 at 03:28

4 Answers4

9

There is no need for the triple pointer since you are already supplying the memory. You would use that if you were to allocate the memory inside de function.

You can't index a 2 dimension matrix without supplying at least the size of 1 dimension. The reason is that the compiler needs to generate code to access the correct offset taking into account both dimensions. In this particular case, I suggest passing a simple pointer and indexing as a 1D array, like this:

void process(float *matrix, int nRows, int nCols){
 short i;
 short j;
 for (i=0 ; i<nRows; i++){
   for (j=0 ; j<nCols ; j++){
     matrix[i * nCols + j] *= -1;
   }
 }
}

You can then call it like this:

process((float*)a,3,4);

This way you manually index your buffer.

imreal
  • 10,178
  • 2
  • 32
  • 48
  • In this way, I manipulate the (2D) matrix as if it were a (1D) vector. It makes sense, but, is there a way to work with the 2D entity directly? – Pantelis Sopasakis Jan 22 '13 at 01:42
  • Thanks! It works fine. One more question: I took a look at BLAS and I see that most functions expect vectors and matrices to be provided as `void*`! What exactly is that? Is it supposed to mean "Any possible type?" – Pantelis Sopasakis Jan 22 '13 at 01:56
  • 1
    You do not have to bind the size at compile time to pass a two-dimensional matrix. See my answer for how to do this. – Eric Postpischil Jan 22 '13 at 02:01
3

You have to change the signature of the function to this:

void process(float (*matrix)[3][4], int nRows, int nCols){

And when calling the function, use this:

process(&a, 3, 4);
A.B.
  • 2,374
  • 3
  • 24
  • 40
  • Nice, but it binds `matrix` to have a fixed size. – Pantelis Sopasakis Jan 22 '13 at 01:46
  • 1
    well Nick's answer is the only way to handle with 2d stack arrays of any size. If you don't want the 1d-indexing, you should use 2d heap array (new/delete). Then you can use a double or triple pointer. – A.B. Jan 22 '13 at 01:55
1

If you put the nCols parameter before the matrix parameter, you can pass the two-dimensional matrix and use it in the natural way, without extra * operators or index arithmetic:

void process(int nRows, int nCols, float (*matrix)[nCols])
{
    for (short i = 0 ; i < nRows; i++)
    {
        for (short j = 0; j < nCols; j++)
        {
            matrix[i][j] *= -1;
        }
     }
}

Then you call process like this:

process(3, 4, matrix);

Incidentally:

  • Unless there is special reason for making i and j short, you should declare them int. int is defined to be the “natural” size for integers on the target platform.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

So easy, if you have a matrix:

int m[2][2]={{1,0},{0,1}};

and you want to define a pointer to m, so you must declare:

int (*mptr)[2][2];
mprt=m; // or mptr=&m;  is the same.

and you can use it to point to elements of the matrix m.

(*mptr)[i][j]....
Sergei Bubenshchikov
  • 5,275
  • 3
  • 33
  • 60
milcom
  • 1