defining a 2D array with malloc and modifying it

Solution 1:

10x30:

int(*array)[30] = malloc((sizeof *array) * 10);

15x20:

int(*array)[20] = malloc((sizeof *array) * 15);

Resizing to 20x25:

int(*array2)[25] = realloc(array, (sizeof *array2) * 20);

The outer dimension (10, 15, 20) can be determined at runtime, because it's not need as part of index calculations by the compiler. The inner dimension (30, 20, 25) needs to be known at compile time. Hope it helps.

Note that unlike the array-of-pointer solutions, this one can be handled as a single block of memory, because it allocates everything in a single chunk of memory like a real declared array:

memcpy(somewhere, array2, sizeof(int) * 20 * 25); // (sizeof *array2) * 20

It ultimately depends on your usecase, though.


Since some people have difficulties understanding the actions taken by an index operation to array, let's what Clang gives us for an index expression in the following code

int main() {
  int(*array)[10] = malloc((sizeof *array) * 5);
  array[4][9] = 0;

  int(*array1)[10][5] = malloc((sizeof *array1) * 20);
  array1[19][9][4] = 0;
}

It's a nice compiler, which can print its AST in an easily readable manner

  // array[4][9] = 0;
  (BinaryOperator 0xba62cc0 <line:5:3, col:17> 'int' '='
    (ArraySubscriptExpr 0xba62c80 <col:3, col:13> 'int'
      (ImplicitCastExpr 0xba62c60 <col:3, col:10> 'int *' <ArrayToPointerDecay>
        (ArraySubscriptExpr 0xba62c20 <col:3, col:10> 'int [10]'
          (DeclRefExpr 0xba62bdc <col:3> 'int (*)[10]' Var='array' 0xba62a00)
          (IntegerLiteral 0xba62c00 <col:9> 'int' 4)))
      (IntegerLiteral 0xba62c40 <col:12> 'int' 9))
    (IntegerLiteral 0xba62ca0 <col:17> 'int' 0))

  // array1[19][9][4] = 0;
  (BinaryOperator 0xba630b8 <line:8:3, col:22> 'int' '='
    (ArraySubscriptExpr 0xba63078 <col:3, col:18> 'int'
      (ImplicitCastExpr 0xba63058 <col:3, col:15> 'int *' <ArrayToPointerDecay>
        (ArraySubscriptExpr 0xba63018 <col:3, col:15> 'int [5]'
          (ImplicitCastExpr 0xba62ff8 <col:3, col:12> 'int (*)[5]' <ArrayToPointerDecay>
            (ArraySubscriptExpr 0xba62fa0 <col:3, col:12> 'int [10][5]'
              (DeclRefExpr 0xba62f5c <col:3> 'int (*)[10][5]' Var='array1' 0xba62db0)
              (IntegerLiteral 0xba62f80 <col:10> 'int' 19)))
          (IntegerLiteral 0xba62fc0 <col:14> 'int' 9)))
      (IntegerLiteral 0xba63038 <col:17> 'int' 4))
    (IntegerLiteral 0xba63098 <col:22> 'int' 0)))

Note that each array subscript expression takes a pointer, adds the value of the index, and yields the addressed element. If that subelement is an array, it is decayed to a pointer to its first element. This is really not actually different than the steps done for a declared array

int main() {
  int array[5][10] = { };
  array[4][9] = 1;
}

Yields a very similar AST, with just the most inner expression first being decayed to a pointer to its first element

  // array[4][9] = 1;
  (BinaryOperator 0xbf9f7e8 <line:5:3, col:17> 'int' '='
    (ArraySubscriptExpr 0xbf9f7a8 <col:3, col:13> 'int'
      (ImplicitCastExpr 0xbf9f788 <col:3, col:10> 'int *' <ArrayToPointerDecay>
        (ArraySubscriptExpr 0xbf9f748 <col:3, col:10> 'int [10]'
          (ImplicitCastExpr 0xbf9f728 <col:3> 'int (*)[10]' <ArrayToPointerDecay>
            (DeclRefExpr 0xbf9f6cc <col:3> 'int [5][10]' Var='array' 0xbfa81f0))
          (IntegerLiteral 0xbf9f6f0 <col:9> 'int' 4)))
      (IntegerLiteral 0xbf9f768 <col:12> 'int' 9))
    (IntegerLiteral 0xbf9f7c8 <col:17> 'int' 1)))

Solution 2:

While malloc() does not directly support multi-dimensional arrays, there are workarounds, such as:

int rows = 10;
int cols = 30;
int *array = malloc(rows * cols * sizeof(int));

// Element (5,6)
int x = 5;
int y = 6;
int element = array [ x * cols + y ];

While this isn't directly a 2D array, it works, and in my opinion it's the simplest. But if you want to use the [][] syntax instead, you would have to make pointers to pointers, for instance:

int rows = 10;
int cols = 30;
// Rows
int **array = malloc(rows * sizeof(int*));
// Cols
int i;
for(i = 0; i < rows; i++)
  array[i] = malloc(cols * sizeof(int));

// Element (5,6)
int x = 5;
int y = 6;
int element = array[x][y];

Solution 3:

// first allocate the 20 rows, that contain pointers to int 
// (if the matrix contains int type values)
int **a = malloc(20 * sizeof(int *));

// now loop for each row and allocate data for the actual values
int i;
for(i = 0; i < 20; i++) {
    a[i] = malloc(10 * sizeof(int));
}

For increasing the size of the matrix you can use realloc although it would probably be easier to regenerate the matrix of different size and copy the values over.