1
void setArr(int x[2][2], int a, int b)
{
    for (int i = 0; i < a; i++)
        for (int j = 0; j < b; j++)
            x[i][j] = 0;
}
int main(void)
{
    int *arr[2];
    for (int i = 0; i < 2; i++) {
        arr[i] = malloc(sizeof(int) * 2);
    }
    setArr(arr, 2, 2);
}

I know this code will not work, but I do not know the reason behind it. Can any one explain to my why, in this case, I cannot use x[2][2] as a parameter to receive arr. Thanks

I put the code into a visualizer, and the setArr function sets the element of arr into NULL. I know that NULL is 0 in C. But I cannot connect why and how element of arr can be set to NULL.

XIAOYIJ
  • 13
  • 3
  • it's a good read with this topic - hope it helps you - https://www.geeksforgeeks.org/pass-2d-array-parameter-c/ – Rafaf Tahsin Sep 26 '19 at 06:31
  • 1
    Because `int *arr[2];` declares ***an array of pointers*** while `void setArr(int x[2][2], ...)` expects a ***pointer to array of int [2]***. You want `void setArr(int **x, int a, int b)` – David C. Rankin Sep 26 '19 at 06:31
  • @DavidC.Rankin No, they likely don't want `int**`, because they need a 2D array. – Lundin Sep 26 '19 at 08:45
  • @Lundin - that is what the function is set up to take, but not what is declared in `main()`. One or the other has to change. Presuming the declaration in `main()` of `int *arr[2];` and the subsequent allocation is intended, then the parameter must change to `int **x`. If `main()` above is wrong and what was intended was `int arr[2][2];`, then the loop and allocation make no sense. How do you know which one is correct? – David C. Rankin Sep 26 '19 at 13:35

3 Answers3

0

Function declaration void setArr(int x[2][2], int a, int b) declares setArr as a function that takes as a first parameter an array of 2 arrays each holding 2 integers. Whereas in the main you declare arr (the variable you pass to setArr) as int *arr[2], that is as a pointer to an array of 2 integers.

The solution is to either change your code in main, for example by declaring arr as int arr[2][2] and remove the for loop, or change the setArr so that it takes a pointer to an array of two integers void setArr(int *x[2], int a, int b).

I'm not sure if the latter could cause any problems (gcc -Wall compiles without warnings), but one thing to notice is the difference in memory layout when declaring arr as a pointer to an array of size 2 or declaring it as an array of 2 arrays of size 2. Compiling and executing the following should show you the difference:

    int main(void) {
        int *arr[2];
        for (int i = 0; i < 2; i++) {
            arr[i] = malloc(sizeof(int) * 2); 
        }   
        printf("The address of arr[0] is %p\n", &arr[0]);
        printf("The address of arr[1] is %p\n\n", &arr[1]);
        printf("The address of arr[0][0] is %p\n", &arr[0][0]);
        printf("The address of arr[0][1] is %p\n", &arr[0][1]);
        printf("The address of arr[1][0] is %p\n", &arr[1][0]);
        printf("The address of arr[1][1] is %p\n\n", &arr[1][1]);

        int arr2[2][2]; 
        printf("The address of arr2[0] is %p\n", &arr2[0]);
        printf("The address of arr2[1] is %p\n\n", &arr2[1]);
        printf("The address of arr2[0][0] is %p\n", &arr2[0][0]);
        printf("The address of arr2[0][1] is %p\n", &arr2[0][1]);
        printf("The address of arr2[1][0] is %p\n", &arr2[1][0]);
        printf("The address of arr2[1][1] is %p\n", &arr2[1][1]);

        // setArr(arr, 2, 2); 
}

Running the executable once on my machine I got the following:

The address of arr[0] is 0x7ffe43d226b0
The address of arr[1] is 0x7ffe43d226b8

The address of arr[0][0] is 0xb62010
The address of arr[0][1] is 0xb62014
The address of arr[1][0] is 0xb62030
The address of arr[1][1] is 0xb62034

The address of arr2[0] is 0x7ffe43d226c0
The address of arr2[1] is 0x7ffe43d226c8

The address of arr2[0][0] is 0x7ffe43d226c0
The address of arr2[0][1] is 0x7ffe43d226c4
The address of arr2[1][0] is 0x7ffe43d226c8
The address of arr2[1][1] is 0x7ffe43d226cc

You can see that the when declaring arr as an pointer to an array, the two arrays of two integers are not contiguous, whereas when declaring it as an array of arrays, they are. Moreover, when declaring it as an array of arrays there is no need to dynamically allocate memory (e.g., using malloc).

gstukelj
  • 2,291
  • 1
  • 7
  • 20
0

Can any one explain to my why, in this case, I cannot use x[2][2] as a parameter to receive arr.

Because you are using wildly different types. int *arr[2]; is an array of 2 int*, each of them assigned to an allocated chunk of memory. That's a lookup table or "jagged array" if you will, not a proper 2D array. See Correctly allocating multi-dimensional arrays for details.

Correct code for allocating a 2D array is this:

#include <stdlib.h>

void setArr(int a, int b, int x[a][b])
{
    for (int i = 0; i < a; i++)
        for (int j = 0; j < b; j++)
            x[i][j] = 0;
}

int main(void)
{
    int (*arr)[2] = malloc(sizeof(int[2][2])); 
    setArr(2, 2, arr);
    free(arr);
}

Here arr in main is a pointer to the first element of an int[2][2]. The first element of that 2D array is int[2], and a pointer to such an element is int(*)[2].

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

x[2][2] is just a declaration of a variable; there is no need to declare a var in input of a function; you must declare it before and just use its address:

void setArr(int** x, int a, int b)