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("=============");
}
7
  • 4
    because matrix[3][3] isn't a int** but *int[3] Commented Mar 15, 2017 at 7:06
  • but shouldn't it access the same memory location? Commented Mar 15, 2017 at 7:07
  • 1
    @noob No, not at all. After all, an int** is a pointer to a pointer. While a *int[3] contains pointers to integers. How can code that expects pointers to pointers work if you give it pointers to integers? Commented Mar 15, 2017 at 7:09
  • I see. I used the ** since I want the size to be dynamic. How can I declare this function if I want both dimensions of the array to be determined in run-time? Commented Mar 15, 2017 at 7:12
  • 3
    If you're gonna work with multi-dimensional arrays, read this stackoverflow.com/questions/42094465/… Commented Mar 15, 2017 at 7:13

2 Answers 2

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;
}
Sign up to request clarification or add additional context in comments.

3 Comments

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
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?
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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.