-2

I wrote the following code, however compilation fails with the message

Program received signal SIGSEGV, Segmentation fault. main () at qary_code.cpp:130 out<<four_ary_matrix[i][j]<<" "; (gdb)

I want to pass the 2D array to a function, but the length len will change, so I'm also wondering how to pass the 2D array to the function

code:

int** global_fourary_matrix;

void print_ary(int** ary, int len){
    
    for(int i=0;i<len;i++) {
        for(int j=0;j<len;j++) {
            cout<<ary[i][j]<<" ";
        }
        cout<<endl;
    }
}

void main(){

    int four_ary[][4] ={ {0,0,0,0}, {0,1,2,3}, {0,2,3,1}, {0,3,1,2} };
    global_fourary_matrix = (int**) four_ary;

    for(int i=0;i<4;i++) {
        for(int j=0;j<4;j++) {
            cout<<global_fourary_matrix[i][j]<<" ";
        }
        cout<<endl;
    }
    
    int len=4;
    print_ary(global_fourary_matrix, len);
}

another written style was

global_fourary_matrix = (int**) &(four_ary[0]);

however, the compiler still say the same thing

Rohit Gupta
  • 4,022
  • 20
  • 31
  • 41
Ali
  • 1
  • `int**` is a pointer to a pointer to an `int`. A 2D array decays not to a pointer to a pointer but instead to a pointer to a 1 D array. Very different things. – user4581301 Jul 11 '23 at 06:15
  • While an array can decay to a pointer to its first element, this decay happens only for the outer array. So `four_ary` is the same as `&four_ary[0]`, which is a pointer to an array, and have the type `int (*)[4]`. In short [an array of arrays is not compatible with a pointer to a pointer](https://stackoverflow.com/questions/18440205/casting-void-to-2d-array-of-int-c/18440456#18440456). – Some programmer dude Jul 11 '23 at 06:15
  • 1
    Just don't use globals, and stop using "C" style arrays like this they come with all kind of potential bugs. Wrap your matrix inside a class and pass that around. A int** is NOT (semantically) a matrix. You probably forgot to allocate any memory and your pointer is not even initialized. Have a look at std::array, std::vector to implement your matrix class. – Pepijn Kramer Jul 11 '23 at 06:16
  • Also, whenever you feel the need to do a C-style type-conversion (or *cast*) like you do with `(int**) four_ary`, then you should take that as a sign that you're probably doing something wrong. Doing it to silence the compiler from giving errors is *definitely* wrong. – Some programmer dude Jul 11 '23 at 06:17
  • 1
    On another note, matrices are so common there are a lot of good tested libraries for you to reuse (which will also help with hardware acceleration if needed). So use one of those and focus on the rest of the code you need to write. – Pepijn Kramer Jul 11 '23 at 06:18
  • Just because `T[N]` is assignable to `T*` does not mean that `T[M][N]` is assignable to `T**`. Only one level of array can be converted this way. So `T[M][N]` is actually assignable to `T (*)[N]`. – john Jul 11 '23 at 06:44
  • So in your case the legal code is `void print_ary(int (*ary)[4], int len){` but notice that your second dimension is fixed at `4`. – john Jul 11 '23 at 06:48
  • @OP. Either use an `int array[4][4]` throughout your code, or use `int **array` throughout your code. You cannot mix and match them by doing casting -- it's just plain wrong. If you removed the `int **` cast, what error does the compiler give you? All you did when you did the `int **` cast is tell the compiler "shut up, I know what I'm doing", and that was wrong. Or as already mentioned, use `std::vector` or `std::array`. – PaulMcKenzie Jul 11 '23 at 08:46

2 Answers2

1

Employing some other way rather than int** is better, but if you really need to pass your 2D array to int** type argument... what you can do is like this:

void print_ary(int** ary, int len);

int main()
{
    //You want pass this 2D array to the function "print_ary", but you can not do it directly.
    int four_ary[][4] ={ {0,0,0,0}, {0,1,2,3}, {0,2,3,1}, {0,3,1,2} };
    
    //So, here,
    //Creating `int*[]` type array.
    //Each element is `int*` type and pointing correspond row of the 2D array "four_ary".
    int *Rows[] = { four_ary[0], four_ary[1], four_ary[2], four_ary[3] };
    //And, passing the array "Rows" instead of the 2D array "four_ary".
    print_ary( Rows, 4 );
}
fana
  • 1,370
  • 2
  • 7
  • thanks for the response. I'm wondering what can the arguments of print_ary look like? – Ali Jul 11 '23 at 06:48
  • The `print_ary` function is yours. ( `void print_ary(int** ary, int len)` ) – fana Jul 11 '23 at 06:53
  • yes, I want to pass a 2D array to print_ary(int** ary, int len), but don't know how should it look with arguments – Ali Jul 11 '23 at 06:56
  • So, I think this post answered the point... As described by many comments for this question, 2D array can not passed to `int**` type argument as is. Therefore, in this post, creating `int*[]` type array and passing it instead. – fana Jul 11 '23 at 07:01
  • Added comment lines to represent what doing. and also added type of `print_ary` explicitly. – fana Jul 11 '23 at 07:12
1

You have been told that an int[][4] is not an int**, but I thought I would illustrate the difference a bit.

An int[][4] is an array where each element is itself an array of exactly four ints. This results in a single contiguous chunk of memory where A[0][0] is followed directly by A[0][1], and A[0][3] is followed directly by A[1][0].

Arrays

On the other hand, an int** is a pointer to an array of pointers (array of int*), where each array element itself points to an array of ints. Here each individual array is a contiguous chunk of memory, but there are no restrictions on how the arrays are arranged in memory relative to each other. Also, there is no restriction on the length of the individual sub-arrays.

So what happens if you try to access an int[][4] as if it was a int**? Well, if you do B[0][0] where B actually points to A, then you are going to take the element at A[0] (= the int at A[0][0]) and treat it as a pointer to the first sub-array - dereferencing it and trying to access whatever it points to. In your case the first int is 0, so essentially you try to access a NULL pointer giving you a segmentation fault.

Ps. This is a somewhat simplified look at the situation, and does not take stuff like the bit-width of int vs. pointer into account. Suffice to say: If you do it does not get better.

Frodyne
  • 3,547
  • 6
  • 16