0

I have encountered a problem with passing two dimensional arrays to other function as parameter. It was not working when I tried as below.

#include <stdio.h>

int display(int **src) {
    printf("%d", src[0][1]);
}

int main() {
    int arr[2][2] = {{1,2}, {3,4}};
    display(arr);
    return 0;
}`

It raises segmentation fault error. So I changed the display function as below

int display(int src[][3]) {
    printf("%d", src[0][1]);
}

I am not sure why first case raises error. Please help me to understand deeply about this case.

Lundin
  • 195,001
  • 40
  • 254
  • 396
Bojan
  • 637
  • 7
  • 17
  • 4
    What language is this? C or C++? Did you look at the compiler warnings? – rsjaffe May 20 '20 at 05:20
  • 2
    Hint: `int arr` makes *one integer*. – tadman May 20 '20 at 05:22
  • If you break it down `src[0]` is a pointer to an integer and then `src[0][1]` is the second integer from where this pointer points. However, you pass a single integer to the function and not an array and so you are trying to dereference an 'undefined' memory location, hence the fault. – DNT May 20 '20 at 05:26
  • I posted as wrong. the definition was int arr[2][2] = {...}; – Bojan May 20 '20 at 06:07
  • And rsjaffe and klutt there is no answer I am looking for in the link you sent me. I am looking for exact answer. I received parameter as two dimensional pointer but it accesses to null pointer area. In my opinion, it is casted to one dimensional pointer automatically. I would like to know exact reason – Bojan May 20 '20 at 06:23
  • @BojanStojanovic I agree that the duplicate was poor. I will re-open this question. Please edit it if needed. _Don't_ re-post it as a separate question, please. – Lundin May 20 '20 at 06:58
  • You don't need to use **, * will suffice, you are just passing an address, how you reference it in the function is up to you. – SPlatten May 20 '20 at 07:06
  • If you do not see a compiler error for the first case then adjust your settings. It is a complete waste of time to try and run an erroneous program . This is a common mistake (not using the right compiler settings and/or ignoring diagnostics) – M.M May 20 '20 at 07:32

2 Answers2

3
int display(int **src) {
    printf("%d", src[0][1]);
}

you can not do that because the compiler doesn't know the dimensions (rows and columns), in other words: C doesn't use introspection.

Instead:

int display(int src[][2]) {
    printf("%d", src[0][1]);
}

or if you prefer

int display(int (*src)[2]) {
    printf("%d", src[0][1]);
}

Note that you don't need to specify the first dimension, C is able to calculate the position based on the offset: (sizeof(int) * cols)

Also, you promised to return something from the function, if you don't want to return a value use:

void display(int (*src)[2]) {

Finally, as pointed out by @Scheff in comments, your original array haves 2 columns, receiving 3 will break the indexing in the receiver.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • "you can not do that because the compiler doesn't know the dimensions" Well, rather... you cannot do that because `int**` cannot point at an `int[x][y]`, since they are different, unrelated types. An `int**` can only point at the first element in a `int* [x]` pointer array. – Lundin May 20 '20 at 08:15
  • Thanks David and Ludin for great explanation. But I have a question. Even though compiler doesn't know dimensions, it is possible to indicate exact value using this -> *(*src+1) and array is allocated to memory sequentially so it is possible to get value by offset. src[0][1] is *(*src+1). isn't it? – Bojan May 20 '20 at 08:50
  • 1
    I just checked on my end and it was not allocated sequentially. It makes sense if it's not adjacently allocated. Thanks for your explanation. – Bojan May 20 '20 at 09:00
2

Pointers are not arrays and arrays are not pointers. There is a common misunderstanding that type** somehow has something to do with 2D arrays. It has not. It is not a 2D array and it cannot point at a 2D array.

There's a look-up table design pattern where you use int** to point at an array of int* items, where each int* points at a chunk of dynamically allocated memory. By using int** we can "emulate" the [x][y] array syntax, so these look-up tables look like 2D arrays, but they are not, because the data is not allocated adjacently. More on that topic here: Correctly allocating multi-dimensional arrays.

The correct way to pass a 2D array to a function is:

void display(int src[2][2]) {
  printf("%d", src[0][1]);
}

This does not pass the array by value, as one might think. Just like a regular 1D array, the parameter implicitly "decays" into a pointer to the first element, and the first element of a 2D array is a 1D array. So this is 100% equivalent to void display(int (*src)[2]);. And if we modify src[i][j] from inside the function, we therefore modify the original array allocated by the caller.

And because of this array decay, it actually doesn't matter what size we type for the outer-most (left) dimension. We can as well type void display(int src[][2]); (which is actually an array of imcomplete type) and the result will be the same: a decay into an array pointer int (*)[2].

If standard C variable-length arrays are available, then you can also declare the function with variable dimensions:

void display (size_t x, size_t y, int src[x][y]);
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Ah right, Thank you so much Lundin. I just tested 2d array and checked it's not allocated sequentially. Thanks for great explanation. – Bojan May 20 '20 at 08:59