2

I was wondering if it is possible to set the length of an array to another given value in the same structure? I want this lenght to be constant, no need to make a dynamic array or something like that Something like this code below

struct Screen {
    int x ;
    int y ;
    int rows ;
    int columns ;
    char screen[rows][columns] ;
}

I'm very new to C-based languages, it's certainly a very basic knowledge, but hey, that's why I'm learning! (Also excuse my bad English) Any Response would be welcome !

Pajul
  • 23
  • 3
  • 1
    rows and columns shall be known in the data member declaration char screen[rows][columns] ; of the structure. – Vlad from Moscow May 11 '23 at 16:40
  • 3
    No it's not possible. The values of the variables aren't known. at compile-time, and VLA's are not possible in structures. Perhaps it can be solved with more structures and [*flexible array members*](https://en.wikipedia.org/wiki/Flexible_array_member). Otherwise you need to use pointers. – Some programmer dude May 11 '23 at 16:42
  • 1
    It would be possible to use a flexible array member if flattened to one dimension `char screen[];` but some arithmetic will be required by code that needs to access the element for a particular row and column. – Ian Abbott May 11 '23 at 17:51
  • This seems like a duplicate: https://stackoverflow.com/questions/76218493/how-to-create-a-user-defined-sized-2d-array-of-struct-in-c – nielsen May 11 '23 at 19:30

2 Answers2

4

Variable length arrays are not allowed inside of a struct, and a flexible array member can't be used if more than one dimension varies.

The best thing to do to emulate a 2D array is use a double pointer:

struct Screen {
    int x ;
    int y ;
    int rows ;
    int columns ;
    char **screen;
};

And allocate space for it as appropriate:

struct Screen screen;
screen.rows = 4;
screen.columns = 5;
screen.screen = malloc(screen.rows * sizeof *screen.screen);

int i;
for (i=0; i<screen.rows; i++) {
    screen.screen[i] = malloc(screen.columns * sizeof **screen.screen);
}
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Better use 1D array with manual index calculations (`char screen[]`) or use a pointer to a 2D array (`char (*screen)[]`), assign it to a pointer to VLA to access elements via `[x][y]` notation – tstanisl May 11 '23 at 21:24
  • @tstanisl I considered a pointer to an incomplete array type, but that can only be used for a 2D array (not 3 or more) and I wanted to offer something that was more generalizable. – dbush May 11 '23 at 21:41
  • Yes. So likely 1d FLA cast to VLA pointer is a reasonable option – tstanisl May 11 '23 at 21:46
0

It is possible, but you'll need to specify the size when you allocate memory for the structure. Just make the array small.

struct Screen {
    int x ;
    int y ;
    int rows ;
    int columns ;
    char screen[1][1];
}

And then, when you allocate memory for the structure, allocate extra bytes for the additional items.

pScreen = malloc(sizeof(struct Screen) + ??? );

This could get a bit messy though if you need to resize it.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 2
    The right way to do it would be to have a [flexible array member](https://en.wikipedia.org/wiki/Flexible_array_member). The way you show is a hack. – Eugene Sh. May 11 '23 at 17:01
  • 1
    @EugeneSh. Both are hacks. The way I implemented was as you indicated, but I recall at the time that not all compilers supported it in the same way. – Jonathan Wood May 11 '23 at 17:07
  • 2
    Independent of the hack debate and undefined behavior, this will not do correct address calculations unless the runtime number of columns == 1. – Avi Berger May 11 '23 at 17:25
  • @AviBerger: Absolutely. You'll need to know what the heck you're doing when taking this approach. – Jonathan Wood May 11 '23 at 18:16