views:

311

answers:

6
#include<stdio.h>
void foo(int **arr) {
    arr[1][1]++;
}

main() {
    int arr[20][20];
    printf("%d\n",arr[1][1]);
    foo((int**)arr);
    printf("%d\n",arr[1][1]);
}
+5  A: 

Because foo expect a pointer to a pointer to int and you are passing it a pointer to an array of 20 int. Casting it won't change the fact that it isn't the correct type.

AProgrammer
Can u explain in detail "pointer to an array of 20 int" ?
avd
+4  A: 

foo needs to know the array size (well, at least the second array dimension, first isn't needed), otherwise it can't do the necessary pointer arithmetic for the [1][1].

Peter Alexander
John, can you please elaborate?
Matthew Flaschen
Yes, I'd also like to know why this is wrong, when I am certain that it is not, and all the other answers say the same thing...
Peter Alexander
Well, the compiler isn't segfaulting because it is missing information about one of the array's dimensions. It's segfaulting because it's dereferencing where it shouldn't be. If `arr` were a true `int**` ragged array then the compiler would not need to know the size of either dimension, nor would it crash when accessing the array items.If the OP had written `void foo(int arr[][])` and gotten a compile error about a missing dimension then your answer would be correct. As is it is only the tip of the iceberg. @Steve Jessop explains better why the program crashes, IMO.
John Kugelman
Well obviously it's segfaulting because it's accessing the wrong memory - that's what a segfault is. The real question is why it's accessing the wrong memory in the first place, and that's because he's getting the types mixed up.
Peter Alexander
I think this answer goes some way towards explaining what you actually need to do in order to pass a 2-D array as a function parameter. That is, *what's wrong with the questioner's code* to cause the crash. What I explained is *what the wrong code does* that causes the crash: a more proximate cause.
Steve Jessop
You could say this answer is incomplete (I would argue most of the others are too), but it's not wrong. Poita didn't say you can never pass arrays of pointers, or that the OP's code caused a compiler (as opposed to run-time) error.
Matthew Flaschen
+1  A: 

Problem is that int arr[20][20] for 2d array means that this array is stored as 1d array, and lines are stored one after other. when you do indexing to int **arr you actually take 2nd element from first line of array, then you dereference it and take first element there.

Andrey
+7  A: 

Suppose you declare: int arr[ 10 ][ 20 ] ;
What type is arr?
You may think that it's int **, but that's incorrect.

Its actually of type int (*)[20] when it decays (like when you pass it to a function);
Array decaying applies only once.

Details here


Now consider the following,

#include<stdio.h>
#include<stdlib.h>
void foo(int arr[][20]) {
  arr[1][1]++;
}
main() {
  int (*arr)[20];
  arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.

  printf("%d\n",arr[1][1]);
  foo(arr);
  printf("%d\n",arr[1][1]);
}

Output :

$ gcc fdsf.c && ./a.out
0
1


arr and arr+1 are pointing to array of 20 integers.

arr + 0 --> int       int       int    ...    int (20 ints, contiguous)
             [0][0]   [0][1]
arr + 1 --> int       int       int    ...    int (20 ints, contiguous)
             [1][0]   [1][1]

N 1.1
It's actually of type `int[10][12]`, although it decays to `int(*)[10]`. Look at `sizeof(arr)` to see this.
Steve Jessop
@Jessop: right o! thanks :)
N 1.1
Doesn't it decay to `int(*)[12]`?
UncleBens
@UncleBens: updated. Thanks :)
N 1.1
@UncleBens: Good point. Look at `sizeof *arr` to see this ;-)
Steve Jessop
+5  A: 

Here's what an int[2][2] looks like in memory:

int[2] int[2]

That is, an array immediately followed by another array.

Here's what an int[2] looks like in memory:

int int

That is, an int immediately followed by another int.

So, here's also what an int[2][2] looks like in memory:

int int int int
     ^       ^
     |       |___ this is arr[1][1]
     |
     |____ this is p[1], assuming sizeof(int*) == sizeof(int)

If you cast arr to an int**, I'm going to call the result p. Then it points to the same memory. When you do p[1][1] you don't get arr[1][1]. What the program does instead is, it reads the value at p[1], adjusts that up by the size of an int, and dereferences it. If that second int contained, say, the value "21" then you have just tried to dereference the pointer "25" (if int is 4 bytes). That ain't right.

Arrays are not the same as pointers, and 2-D arrays are certainly not the same thing as pointers-to-pointers.

Steve Jessop
+5  A: 

If you change it like this, you get the expected result:

#include<stdio.h>
void foo(int arr[][20]) {
    arr[1][1]++;
}

int
main() {
    int arr[20][20];
    arr[1][1] = 1;
    printf("%d\n",arr[1][1]);
    foo(arr);
    printf("%d\n",arr[1][1]);
}
Lucas
This is correct, but you don't have to put the first dimension.
Matthew Flaschen
@Matthew: changed
Lucas