Saltar al contenido
ES EN

Solved exercise: matrix rotate and shift commands in C

C exam exercise: read a matrix, apply circular column shifts and 90-degree rotations, and print it aligned with the product of every row and column.

Updated on

Exam Code C Programming fundamentals Exam level Tested code

Exam Code: Solved exercise: matrix rotate and shift commands in C
CS1 Introduction to Programming in C · Final examQuestion 3 · 2.5 points · 35 min

A light panel is modelled as an integer matrix with R rows and C columns, where 1 ≤ R, C ≤ 10 and every value lies in [-50, 50]. Write a C program that reads the matrix, applies a sequence of commands to it and prints the final result as an aligned table.

Input (standard input). The first line holds R and C. Then come R lines with C integers each. After them comes an integer Q (0 ≤ Q ≤ 20) followed by Q commands, one per line. There are two kinds of command.

S k: shift the columns circularly k positions to the right, with -1000 ≤ k ≤ 1000. A negative value shifts to the left. An element that leaves one end of a row re-enters at the other end.

R: rotate the matrix 90 degrees clockwise. A matrix of size R×C becomes C×R.

Output. First a line Matrix RxC: with the final dimensions. Then one line per row. Each element is right-aligned in a field whose width equals the number of characters of the longest element in the whole matrix, counting the minus sign. Elements are separated by exactly one space, and lines have no trailing spaces.

Next comes the line Rows: followed, for each row in order, by a space and the product of its elements. Finally, the line Columns: gives the product of each column in the same format.

You may assume the commands follow the format. If the dimensions are out of range or any initial value is missing, print Invalid input. Structure your code in functions: one to read, one per command and one to print.

Sample input

3 4
2 -1 3 4
5 0 -6 1
-3 7 2 10
3
S 1
R
S -1

Expected output

Matrix 4x3:
 1  4 10
 5  2 -3
 0 -1  7
-6  3  2
Rows: 40 -30 0 -36
Columns: 0 -24 -420
Reading dimensions, elements and commands, checking the value returned by scanf
0.5
Circular column shift correct for negative, zero and larger-than-width k
0.75
Clockwise 90-degree rotation that swaps the dimensions of non-square matrices
0.5
Output with a computed column width, and row and column products without overflow
0.75

Hints

Hint 1 · How do I store a matrix whose shape changes?

Always declare a 10×10 array and keep separately how many rows and columns are in use. Bundling the three in a struct lets you hand the whole matrix to each function through a single pointer. After a rotation you only need to swap the two dimensions.

Hint 2 · What do I do with k = -998 or k = 1000?

Shifting by C positions leaves a row unchanged, so only the remainder of k divided by C matters. In C, % with a negative left operand yields a negative remainder. Find an expression that maps any k into [0, C-1]. Write the shifted row into a temporary array before copying it back.

Hint 3 · Where does element (i, j) go when rotating?

In a clockwise rotation, original column j becomes new row j, read from bottom to top. Work out the destination formula from a 2×3 matrix drawn on paper. Write the result into a matrix that is not the original one.

Solution

Explained solution

The solution defines a Matrix type holding the dimensions in use (rows, cols) and a fixed array v[10][10]. Every function receives a pointer to that struct, so the functions that modify the matrix change the caller's copy and not a local one. If that distinction is still shaky, review pass by value and by reference in C before the exam.

The program runs in four phases: read, execute commands, compute the column width, and print the table with its products. Each phase lives in its own function, which is exactly what the statement asks for and what the marker will look for.

#include <stdio.h>

#define MAXD 10

typedef struct {
    int rows;
    int cols;
    int v[MAXD][MAXD];
} Matrix;

static int read_matrix(Matrix *m)
{
    if (scanf("%d %d", &m->rows, &m->cols) != 2) return 0;
    if (m->rows < 1 || m->rows > MAXD || m->cols < 1 || m->cols > MAXD) return 0;
    for (int i = 0; i < m->rows; i++)
        for (int j = 0; j < m->cols; j++)
            if (scanf("%d", &m->v[i][j]) != 1) return 0;
    return 1;
}

/* Circular shift of the columns k positions to the right (k < 0: left). */
static void shift_columns(Matrix *m, int k)
{
    int d = ((k % m->cols) + m->cols) % m->cols;
    if (d == 0) return;
    int row[MAXD];
    for (int i = 0; i < m->rows; i++) {
        for (int j = 0; j < m->cols; j++)
            row[(j + d) % m->cols] = m->v[i][j];
        for (int j = 0; j < m->cols; j++)
            m->v[i][j] = row[j];
    }
}

/* Clockwise 90-degree rotation: (i, j) moves to (j, rows-1-i). */
static void rotate_cw(Matrix *m)
{
    Matrix r = {0};
    r.rows = m->cols;
    r.cols = m->rows;
    for (int i = 0; i < m->rows; i++)
        for (int j = 0; j < m->cols; j++)
            r.v[j][m->rows - 1 - i] = m->v[i][j];
    *m = r;
}

static int width_of(int x)
{
    int n = (x <= 0) ? 1 : 0;
    while (x != 0) {
        n++;
        x /= 10;
    }
    return n;
}

static void print_matrix(const Matrix *m)
{
    int w = 1;
    for (int i = 0; i < m->rows; i++)
        for (int j = 0; j < m->cols; j++) {
            int a = width_of(m->v[i][j]);
            if (a > w) w = a;
        }

    printf("Matrix %dx%d:\n", m->rows, m->cols);
    for (int i = 0; i < m->rows; i++) {
        for (int j = 0; j < m->cols; j++) {
            if (j > 0) putchar(' ');
            printf("%*d", w, m->v[i][j]);
        }
        putchar('\n');
    }

    printf("Rows:");
    for (int i = 0; i < m->rows; i++) {
        long long p = 1;
        for (int j = 0; j < m->cols; j++)
            p *= m->v[i][j];
        printf(" %lld", p);
    }
    putchar('\n');

    printf("Columns:");
    for (int j = 0; j < m->cols; j++) {
        long long p = 1;
        for (int i = 0; i < m->rows; i++)
            p *= m->v[i][j];
        printf(" %lld", p);
    }
    putchar('\n');
}

int main(void)
{
    Matrix m = {0};
    int q;

    if (!read_matrix(&m) || scanf("%d", &q) != 1 || q < 0) {
        printf("Invalid input\n");
        return 0;
    }

    for (int t = 0; t < q; t++) {
        char op;
        if (scanf(" %c", &op) != 1) break;
        if (op == 'S') {
            int k;
            if (scanf("%d", &k) != 1) break;
            shift_columns(&m, k);
        } else if (op == 'R') {
            rotate_cw(&m);
        }
    }

    print_matrix(&m);
    return 0;
}

Reading. read_matrix checks that every scanf call returns the number of items requested and that both dimensions lie in [1, 10]. On any failure it returns 0 and main prints Invalid input. Checking the return value is not decoration: without it, truncated input would leave cells holding garbage, and some toolchains warn when the result is ignored.

Reading commands. In main, the format " %c" starts with a space. That space skips the newline left by the previous line. Without it, op would receive '\n' and the real command letter would be read as the next command, or lost. This is one of the most common exam bugs with mixed numeric and character input.

Shift. In shift_columns, the expression ((k % m->cols) + m->cols) % m->cols maps any k into [0, cols-1]. With 3 columns, -998 % 3 is -2 in C; adding 3 gives 1, and the final modulo keeps it at 1. The element in column j goes to position (j + d) % cols of the temporary array row, which is then copied back. Writing directly into the matrix would overwrite values that have not moved yet.

The large shifts test exercises that normalisation. S 1000 and S -998 are each equivalent to one position to the right, so the row 1 2 3 ends as 2 3 1. The three by two rotated test includes S 3 on a three-column matrix: d is 0 and the function returns immediately.

Rotation. rotate_cw builds a new matrix r with swapped dimensions and stores each v[i][j] at r.v[j][rows-1-i]. Check it on the 2×3 matrix with rows 1 2 3 and 4 5 6: the 1 at (0,0) moves to (0,1), and the new first row is 4 1. Finally *m = r copies the whole struct, array included, because C allows structure assignment. The four rotations test confirms that four turns restore the original matrix.

Formatted output. width_of counts the characters of an integer. It starts at 1 when the value is negative (the sign) or zero (the digit 0), then adds one per division by 10. print_matrix takes the maximum w and uses %*d, which reads the field width from an argument. In the example the longest elements take two characters (10, -3, -6), so the 1 is preceded by a space. In four rotations the width is 3 because of -10.

Products. They are accumulated in long long. A row of ten values of magnitude 50 gives 5010, close to 1017 and far above INT_MAX. The ten-column limit test prints exactly 97656250000000000; an int would have overflowed, which for signed integers is undefined behaviour in C.

Code and tests on GitLab

Test cases

CaseInputExpected outputActual outputResult
statement example3 4 2 -1 3 4 5 0 -6 1 -3 7 2 10 3 S 1 R S -1Matrix 4x3: 1 4 10 5 2 -3 0 -1 7 -6 3 2 Rows: 40 -30 0 -36 Columns: 0 -24 -420Matrix 4x3: 1 4 10 5 2 -3 0 -1 7 -6 3 2 Rows: 40 -30 0 -36 Columns: 0 -24 -420OK
single element, no commands1 1 -7 0Matrix 1x1: -7 Rows: -7 Columns: -7Matrix 1x1: -7 Rows: -7 Columns: -7OK
large shifts2 3 1 2 3 4 5 6 2 S 1000 S -998Matrix 2x3: 2 3 1 5 6 4 Rows: 6 120 Columns: 10 18 4Matrix 2x3: 2 3 1 5 6 4 Rows: 6 120 Columns: 10 18 4OK
four rotations2 3 -10 20 0 3 -4 5 4 R R R RMatrix 2x3: -10 20 0 3 -4 5 Rows: 0 -60 Columns: -30 -80 0Matrix 2x3: -10 20 0 3 -4 5 Rows: 0 -60 Columns: -30 -80 0OK
ten-column limit1 10 50 -50 50 50 -50 50 50 50 50 50 1 RMatrix 10x1: 50 -50 50 50 -50 50 50 50 50 50 Rows: 50 -50 50 50 -50 50 50 50 50 50 Columns: 97656250000000000Matrix 10x1: 50 -50 50 50 -50 50 50 50 50 50 Rows: 50 -50 50 50 -50 50 50 50 50 50 Columns: 97656250000000000OK
three by two rotated3 2 1 2 3 4 5 6 2 R S 3Matrix 2x3: 5 3 1 6 4 2 Rows: 15 48 Columns: 30 12 2Matrix 2x3: 5 3 1 6 4 2 Rows: 15 48 Columns: 30 12 2OK

Actual outputs: code compiled with gcc 14.4.0 (C17) and run in an isolated container on 26 October 2026.

Complexity

Each S command walks the matrix twice (writing into the temporary row and copying back), and each R command walks it once plus the copy of the struct. Both cost O(R·C). With Q commands the total is O(Q·R·C), plus O(R·C) for reading, computing the width and the products. Under the stated limits that is a few thousand operations at most.

Memory is a fixed array of 100 integers, a temporary copy of the same size inside rotate_cw and a 10-integer array inside shift_columns: O(MAXD²), constant with respect to the input. Dynamic memory is unnecessary because the statement bounds the maximum size.

Common mistakes

  • Normalising the shift with plain k % cols: for negative k the remainder is negative and the index (j + d) % cols falls outside the array.
  • Shifting inside the row itself without a temporary array. The first write overwrites a value that has not moved yet, and the row ends up with duplicates.
  • Rotating in place with a swap loop designed for square matrices. When rows differ from columns, the destination (j, rows-1-i) lies outside the original shape and data get mixed.
  • Forgetting to swap rows and cols after rotating, so every later loop walks the wrong shape.
  • Reading the command with "%c" without a leading space, which reads the newline instead of the letter.
  • Computing products in int, or hard-coding the width with a magic %4d instead of deriving it from the data.

Variants

Add command L: anticlockwise rotation

Write another function shaped like rotate_cw with the destination changed to r.v[cols-1-j][i] = v[i][j]. Calling rotate_cw three times also works, but it triples the cost; say so if the examiner asks about efficiency.

Vertical row shift

A command V k that moves rows downwards uses the same normalisation, now modulo rows. Since whole rows move, the temporary can be a full matrix, or you can copy row by row in a loop. Another option is rotate, shift columns, and undo the rotation, but then you must think carefully about the direction of the shift.

No size limit

If the statement did not bound R and C, the struct would hold a pointer and the storage would come from malloc. The rotation would allocate a new block and free the old one. The technique is covered in dynamic matrices with malloc and free in C.

On the syllabus

Multidimensional arrays and their relation to pointers appear in Unit III of the syllabus of Algoritmos y Programación I (95.11) at the Universidad de Buenos Aires. This exercise practises that material: fixed-size arrays with variable logical dimensions, index-based traversals and passing structures through pointers.

At a later stage, the syllabus of CC3301 Programación de Software de Sistemas at the Universidad de Chile covers C programming against the Linux API. For a course of that kind, robust input with scanf and confident array handling like the one practised here are prerequisites.

Article generated with AI.larebelion

Byline

· Chief editor · English edition · London

“The costly bug here is not the loop. It is a negative modulo or an int that overflows without a word.”

Comentarios