Home > Enterprise >  How to traverse a matrix in a spiral fashion in C using pointers?
How to traverse a matrix in a spiral fashion in C using pointers?

Time:04-22

This is the algorithm for traversing a matrix in spiral fashion and printing the traversal as an array in Python:

def spiralTraverse(array):
    result = []
    startRow, endRow = 0, len(array) - 1
    startCol, endCol = 0, len(array[0]) - 1
    
    while startRow <= endRow and startCol <= endCol:
        for col in range(startCol, endCol   1):
            result.append(array[startRow][col])
            
        for row in range(startRow   1, endRow   1):
            result.append(array[row][endCol])
            
        for col in reversed(range(startCol, endCol)):
            if startRow == endRow:
                break
            result.append(array[endRow][col])
            
        for row in reversed(range(startRow   1, endRow)):
            if startCol == endCol:
                break
            result.append(array[row][startCol])
            
        startRow  = 1
        endRow -= 1
        startCol  = 1
        endCol -= 1
        
    return result

So if sample input is

array = [[1, 2, 3, 4],[12, 13, 14, 5],[11, 16, 15, 6],[10, 9, 8, 7]]

Output will be

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

I am trying to translate this into C with pointers but the function fails to print the final array. The file compiles but with warnings related to the multidimensional array as argument in spiralTraverse(). I call the spiralTraverse function from main() as follows: spiralTraverse(*array[r], r, c), where r=rows and c=cols are number of rows and columns respectively.

This is what I did:

void spiralTraverse(int *vector[], int rows, int cols)
{
    int i, indx_col, indx_row;
    int indx_array = 0;
    int startRow = 0;
    int endRow = rows-1;
    int startCol = 0;
    int endCol = cols-1;
    int new_array[rows*cols];

    
        while ((startRow <= endRow) && (startCol <= endCol))
        {
            for (indx_col=startCol;indx_col<endCol 1;indx_col  )
                new_array[indx_array  ] = *(*(vector startRow) indx_col);
            
            for (indx_row=startRow 1;indx_row<endRow 1;indx_row  )
                new_array[indx_array  ] = *(*(vector indx_row) endCol);

            for (indx_col=endCol;indx_col>startCol;indx_col--)
            {
                if (startRow == endRow)
                    break;
                new_array[indx_array  ] = *(*(vector endRow) indx_col);
            }
            for (indx_row=endRow;indx_row>startRow 1;indx_row--)
            {
                if (startCol == endCol)
                    break;
                new_array[indx_array  ] = *(*(vector indx_row) startCol);
            }
            startRow  ;
            endRow--;
            startCol  ;
            endCol--;
        }

        puts("");
        puts("The array below displays the elements in spiral order");
        for (i=0;i<(rows*cols);i  )
            printf("%d, ", new_array[i]);
        puts("");
    }
}

Why is the program failing to print my final one-dimensional array?

CodePudding user response:

Function argument

The file compiles but with warnings related to the multidimensional array as argument in spiralTraverse().

Please refer to those others Q&A for details about the proper way to allocate and pass multidimensional arrays as function parameters in C:

Correctly allocating multi-dimensional arrays
What's the point of VLA anyway?
How to pass a multidimensional array to a function in C and C

Given the array

int array[][4] = {
    { 1,  2,  3, 4},
    {12, 13, 14, 5},
    {11, 16, 15, 6},
    {10,  9,  8, 7}
};

The function signature could be one of those

// Declaring m as a Variable Length Array (since C99, optional from C11)
void spiral_traverse(int rows, int cols, int m[rows][cols]);

// or as a pointer to arrays of size 4
void spiral_traverse(int rows, int *m[4]);

Keep It Simple

The C implementation of the algorithm has an issue with the extemes of the loops, in particular the second and the third:

for ( indx_row = startRow   1; indx_row < endRow   1; indx_row   )
//                                      ^^^^^^^^^^^^
    /* ... */ = *(*(vector indx_row) endCol);

for ( indx_col = endCol; indx_col > startCol; indx_col-- )
//    ^^^^^^^^^^^^^^^^^
    /* ... */ = *(*(vector endRow) indx_col);

The last element visited by the first (well, second) loop is vector[endRow][endCol], which is the same one visited first by the other loop.

The following version produces the expected output.

Note that I changed the extremes of the loops.

#include <stdio.h>

void spiral_traverse(int rows, int cols, int m[rows][cols]);

int main(void)
{
    int array[][4] = {
        { 1,  2,  3, 4},
        {12, 13, 14, 5},
        {11, 16, 15, 6},
        {10,  9,  8, 7}
    };
    spiral_traverse(4, 4, array);
    spiral_traverse(3, 4, array); // Elements are stored row-major.
}

void spiral_traverse(int rows, int cols, int m[rows][cols])
{ // m is a Variable Length Array        ^^^^^^^^^^^^^^^^^
    int startRow = 0;
    int endRow = rows - 1;
    int startCol = 0;
    int endCol = cols - 1;
    int new_array[rows*cols]; // <-- Another VLA

    int i = 0;
    while ((startRow <= endRow) && (startCol <= endCol))
    {
        for (int col = startCol; col < endCol;   col,   i)
        { //                         ^              ^^^^^
            new_array[i] = m[startRow][col];
        } //               ^^^^^^^^^^^^^^^^      
        
        for (int row = startRow; row < endRow;   row,   i)
        { //         ^^^^^^^^^^      ^              ^^^^^        
            new_array[i] = m[row][endCol];
        } //               ^^^^^^^^^^^^^^

        for (int col = endCol; col > startCol; --col,   i)
        { //         ^^^^^^^^      ^                ^^^^^           
            new_array[i] = m[endRow][col];
        } //               ^^^^^^^^^^^^^^

        for (int row = endRow; row > startRow; --row,   i)
        { //         ^^^^^^^^      ^                ^^^^^
            new_array[i] = m[row][startCol];
        } //               ^^^^^^^^^^^^^^^^

        startRow  ;
        endRow--;
        startCol  ;
        endCol--;
    }

    puts("\nThe array below displays the elements in spiral order");
    for (i=0;i<(rows*cols);i  )
        printf("%d, ", new_array[i]);
    putchar('\n');
}

Of course, if the goal is only to print the elements, you don't really need to copy all of them into another array. Also, introducing a function pointer parameter, the function could become more generic (see e.g. here).

  • Related