0

Trying to work on leetcode #497 in C on my vscode. When writing main(), I am not sure how to deal with int** that leetcode provides. Is it possible to pass a 2D array using int**?


#include <stdio.h>
#include <stdlib.h>


typedef struct {
    
    int rectsSize;
    int * rectsColSize;
    int** rects;    
} Solution;

int points[100];

Solution* solutionCreate(int** rects, int rectsSize, int* rectsColSize) {
    
    Solution* sol = malloc(sizeof(Solution));
    sol->rects = rects;
    sol->rectsSize = rectsSize;
    sol->rectsColSize = rectsColSize;
    //some codes
    }
    return sol;
}

int* solutionPick(Solution* obj, int* retSize) {
    //some codes
    return ret;
}

void solutionFree(Solution* obj) {
    free(obj);
}

int main(void)
{
    int rects[2][4] = {{1, 1, 5, 5}, {6, 6, 9, 9}};
    int rectsSize = 2;
    int rectsColSize = 4;
    int retSize;
    Solution* obj = solutionCreate(rects, rectsSize, &rectsColSize);
    int* param_1 = malloc(sizeof(int));
    param_1 = solutionPick(obj, &retSize);
    solutionFree(obj);
    return 0;
}

Walrus
  • 11
  • 1
  • 3
  • 1
    I'm a bit confused about where your problem is. Are you asking if its valid to pass an `int[][]` to something expecting an `int**`? – David Sullivan Oct 04 '20 at 05:14
  • @DavidSullivan I guess it's not valid, but I wonder how leetcode use it to pass the array, because I want to test my solution offline so I need to write the main() function myself. – Walrus Oct 04 '20 at 05:32
  • `int **rects` isn't technically a 2D array, even though 2D array syntax can be used (e.g. `rects[0][0]` works). Instead it's an array of pointers. Each of those pointers points to an array of `int`. So if you want a 3 row by 5 column array, you first need to allocate memory for an array of three pointers. Then for each of those three pointers, you need to allocate an array of five `int`. – user3386109 Oct 04 '20 at 05:35
  • 1
    "Is it possible to pass a 2D array using int**?" --> No. `int **` matches a pointer to a `int *`. With `int** rects` , the `rects` in `main` needs to be a a different type. – chux - Reinstate Monica Oct 04 '20 at 12:58

1 Answers1

0

While in general there are many different ways to handle 2D array, the simple answer is no. There is a lot of info about 2d arrays in C: 1, 2, 3, etc. In principle, when dealing with 2d arrays, every dimension except first to the left needs to be specified exactly. In your case, every rectangle is defined by 4 integers, so instead int** rects consider int*[4] rects. This makes rectsColSize useless, because now each column has constant size of 4 ints.

Just for completness: what you are trying to do is second approach to arrays, where each column has independent size, and (usually) additional malloc call. While this approach is also valid and requires int** type, it is not needed for your task. Nice description of the difference here.

Edit

Here is how to loop through 2d arrays:

#define col 4
void print_2d(int (*a)[col], int aSize){
    for(size_t i = 0; i < aSize; i++){
        for(size_t j = 0; j < col; j++){
            printf("%d ", a[i][j]);
        }
    printf("\n");
    }
}

and here for int**:

void print_pp(int** a, int aSize, int* aiSize){
    for(size_t i = 0; i < aSize; i++){
        for(size_t j = 0; j < aiSize[i]; j++){
            printf("%d ", a[i][j]);
        }
    printf("\n");
    }
}

It seems that you want to convert int*[4] to int**, or more precisely, int*[4] arr2d with it's size int arr2dSize to structure Solution. In that case, here is wrapper to solutionCreate.

Solution* solutionCreateWrap(int (*arr2d)[4], int arr2dSize) {
    int* rectsColSize = malloc(arr2dSize * sizeof(int));
    int** rects = malloc(arr2dSize * sizeof(int*));
    size_t arr2dMem = arr2dSize * 4 * sizeof(int);
    rects[0] = malloc(arr2dMem);
    memcpy(rects[0], arr2d, arr2dMem);
    rectsColSize[0] = 4;
    for(size_t i = 1; i < arr2dSize; i++){
        rects[i] = rects[0] + i*4;
        rectsColSize[i] = 4;
    }
    sol->rects = rects;
    sol->rectsSize = rectsSize;
    sol->rectsColSize = rectsColSize;
    //some codes
    }
    return solutionCreate(rects, arr2dSize, rectsColSize);
}

Now for int rects[2][4] = {{1, 1, 5, 5}, {6, 6, 9, 9}}; call solutionCreateWrap(rects, 2) will return initialised structure Solution. It looks gruesome, and it's details are even worse, so if it just works, you may skip the explanation. Understanding low level C details isn't neccesarily to write in it, and this (or any other) explanation cannot possibly cover this matter, so don't be discouraged, if you won't get it all.

arr2d is contiguous block of memory of arr2dSize*4 integers. When multiplied by sizeof(int) we get size in bytes - arr2dMem in my code. Declaration int (*arr2d)[4] means, that arr2d is of type int*[4]. Knowing this we can cast it to int* like so: int* arr = (int*)arr2d and expression arr2d[i][j] is translated as arr[i*4+j].

The translation to rects is as follows; int** is array of pointers, so every rect[i] has to be pointer to i-th row of arr2d. Knowing this, everything else is pointer arithmetic. rects[0] = malloc(arr2dMem); and memcpy(rects[0], arr2d, arr2dMem); copies whole arr2d to rect[0], then every next rects[i] = rects[0] + i*4; is shifted 4 integers forward. Because rect is of type int**, the expression rects[i][j] translates to *(rects[i]+j), and replacing rects[i] by rects[0] + i*4, we get *((rects[0] + 4*i)+j), that is rects[0][4*i+j]. Note striking similarity between last expression, and arr[i*4+j]. rectsColSize is somewhat superfluous in this case, but it is essential in general int** array, when every subarray could have different sizes. After wrap function is done, rects is exact copy of arr2d, but with type appropriate for your Solution structure, so we can call solutionCreate().

Przemek
  • 240
  • 2
  • 8
  • 1
    My only problem is that the `int** rects` is provided by LeetCode by default when I chose C. Though I think it to be weird, on leetcode it is okay to treat `rects` as a normal 2d array, where you can use rects[0][0] etc. – Walrus Oct 04 '20 at 05:24
  • It's not weird at all. I might write my answer too sloppy, but `int**` is that second type of array - array of pointers. Anyhow the last link has nice explanation. Both arrays use the same syntax which may be confusing, because the difference is in memory layout. – Przemek Oct 04 '20 at 05:48
  • Could you please show me an example of initialising and using that second type of array? I am now aware of the difference but still a bit confused. – Walrus Oct 04 '20 at 06:11