0

I want to dynamically create a 2D array like so:

+------+------+
|  i   |   j  |
+------+------+  // 2 cols and N rows (N unknown)
| 2    |  2048|
+------+------+
| 3    |  3072|
+------+------+
| 5    |   256|
+------+------+
| ...  |  ....|
+------+------+

And this is a pseudo code on how I'm going to fill the array:

int N = 4096;
void foo(int N)
{
  for (i =0;i<N;i++)
  {
    int j = index_computation(i);
    if(j>i)
    {
      //alocate array row
      A[i][0] = i;
      A[i][1] = j;
    }  
  }  
}

I'm a little bit confused about how to dynamically allocate it.

A.nechi
  • 197
  • 3
  • 17
  • How is your array `A` declared? Also, expressions such as `A[i][0] = i` do not "allocate" anything. It assigns a value to space that's already been allocated. For dynamic allocation, you need to use `malloc`. – lurker Jul 10 '17 at 15:06
  • take a look at `malloc` https://linux.die.net/man/3/malloc – yano Jul 10 '17 at 15:07
  • If `N` is unknown, then how are you going to allocate it at all? Do you mean *variable*? – meowgoesthedog Jul 10 '17 at 15:08
  • Perhaps this is what you're looking for? [Using malloc for allocation of multi-dimensional arrays with different row length](https://stackoverflow.com/questions/1970698/using-malloc-for-allocation-of-multi-dimensional-arrays-with-different-row-lengt) – Miket25 Jul 10 '17 at 15:09
  • No, No `A[i][0] = i` I know that this expression is only used to assign a value to the array space A[i][j]... My question is that how am I going to allocate the array knowing that I only know that it has 2 cols? – A.nechi Jul 10 '17 at 15:10
  • @A.nechi, check out those links above. They're very similar to the thing you need. – Miket25 Jul 10 '17 at 15:11
  • You can do this with `#define COLS 2`, and later `int (*A)[COLS] = malloc(sizeof *A * rows);`. This gives array subscripting access, uses contiguous storage, and does not require VLAs. Also deallocation is as simple as `free(A);`, in contrast to jagged arrays. – ad absurdum Jul 10 '17 at 15:52

2 Answers2

5

Since a 2D array is an array of arrays, you can think of it as a 1D array, where every row of the 2D array follows each other:

int array2D[4][2] = { { 11, 12 }, { 21, 22 }, { 31, 32 }, { 41, 42 } };
int array1D[8] = { 11, 12, 21, 22, 31, 32, 41, 42 };

Why is it good? Because you don't have to mind do you allocate a 1D or a 2D array, the key is how you index it. Here is my example:

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

#define COL_NUM 2

int main() {
    int rows = 5;

    // allocate a 1D array, with size: rows * columns
    int* array = (int*)calloc(rows * COL_NUM, sizeof(int)); 

    // fill the array with some values
    int i, j = 0;
    for(i = 0; i < rows; ++i) {
        array[i * COL_NUM + j] = 1; // index elements as if it were 2D array
        j = (j + 1) % COL_NUM;
    }

    // print the quasi 2D array
    for(i = 0; i < rows; ++i) {
        for(j = 0; j < COL_NUM; ++j)
            printf("%d ", array[i * COL_NUM + j]);
        printf("\n");
    }

   free(array);
   return 0;
}

As in the example above, indexing a 1D array as if it were 2D array explained by the following:

#define NUMBER_OF_COLUMNS 2
int row = 2, column = 0;

array2D[row][column] = 5;
array1D[row * NUMBER_OF_COLUMNS + column] = 5;

As the comments below warn, indexing a 1D array as if it were a 2D array (with the method shown above) is safe, but the opposite is undefined behavior. My previous statement:

Since a 2D array is an array of arrays, you can think of it as a 1D array

shouldn't be understood as you can indexing a 2D array as if it were a 1D array.

Akira
  • 4,385
  • 3
  • 24
  • 46
  • 1
    You have to be careful with: "you can think of it as a 1D array"; note that, e.g., it is UB to do `int *ptr = &array2d[0][0];`, then `int val = *(ptr + 3)`, which is within the bounds of the 2d array, but out of bounds of the first row. [See this question](https://stackoverflow.com/questions/6290956/one-dimensional-access-to-a-multidimensional-array-well-defined-c) and [my recent question](https://stackoverflow.com/questions/44987543/is-it-ub-to-access-an-element-one-past-the-end-of-a-row-of-a-2d-array) for some discussions. – ad absurdum Jul 10 '17 at 16:25
  • 1
    @DavidBowling, thanks for the warning, I added it to my answer. – Akira Jul 10 '17 at 22:25
2

The best approach is to forget the 2D array syntax, and simply create a buffer with 2 * Nrows entries. Then access via

 A[i*2+0] = i;
 A[i*2+1] = j;

Of course you must also ensure that A is big enough.

 A = realloc(A, N * 2 * sizeof *A);

will achieve this, call whenever you get a new bound for N.

Malcolm McLean
  • 6,258
  • 1
  • 17
  • 18