2

I'm having trouble understanding why my code crashes when accessing the array. When converting the function param to int[3][3] instead of int** I get no problems, but I can't understand why, since the int** I'm given as a argument is a valid pointer that points to local memory defined in main

typedef struct {const unsigned int m; const unsigned int n;} mat_size;

void print_mat(int** mat, mat_size s){  // <-- faulty version
    int i,j;
    for(i = 0; i < s.m; i++){
        for(j = 0; j < s.n; j++){
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    } 
    printf("=============");
}


int main(int argc, char** argv) {

    int matrix[3][3] = {{1,4,2},{7,-1,15},{33,-10,-1}};
    mat_size s = {3,3};
    print_mat(matrix, s);  

    while(1);
    return 0;
}

void print_mat(int mat[3][3], mat_size s){  // <-- good version
    int i,j;
    for(i = 0; i < s.m; i++){
        for(j = 0; j < s.n; j++){
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    } 
    printf("=============");
}
CIsForCookies
  • 12,097
  • 11
  • 59
  • 124

2 Answers2

3

The type of function parameter does not match the passed matrix because matrix[3][3] isn't a int** but (*int)[3].

From comment you also want to have dynamic sizes for your matrix so you can do that using VLA :

#include <stdio.h>

typedef struct
{
    const unsigned int m;
    const unsigned int n;
} mat_size;

void print_mat(mat_size s, int (*mat)[s.n])
{
    unsigned int i, j;
    for (i = 0; i < s.m; i++)
    {
        for (j = 0; j < s.n; j++)
        {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
    printf("=============\n");
}

int main(int argc, char** argv)
{

    int matrix[3][3] = { { 1, 4, 2 }, { 7, -1, 15 }, { 33, -10, -1 } };
    mat_size s = { 3, 3 };
    print_mat(s, matrix);

    return 0;
}
LPs
  • 16,045
  • 8
  • 30
  • 61
  • thx! I tried using the mat_size s.n as argument but didn't succeed so I thought of sending mat as void* and then casting it inside the function, but this looks way better – CIsForCookies Mar 15 '17 at 07:19
  • If I now want to create a new function that returns a dynamically-determined-sized-array, how would I do that? I cant declare a "int [][] f(){}"... so should I declare a void* and then cast it? – CIsForCookies Mar 15 '17 at 07:34
  • 1
    You should think to use a struct with pointer to dynamic allocated array and dim. So you can return a simple struct pointer. Otherwise you can pass output arrays pointer ans sizes as parameters to function. – LPs Mar 15 '17 at 07:36
1

An array that is declared as a function parameter gets silently adjusted by the compiler to the first object. This is why

void func (int a[5]);

is equivalent to

void func (int* a);

Similarly, an array that is declared by the caller and passed to such a function, also "decays" into a pointer to the first element.

The rationale behind this is that arrays shouldn't get passed by value to functions, since taking a hard copy of an array takes up execution time and memory.


In the case of multi-dimensional arrays, the same rules apply. Given a function void print_mat(int mat[3][3]), the array will get silently adjusted to a pointer to the first element. The first element in an int [3][3] array is an array of type int[3]. Therefore a pointer to such an element must be an array pointer, int (*)[3].

Therefore void print_mat(int mat[3][3]) is equivalent to void print_mat(int (*mat)[3]). So you can change the function to use such an array pointer and it would be equivalent.

However, I would recommend using a variable approach instead:

void print_mat (size_t x, size_t y, int mat[x][y])

Pointer-to-pointers have nothing to do with multi-dimensional arrays, though they can be used to emulate one together with dynamic memory allocation. Doing so is however most often bad and incorrect practice. See Correctly allocating multi-dimensional arrays for more info about that.

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396