3

Having looked around I've built a function that accepts a matrix and performs whatever it is I need on it, as follows:

float energycalc(float J, int **m, int row, int col){
...
}

Within the main the size of the array is defined and filled, however I cannot passs this to the function itself:

int matrix[row][col];
...
E=energycalc(J, matrix, row, col);

This results in a warning during compilation

"project.c:149: warning: passing argument 2 of ‘energycalc’ from incompatible pointer type project.c:53: note: expected ‘int **’ but argument is of type ‘int (*)[(long unsigned int)(col + -0x00000000000000001)]’

and leads to a segmentation fault.

Any help is greatly appreciated, thank you.

Narlok
  • 53
  • 2
  • 6
  • `float energycalc(float J, int row, int col, int m[row][col] ){` – BLUEPIXY Apr 07 '15 at 14:20
  • 2
    An array of arrays is not the same as a pointer to pointer, see e.g [this old answer of mine](http://stackoverflow.com/a/18440456/440558) to see why. You could possibly get by with a pointer to arrays though (e.g. `int (*m)[]`). – Some programmer dude Apr 07 '15 at 14:20
  • @legends2k The question was tagged with `C` only...I found out the hard way when Cool Guy complained about my answer. – Tim Biegeleisen Apr 07 '15 at 14:24
  • The C duplicates: [2D array passing to a function](http://stackoverflow.com/q/16822496/183120) and [passing 2d arrays](http://stackoverflow.com/q/3911400/183120). Worry not, I've found 2 just by looking around, sure we could dig more if we sweat more :) – legends2k Apr 07 '15 at 14:24
  • That being said, could someone post a solution which would pass an `int**` to the `energycalc()` function, just for the sake of completeness? – Tim Biegeleisen Apr 07 '15 at 14:25
  • 1
    Check the dupes, you'd find more complete answers than any posted here. – legends2k Apr 07 '15 at 14:27

5 Answers5

3

If the array is declared as

int matrix[row][col];

then change the function declaration to

float energycalc(float J, int m[][col], int row, int col){

The name of a two dimensional array of type T does not decay to T**.

If col is a local variable, then you need to call the function with the col parameter before matrix. This is done so that col is visible in the function.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
  • @BLUEPIXY , Sorry, I didn't understand – Spikatrix Apr 07 '15 at 14:28
  • 2
    see [DEMO](http://ideone.com/QarBmz) `error: 'col' undeclared here (not in a function)` – BLUEPIXY Apr 07 '15 at 14:37
  • 1
    @CoolGuy; With declaration `float energycalc(float J, int m[][col], int row, int col)` compiler has no idea about `col` and it will produce an error. You must have to place `col` before using it in `int m[][col]`. – haccks Apr 07 '15 at 14:40
3

The function should be declared like

float energycalc( float J, int row, int col, int ( *m )[col] );

if your compiler supports variable length arrays.

Otherwise if in declaration

int matrix[row][col];

col is some constant then the function can be declared the following way

float energycalc(float J, int m[][col], int row );

provided that constant col is defined before the function.

Your function declaration

float energycalc(float J, int **m, int row, int col);

is suitable when you have an array declared like

int * matrix[row];

and each element of the array is dynamically allocated like for example

for ( int i = 0; i < row; i++ ) matrix[i] = malloc( col * sizeof( int ) );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

Passing two dimensional array to a function in C is often confusing for newbies.
The reason is that they assume arrays are pointers and having lack of understanding how arrays decays to pointer.
Always remember that when passed as an argument arrays converted to the pointer to its first element.
In function call

E = energycalc(J, matrix, row, col);  

matrix is converted to pointer to its first element which is matrix[0]. It means that passing matrix is equivalent to passing &matrix[0]. Note that the type of &matrix[0] is int(*)[col] (pointer to an array of col int) and hence is of matrix. This suggest that the second parameter of function energycalc must be of type int(*)[col]. Change the function declaration to

 float energycalc(int col, int (*m)[col], int row, float J);  

and call your function as

 E = energycalc(col, matrix, row, J); 
haccks
  • 104,019
  • 25
  • 176
  • 264
  • 1
    Or simply declare the pointer parameter as `int m[row][col]`, which is more readable. – Lundin Apr 07 '15 at 14:48
  • @Lundin; or `int m[][col]`. – haccks Apr 07 '15 at 14:49
  • Any reason why you'd want to omit one of the dimensions? – Lundin Apr 07 '15 at 14:51
  • @Lundin; If you will not omit the first dimension then compiler will do. – haccks Apr 07 '15 at 14:53
  • 1
    Indeed. But my point is: why would I would want to make my code less readable? – Lundin Apr 07 '15 at 14:53
  • 1
    @Lundin; Why do you thing it will make less readable? To me `int m[row][col]` is less readable than `int (*m)[col]`. – haccks Apr 07 '15 at 14:56
  • Maybe subjective, but I definitely find the array pointer syntax far less intuitive than the plain array syntax. Consider a more complex case: `int*(*m)[col]` versus `int* m[row][col]`. And we should not even mention arrays of function pointers :) – Lundin Apr 07 '15 at 15:06
  • @Lundin adding the dimension gives a false notion that it's part of the type, when it is not. The absent minded Jimmy will probably trip on that syntax but get alerted by the pointer to array syntax. – legends2k Apr 07 '15 at 17:37
  • @haccks when so many dupes were already found and listed, isn't marking this a dupe more appropriate? – legends2k Apr 07 '15 at 17:40
  • @legends2k; That's true, but read all the answers of listed dupes and then my answer then you will find none of the existing answer their addressed this approach. – haccks Apr 07 '15 at 17:47
  • @legends2k That is just a "known bug" in the C language, whenever you write function declarations. Similarly, `int a[]` in a function parameter list is a pointer, not an array. This is because the C language is being obfuscated when it comes to function parameter declarations.: absent-minded Jimmy and all other C programmers must learn this. – Lundin Apr 08 '15 at 07:42
  • 1
    Sure they must learn the difference but even the most alert programmer will have her dull day when `int(*)[col]` will be less tricky, more explicit than `int[row][col]` which is nothing but the former in a parameter list. – legends2k Apr 08 '15 at 12:53
  • @legends2k There's also another advantage except the subjective readability part: if you write both dimensions explicitly, an external static analysis tool would be able to spot various type conflicts or out-of-bounds errors, that the compiler can't find. – Lundin Apr 10 '15 at 13:03
0

I think you can do something like this in C

float function_name(int mat_width, int mat_height, float matrix[mat_width][mat_height]) {
    ... function body...
}
Mateo Hrastnik
  • 533
  • 1
  • 7
  • 20
  • You can if `mat_width` and `mat_heigth` are compile-time constants. And if they are, they should be written in upper-case (because of the convention), and then this is the best way to do it, because it clearly and unambiguously documents the fact the function expects a pointer to a N by M matrix, as opposed to just a pointer to a random type without knowing if it's an array and by which size. – Bregalad Apr 07 '15 at 14:27
  • @Bregalad That's not true... You can mat_width and mat_height can be variables and you can send different values every time... I think it's not standard C but an extension. – Mateo Hrastnik Apr 07 '15 at 14:32
  • 1
    @Bregalad These are variable-length arrays (VLAs). You might want to update your C knowledge to C99, which was released 16 years ago. – Lundin Apr 07 '15 at 14:50
  • @MattHammond It is standard C. – Lundin Apr 07 '15 at 14:51
  • @Lundin `matrix` in this answer has variably modified type. It might not point to a VLA (e.g. the function could be called from two different places, each with a normal array). – M.M Apr 10 '15 at 05:57
-1

A pointer-to-pointer is not an array, nor does it point to a two-dimensional array. It has nothing to do with arrays, period, so just forget you ever heard about pointer-to-pointers and arrays together.

(The confusion likely comes from the hordes of confused would-be programming teachers/authors telling everyone that they should use pointer-to-pointer when allocating dynamic 2D arrays. Which is just plain bad advice, since it will not allocate a real array allocated in adjacent memory cells, but rather a fragmented look-up table exploded in pieces all over the heap. See this for reference about how to actually allocate such arrays.)

Assuming that your compiler isn't completely ancient, simply use a variable length array (VLA), which is a feature introduced in the C language with the C99 standard.

#include <stdio.h>

void print_matrix (size_t row, size_t col, int matrix[row][col]);


int main (void)
{
  int matrix[2][3] = 
  {
    {1,2,3},
    {4,5,6}
  };

  print_matrix(2, 3, matrix);

  return 0;
}

void print_matrix (size_t row, size_t col, int matrix[row][col])
{
  for(size_t r=0; r<row; r++)
  {
    for(size_t c=0; c<col; c++)
    {
      printf("%d ", matrix[r][c]);
    }
    printf("\n");
  }
}
Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396