1

currently I am trying to resize a 2D Array in C using this code snippet

array = (int**) realloc(array, s * 2 * sizeof(int));

Where s is the size of the array in rows and colums. However, when trying to access the new areas of the array like this,

array[3][0] = x;

I only get a segfault. The old areas of the array work fine. How can I solve this issue?

Gleydar
  • 125
  • 2
  • 11
  • are you _sure_ that `array` is an _array_? – Sourav Ghosh Aug 29 '16 at 14:41
  • 1
    **Pointers are not arrays**. Pointer to pointer doesn't mean array of arrays. – haccks Aug 29 '16 at 14:41
  • 2
    Please construct a [minimal test-case](http://stackoverflow.com/help/mcve). – Oliver Charlesworth Aug 29 '16 at 14:42
  • How did you declare `array` and how did you initially allocate it? – John Bode Aug 29 '16 at 14:42
  • 1
    Assuming that you declared `array` correctly and that you fixed every warning from your compiler there is a fundamental mistake using `realloc()`. These functions all, return `NULL` on failure, in that case you loose reference to the orignal pointer causing a memory leak. Use a temporary variable, and depending on the value of `s` you might be asking for an unavailable ammount of memory, so check that `arary` is not `NULL` before `array[3][0] = x`, last but not least don't cast the return value of `malloc()`. – Iharob Al Asimi Aug 29 '16 at 14:42
  • See section 6 of the [c-faq](http://c-faq.com/). – pmg Aug 29 '16 at 14:42
  • For resizable "2D arrays" (an array of pointers, like you declare, which each point to their own row, which are allocated 1D arrays), you'll typically need the allocation you show for the pointers, and then an iteration over the pointers in order to allocate the row each pointer is to point to. Right now you only have a 1D array of pointers (the `int **` not withstanding). – Peter - Reinstate Monica Aug 29 '16 at 14:45

2 Answers2

16

Assuming you declared array as

int **array;

and allocated as

array = malloc( sizeof *array * ROWS );
if ( array )
{
  for ( size_t i = 0; i < ROWS; i++ )
    array[i] = malloc( sizeof *array[i] * COLS );
}

The structure you wind up with looks something like:

       +---+        +---+                  +---+
array: |   | -----> |   | array[0] ------> |   | array[0][0]
       +---+        +---+                  +---+
        ...         |   | array[1] ---+    |   | array[0][1]
                    +---+             |    +---+
                     ...              |    |   | array[0][2]
                                      |    +---+
                                      |     ...
                                      |    
                                      |    +---+
                                      +--> |   | array[1][0]
                                           +---+
                                           |   | array[1][1]
                                           +---+
                                           |   | array[1][2]
                                           +---+
                                            ...

If you want to increase the number of rows in the array but leave the column sizes the same, you'd do something like

int **tmp = realloc( array, sizeof *array * (ROWS + add_rows) );
if ( tmp )
{
  array = tmp;
  for ( size_t i = 0; i < add_rows; i++ )
  {
     array[ROWS + i] = malloc( sizeof *array[ROWS + i] * COLS );
  }
}

If you want to leave the number of rows the same but increase the number of columns in each row, you would do something like

for ( size_t i = 0; i < ROWS; i++ )
{
  int *tmp = realloc( array[i], sizeof *array[i] * (COLS + add_cols) );
  if ( tmp )
  {
    array[i] = tmp;
  }
}

If you want to reduce the number of rows in the array, you will need to free the affected rows first:

for ( size_t i = 1; i <= del_rows; i++ )
  free( array[ROWS - i] );

int *tmp = realloc( array, ROWS - del_rows );
if ( tmp )
  array = tmp;

If you want to reduce the number of columns:

for ( size_t i = 0; i < ROWS: i++ )
{
  int *tmp = realloc( array[i], sizeof *array[i] * (COLS - del_cols) );
  if ( tmp )
    array[i] = tmp;
}

From there, you should be able to figure out any combinations you need. I strongly recommend doing only one dimension at a time (that is, if you want to increase the number of rows and columns, do the rows first, then do the columns).

You always want to assign the result of realloc to a temporary variable; if realloc cannot satisfy the request, it will return NULL, and if you assign it back to the original variable, you will lose your only reference to the memory that was previously allocated, leading to a memory leak.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Here is an example of a function to resize a 2D array in C:

int** ResizeGrid(int** A, uint64_t rows, uint64_t cols, uint64_t newRow, uint64_t newCol)
{
  // If old size is same as new size, return the same grid
  // if (newRow == rows && newCol == cols) {
  //   return A;
  // }

  // If new size is smaller than old size, free the extra memory
  if (rows > newRow) {
    for (uint64_t i = newRow; i < rows; i++) {
      free(A[i]);
    }
    return A;
  }

  A = (int**)realloc(A, sizeof(int*) * newRow);
  // Check if realloc fails
  if (A == NULL) {
    return NULL;
  }

  for (uint64_t i = 0; i < newRow; i++) {
    // Reallocate memory only on already allocated rows
    if (rows > i) {
      A[i] = (int*)realloc(A[i], sizeof(int) * newCol);
    } else {
      A[i] = (int*)malloc(sizeof(int) * newCol);
    }
    // Check if realloc/malloc fails
    if (A[i] == NULL) {
      // Free all the rows that have been allocated
      for (uint64_t j = 0; j < i; j++) {
        free(A[j]);
      }
      free(A);

      return NULL;
    }
  }
  return A;
}

An example implementation of the function

Bensuperpc
  • 1,275
  • 1
  • 14
  • 21