Gleydar
Gleydar

Reputation: 125

Resizing 2D Arrays in C

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?

Upvotes: 1

Views: 9936

Answers (2)

Bensuperpc
Bensuperpc

Reputation: 1405

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

Upvotes: 0

John Bode
John Bode

Reputation: 123458

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.

Upvotes: 16

Related Questions