1

I have code like this:

void print_matrix(int **a, int n) {
    int i, j;
    for(i = 0; i < n; i++) {
        for(j = 0; j < n; j++)
            printf("%d\t", *(a+i*n+j));
        putchar('\n');
    }
}

int main () {
  int matrix[3][3];

  insert (matrix); /* Function that reads Matrix from stdin */
  print_matrix(matrix, 3);
  return 1; 
}

I receive GCC error:

expected ‘int **’ but argument is of type ‘int (*)[3]

I read all related topics but I still couldn't find answer to my question, so before you mark it as duplicate please read it.

Pointers are not Arrays, I understand that. I've read somewhere that elements are not sequential, in that case, this could happen: 111 222 333 -> 111 is address of first int array, 222 is address of second int array, and 333 is address of third int array. But if this is the case, I don't understand why GCC gives me an error.

First I would like someone to confirm me that what I've read is true. Then I would really appreciate if someone could give me answer.

Note that I understand that *(a+i*n+j) is incorrect in case that memory for matrix is not sequential.

Best regards.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
Aleksandar Makragić
  • 1,957
  • 17
  • 32

3 Answers3

4

When you pass int[3][3], the function receives a pointer to the (int*)[3] which is a pointer to an array of 3 int's. Because an array gets converted into a pointer to its first element when you pass it to a function.

So adjust the function accordingly. One way is to receive it as a pointer to an array. You array indexing is wrong too. You can index just like how you would index a real the array.

void print_matrix(int (*a)[3], int n) {

    int i, j;
    for(i = 0; i < n; i++) {
        for(j = 0; j < n; j++)
            printf("%d\t", a[i][j]);
        putchar('\n');
    }

}

If you use C99, you can pass both dimensions:

void print_matrix(int x, int y, int a[x][y]) {

    int i, j;
    for(i = 0; i < x; i++) {
        for(j = 0; j < y; j++)
            printf("%d\t", a[i][j]);
        putchar('\n');
    }

}

and call it as:

  print_matrix(3, 3, matrix);

Just to illustrate how you would access the individual "arrays":

void print_matrix(int (*a)[3], int n) {
    int i, j;
    for(i = 0; i < n; i++) {
       int *p = a+i;
        for(j = 0; j < 3; j++)
            printf("%d\t", p[j]);
        putchar('\n');
    }

}
P.P
  • 117,907
  • 20
  • 175
  • 238
  • When you pass int[3][3], the function receives a pointer to the (int*)[3] which is a pointer to an array of 3 int's. Because an array gets converted into a pointer to its first element when you pass it to a function. - Can you explain this a little bit more? – Aleksandar Makragić Jan 06 '16 at 21:40
  • In C, you can neither pass nor return an *array* to/from a function. It always gets converted into a pointer to its first element. So the array loses its size information and becomes just a pointer (inside a function) which is also the reason why you can't use `sizeof` on it to get its actual size. See [What is array decaying?](http://stackoverflow.com/questions/1461432/what-is-array-decaying) which specifically covers this topic. – P.P Jan 06 '16 at 21:43
  • So basically when I pass to function int[3][3] ONLY the first int[3] converts to pointer, and then I get (int*)[3] and that is pointer to an array of 3 ints, and not 3 pointers to 3 different arrays? – Aleksandar Makragić Jan 06 '16 at 21:50
  • Yes. But the pointer still points to the same array. That's why you can index it like a real array or increment it to get the next 3 ints E.g. If you have 1D arrat then: `int a[3]; func(a); void func(int *a) {..}`. If you have a 2D array then: `int a[3][3]; func(a); void func(int (*a)[3]) {..}` and so on. – P.P Jan 06 '16 at 21:53
  • @АлександарМакрагић I just edited which may add a bit of clarity. – P.P Jan 06 '16 at 22:11
  • int (*a)[3] I'm saying that I have array of 3 integers -> int something[3] says that, and by putting (*a) instead of something I'm saying that those 3 integers happen to be pointers? I'm actually saying that those 3 integers have type: pointer. Is that right? – Aleksandar Makragić Jan 06 '16 at 22:29
  • @АлександарМакрагић No. `int a[3]` is very different from `int (*a)[3]`. In `int (*a)[3]`, `a` is a pointer that points to an array of 3 ints whereas `int a[3]` is an array of 3 ints. – P.P Jan 06 '16 at 22:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99990/discussion-between---and-l3x). – Aleksandar Makragić Jan 06 '16 at 22:36
1

If you want n to vary (and be square), it is best to allocate and use a single dimension array and multiply when you want a different row.

int matrix[3*3];

How to use it?

matrix[row*3+col] = 5;

How to pass it.

f(int *a,int n)
Robert Jacobs
  • 3,266
  • 1
  • 20
  • 30
0

int** is a pointer to a pointer (pointing on an int).

int[3][3], as a function argument, is converted to a pointer to an int array - see Is an array name a pointer?

So the types don't match, as the compiler is telling you.

Note: if you're doing pointer arithmetic in your function, you can pass int *a instead of int **a (by casting: print_matrix((int *)matrix, 3);. That's ugly but helps to understand what's going on - namely, a int[3][3] array is stored in memory exactly as a int[9] array, and if you're computing the int positions yourself, as you do, it will also work as a 1D array.

Community
  • 1
  • 1
Ilya
  • 5,377
  • 2
  • 18
  • 33
  • `int[3][3]` is an array of arrays. There's no "as a pointer", because it isn't one. It may be a matter of terminology but I think it is important to get this right because it confuses so many beginners (and some non-beginners too) – juanchopanza Jan 06 '16 at 22:44
  • As a parameter, int[3][3] is indeed converted to a pointer. But you're right, I'll update the description, it's not quite clear. As it is, I'm mixing the actual content of the parameters variables with the types that the compiler "sees". – Ilya Jan 06 '16 at 22:51
  • Yes, I think if you explain that a parameter of type `T[42]` is adjusted to `T*` then it will be clearer. But still, there is no parameter of type `int[N][N]` in the question. There is just an argument. – juanchopanza Jan 06 '16 at 22:53
  • @juanchopanza done (NB by parameter I meant function argument) – Ilya Jan 06 '16 at 22:58