Search code examples
callocation

Checking neighboring cells in a dynamically allocated 2D array


I am working on a project in which I need to check neighboring cells of a specific cell in a dynamically allocated 2D char array. Basically, If certain neighboring cells are 'X' for example, then the current cell you are on becomes '-'. To allocate the 2D array, I used a single malloc call:

char *array = (char *)malloc(numRows * numCols * sizeof(char));

To access an element while using a double for loop, I use this:

for (int i = 0; i <= getNumRows(); i++)
{
    for (int j = 0; j < getNumCols(); j++)
    {
        printf("%c ", **(array + i * getNumCols() + j));
    }
    printf("\n");
}

How would I access and view the neighboring cells of the current element?


Solution

  • The code posted to display the matrix has problems:

    • the outer loop should stop when i == getNumRows() and
    • the printf argument should use a single * dereferencing operator

    Here is a modified version:

    for (int i = 0; i < getNumRows(); i++) {
        for (int j = 0; j < getNumCols(); j++) {
            printf("%c ", *(array + i * getNumCols() + j));
        }
        printf("\n");
    }
    

    Which can also be rewritten to avoid recomputing the matrix sizes repeatedly:

    for (int i = 0, row = getNumRows(), cols = getNumCols(); i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%c ", array[i * cols + j]);
        }
        printf("\n");
    }
    

    Accessing the neighbouring cells of cell r,c depends on how you deal with boundaries:

    • if boundaries should not be crossed, you must test if r and/or c are on a boundary to produce between 3 and 8 neighbours.
    • if boundaries wrap as a torus, you can just compute r+/-1 % rows and c+/-1 % cols to always produce 8 neighbours.

    To simplify the first case, you can allocate the matrix with 2 extra columns and rows, with char *array = malloc(sizeof(char) * (numRows + 1) * (numCols + 2)); and use the inner space (active area) this way:

    for (int i = 1; i <= getNumRows(); i++) {
        for (int j = 1; j <= getNumCols(); j++) {
            printf("%c ", *(array + i * getNumCols() + j));
        }
        printf("\n");
    }
    

    If you initalize the boundary rows and columns in the matrix as ' ', you can always access the 8 cells at r+/-1, c+/-1 and check for 'X' without special casing the boundary rows of the active part.

    Accessing these neighbouring cells can be done according to the implementation choices:

     int rows = getNumRows(), cols = getNumCols();
     char *cellp = array + r * cols + c;
    
     // using extra rows and columns
     char top_1 = cellp[-cols - 1];
     char top_2 = cellp[-cols];
     char top_3 = cellp[-cols + 1];
     char mid_1 = cellp[-1];
     char mid_2 = cellp[+1];
     char bot_1 = cellp[+cols - 1];
     char bot_2 = cellp[+cols];
     char bot_3 = cellp[+cols + 1];
    
     // using torus-like wrapping
     char top_1 = array[(r + rows - 1) % rows * cols + (c + cols - 1) % cols];
     char top_2 = array[(r + rows - 1) % rows * cols + c];
     char top_3 = array[(r + rows - 1) % rows * cols + (c + 1) % cols];
     char mid_1 = array[r * cols + (c + cols - 1) % cols];
     char mid_2 = array[r * cols + (c + 1)];
     char bot_1 = array[(r + 1) % rows * cols + (c + cols - 1) % cols];
     char bot_2 = array[(r + 1) % rows * cols + c];
     char bot_3 = array[(r + 1) % rows * cols + (c + 1) % cols];
    
     // using tests
     char top_1 = (r == 0        || c == 0       ) ? 0 : cellp[-cols - 1];
     char top_2 = (r == 0                        ) ? 0 : cellp[-cols];
     char top_3 = (r == 0        || c == cols - 1) ? 0 : cellp[-cols + 1];
     char mid_1 = (                 c == 0       ) ? 0 : cellp[-1];
     char mid_2 = (                 c == cols - 1) ? 0 : cellp[+1];
     char bot_1 = (r == rows - 1 || c == 0       ) ? 0 : cellp[+cols - 1];
     char bot_2 = (r == rows - 1                 ) ? 0 : cellp[+cols];
     char bot_3 = (r == rows - 1 || c == cols - 1) ? 0 : cellp[+cols + 1];