1

I want to initialize a two dimensional array with a variable size in visual studio 2017 c. It is a simple square with a the dimensions of an integer. However i get the following errors missing subscript and cannot allocate an array of constant size 0.

int dim = 10;
short square [dim][dim];

Using malloc does not work using the two dimensions as before meaning that the rest of the code does not work anymore, what is the best solution to still use a two dimensional array with a varialbe size in visual studio 2017?

int *arr = (int *)malloc(row * col * sizeof(int)); 
Meng
  • 191
  • 9

4 Answers4

2

If MSVC doesn't support VLAs, but your code expects to index into arr as arr[i][j], then you're going to have get creative.

If your array contents need to be contiguous, then you need to allocate a single backing store:

int *store = malloc( dim * dim * sizeof *store );

and then allocate arr as an array of pointers into that storage:

int **arr = malloc( dim * sizeof *arr );

for ( size_t i = 0; i < dim; i++ )
  arr[i] = store + i * dim;

Which gives us something like this:

     int **      int *                  int
     +---+      +---+                   +---+
arr: |   | ---> |   | arr[0] ---------> |   | arr[0][0]  (store[0])
     +---+      +---+                   +---+
                |   | arr[1] -------+   |   | arr[0][1]  (store[1])
                +---+               |   +---+
                 ...                |    ...
                +---+               |   +---+
                |   | arr[dim-1] -+ |   |   | arr[0][dim-1] (store[dim-1])
                +---+             | |   +---+
                                  | +-> |   | arr[1][0] (store[dim])
                                  |     +---+
                                  |     |   | arr[1][1] (store[dim+1])
                                  |     +---+
                                  |      ...
                                  |     +---+
                                  |     |   | arr[1][dim-1] (store[dim+dim-1])
                                  |     +---+
                                  |      ...
                                  |     +---+
                                  +---> |   | arr[dim-1][0] (store[dim*(dim-1)])
                                        +---+
                                        |   | arr[dim-1][1] (store[dim*(dim-1)+1]
                                        +---+
  
     

If your array doesn't need to be contiguous, you can do a "jagged" allocation:

int **arr = malloc( dim * sizeof *arr ); // allocates your "columns"
if ( arr )
{
  size_t i;
  for ( i = 0; i < dim; i++ )
  {
    arr[i] = malloc( dim * sizeof *arr[i] ); // allocates your "rows"
  }
}

arr is a pointer to a dim-element array of int *, and each arr[i] is a pointer to a dim-element array of int, giving you something like this:

     int **      int *                      int
     +---+       +---+                      +---+
arr: |   | ----> |   | arr[0] ------------> |   | arr[0][0]
     +---+       +---+                      +---+
                 |   | arr[1] ----------+   |   | arr[0][1]
                 +---+                  |   +---+
                  ...                   |    ...
                                        |   
                                        |   +---+
                                        +-> |   | arr[1][0]
                                            +---+
                                            |   | arr[1][1]
                                            +---+
                                             ...

Note that if you're passing arr to any functions, the corresponding function argument must have type int **, not int (*)[dim] or int [][dim] or int [dim][dim].

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1
    Using pointers-to-pointers is an inefficient way to implement two-dimensional arrays and should not be recommended in most circumstances. Its only benefit is allowing an `x[i][j]` syntax instead of a calculating index or auxiliary function or macro, but that is a minor benefit to the programmer, and students ought to learn to do things well even if it takes a little more effort on their part. – Eric Postpischil Jun 20 '21 at 20:35
  • Also, the decision has nothing to do with whether the memory needs to be contiguous. The pointer-to-pointer method does not require non-contiguous memory. It can be implemented simply by allocating one block for all the elements and setting the various pointers appropriately, and this is better because it reduces allocations and frees and uses less memory (since the memory manager has fewer blocks to keep track of). – Eric Postpischil Jun 20 '21 at 20:37
2

int *arr = (int *)malloc(row * col * sizeof(int)); You already got the allocation part right (though you can drop the cast). Now simply access members like this:

for(size_t i=0; i<row; i++)
  for(size_t j=0; j<col; j++)
    arr[i*col + j] = ... ;

This is sometimes referred to as "mangled 2D arrays", and was how such arrays were used back in the 1990s, before "variable-length arrays" got standardized in 1999.

Please note that pointer-to-pointer solutions are needlessly inefficient and complex. See Correctly allocating multi-dimensional arrays for details (though that post uses modern standard C with VLA, so the examples won't compile in MSVC).

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

I want to initialize a two dimensional array with a variable size in visual studio 2017 c.

I have heard that Microsoft's most recent C compiler supports variable-length arrays, or maybe it's that a soon-to-come one will. Support for them is optional in C11 and C17, however, and historically, Microsoft compilers have omitted that support. Even when C99, in which VLA support is obligatory, was the current standard. Thus, it is not particularly surprising that MSVC 2017 rejects your VLA declaration.

Using malloc does not work using the two dimensions as before meaning that the rest of the code does not work anymore,

It is possible to allocate a two-dimensional array via malloc, such that it can be accessed as a 2D array, but

  • your example pointer declaration and allocation do not have the correct form for that, and
  • without VLA support, you still need to declare a constant size for the second dimension.

what is the best solution to still use a two dimensional array with a variable size in visual studio 2017?

If VS 2017 does not accept the code presented in the question then it does not afford any mechanism for declaring a 2D array with both dimensions determined at run time. Some of your better alternatives then are:

  • Choose an upper bound on the supported array size, and declare it as having that size. On any given run, use only the portion of it that you need.

  • Declare and dynamically allocate an array of pointers, which will serve as pointers to the array rows. Dynamically allocate space for each row, separately. The resulting data structure will not have the same layout in memory as a bona fide 2D array, but it can be accessed via the same syntax as one.

  • Perform a dynamic allocation as shown in the question, and simulate a 2D array on top of that. It might be helpful in this case to write one or more macros to wrap the address / offset logic.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
-1

Use pointers to array for that:

void foo(size_t rows, size_t cols)
{
    int (*array)[cols] = malloc(rows * sizeof(*array));
    int (*array1)[rows][cols] = malloc(sizeof(*array));
}
0___________
  • 60,014
  • 4
  • 34
  • 74