1

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?

  • 2
    Write down the matrix on paper. Using pen and paper try to figure out the algorithm that steps through the matrix in the way you want. You might also want to attempt to solve it using indexes first. – Some programmer dude Apr 11 '22 at 08:30
  • 1
    On an unrelated note, remember that for any pointer or array `p` and index `i`, the expressions `*(p + i)` is *exactly* equal to `p[i]`. The latter (`p[i]`) is usually easier to read, write and understand, as well as less to write. – Some programmer dude Apr 11 '22 at 08:31
  • First try to make a simple program that show you the contents of the array from first line to list line and for each line all the columns. This will help you to understand how you can go through the array using pointers. When you understand this you can then start implementing your algorithm. – Ptit Xav Apr 11 '22 at 09:25
  • 1
    Is your question how to translate the Python `for` loops to C `for` loops? Maybe you should add some output to the Python loops to display the loop index and run it to see the sequence of index values. – Bodo Apr 11 '22 at 10:11
  • Maybe I am overthinking but the issues are twofold: 1 - array in C is a different structure than lists in python. I can't use append in C; 2 - the counters in the *for...loops*. I am unsure how to set them up. – Thadeu Freitas Filho Apr 12 '22 at 02:01
  • Well, I suppose issue #1 above is not a problem, really. I can just increase the counter every time I append an item to *new_array*. – Thadeu Freitas Filho Apr 12 '22 at 02:25

1 Answers1

1

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).

Bob__
  • 12,361
  • 3
  • 28
  • 42