1

I am trying to create a struct. One of the elements of the struct is an array that should be able to grow if needed.

I do this:

int  COLS=2, ROWS=20;
long int (*array)[COLS] = malloc(sizeof(int[ROWS][COLS]));

struct test{
    long int (*arr)[COLS];
};

struct test *s_test = malloc(sizeof(s_test));
s_test->arr = array;

for (int i=0; i<ROWS; i++){
    array[i][0]=i;
    array[i][1]=i+20;

    printf("0:%ld\t1:%ld\n",s_test->arr[i][0], s_test->arr[i][1]);
}

but the compiler says:

test.c:10:14: error: fields must have a constant size: 'variable length array in structure' extension will never be supported
                long int (*arr)[COLS];

This works ok:

int COLS=2, ROWS=20;
long int (*array)[COLS] = malloc(sizeof(int[ROWS][COLS]));

long int (*arr)[COLS];

//struct test{
//  long int (*arr)[COLS];
//};

struct test *s_test = malloc(sizeof(s_test));

//s_test->arr = array;

arr = array;

for (int i=0; i<ROWS; i++){
    array[i][0]=i;
    array[i][1]=i+20;

    printf("0:%ld\t1:%ld\n", arr[i][0], arr[i][1]); //s_test->arr[i][0], s_test->arr[i][1]);
}

BTW, I, mistakenly forgot to delete the declaration of a struct test (which is not defined now) and the compiler didn't complain...). I will also appreciate a very simple (if possible) explanation of why.

1 - I clearly don't know how to solve this problem.
2 - Does the struct HAS to be a pointer?
3 - Can't the element arr be a pointer to theh 2darray?

Thank you a lot!

aerijman
  • 2,522
  • 1
  • 22
  • 32
  • 2
    Make `COLS` a macro instead of a variable. – Barmar Dec 18 '20 at 00:19
  • You can't grow an array. You can only grow memory that was allocated dynamically with `malloc()`. `long int (*arr)[COLS]` declares an array that has `COLS` rows, and each row is a pointer. You can resize the rows, but not the main array. – Barmar Dec 18 '20 at 00:21
  • 1- The mentioned question does not include a variable array within a struct. 2- One of the things that in my view makes this community so helpful is that the answers can be focused on a specific question and not a chapter of a book. 3 - It's not helpful closing the question without providing an answer when the answer is not clearly stated in the mentioned original question. – aerijman Dec 18 '20 at 01:08
  • There's no difference when the array is in a struct. – Barmar Dec 18 '20 at 01:10
  • Just declare `long int **arr` as the struct member, and do it as in the linked question. – Barmar Dec 18 '20 at 01:11
  • @Barnar. 1 -thank you. 2- With `long int **arr` as the struct member I then get `incompatible pointer types assigning to 'long **' from 'long (*)[2]` for ` s_test->arr = array;`. When using a macro to define COLS, I get a segmentation fault. I don't understand why. – aerijman Dec 18 '20 at 01:26
  • Of course you need to change other things to be compatible. Pointers are not the same as arrays. – Barmar Dec 18 '20 at 01:27
  • @Barmar `long int **array = malloc(sizeof(COLS) * sizeof(ROWS));` does not seem to help me. Is it so simple? Would you mind expanding a little bit why **arr is a better solition. Also, why do you say pointers and arrays are not the same? Array variable is a pointer to the first element of a chunk of memory, isn't it? – aerijman Dec 18 '20 at 01:37
  • `malloc(COLS * ROWS * sizeof(long int))` – Barmar Dec 18 '20 at 01:44
  • But then it should be declared `long int *arr` – Barmar Dec 18 '20 at 01:44
  • @Barmar But then I can't access `array[a][b] `? – aerijman Dec 18 '20 at 01:48
  • Right. If you want to be able to access it like that, you need to make a dynamic array of pointers to dynamic rows. – Barmar Dec 18 '20 at 01:51

1 Answers1

1

Disclaimer: I think long int (*arr)[COLS] (flexible array to pointer to long) is a mistake; but all you need to do to fix it is adjust the type.

That doesn't look quite right. if COLS really is dynamic we need to say:

struct test{
    long int (*arr)[];
};

but this is invalid due to the toy example being too small. The stretchy element has to be the last one, but it can't be the only one either. Needs to look like this:

struct test{
    size_t nelem; /* I suppose you could have another way of knowing how many */
    long int (*arr)[];
};

and you allocate it with a call that looks like this:

    struct test *ptr = malloc(sizeof(struct test) + sizeof (long int *) * COLS);

If COLS is really constant, the way to get to compile is to change the declaration of COLS to be a macro, or an enum like so: enum { COLS = 2; };

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • 1
    BTW, Could use `sizeof *ptr + sizeof ptr->arr[0] * COLS` and remove any type matching maintenance issues. – chux - Reinstate Monica Dec 18 '20 at 04:28
  • @chux-ReinstateMonica. Your addition looks good to me but I get: `error: subscript of pointer to incomplete type 'int []'`. – aerijman Dec 19 '20 at 17:06
  • @Joshua, Thank you very much! 1 - s_truct->arr is now a pointer to array of int (with COL dimensions). Now I have to allocate memory for the array, right? Will I have to allocate memory for each COL separately? My intention is to call the array like:`arr[row][col]. 2 - I use long int because the numbers are genomic locations and unsigned int is not enough. Should I use other type – aerijman Dec 19 '20 at 17:51
  • @aerijman Does `sizeof *ptr + sizeof *(ptr->arr) * COLS` also error? – chux - Reinstate Monica Dec 19 '20 at 18:03
  • @chux-ReinstateMonica. I get `error: invalid application of 'sizeof' to an incomplete type 'int []'` – aerijman Dec 19 '20 at 18:19
  • So far, the only way I make it work is by declaring `test.arr` as `int (*arr)[COLS]` then `s_test->arr = malloc(sizeof(int[ROWS][COLS]))`. I couldn't yet understand how to declare the element arr pointer to int array and allocate later the memory for a 2d array that I can use with the indices arr[i][j] – aerijman Dec 19 '20 at 19:21