Updated on
Exam Code C Programming fundamentals Exam level Tested code
Solved C exam on matrices: row and column sums, trace, antidiagonal, symmetry check and transpose, with graded hints and a step-by-step trace.

A farming cooperative divides each field into a grid of N×N sectors. Each sector has a sensor that records the daily change in soil moisture as an integer. The value is positive if the sector gained moisture and negative if it lost moisture. The agronomist needs a report that summarises the grid by rows, by columns and along its two diagonals. She also wants to know whether the readings are symmetric about the main diagonal. Finally, she wants to see the transposed grid, because the irrigation plan was drawn with the axes swapped.
Input. Standard input first contains an integer N, followed by N·N integers given row by row. The first N values form row 0, the next N form row 1, and so on. The numbers may be separated by spaces, newlines or any mix of both. Every grid value lies between -1000 and 1000, and the largest allowed order is 10.
Errors. If N cannot be read (for example, because the input is empty), or if N is not between 1 and 10, the program prints the line Invalid N and stops without reading anything else. If N is valid but the input ends before all N·N values have been read, it prints the line Incomplete data and stops. In both cases nothing else is printed.
Output. If the input is valid, the output contains these lines in this order. First comes Rows: followed by the N row sums. Next comes Columns: followed by the N column sums. Then Trace: T, where T is the sum of the elements m[i][i]. Then Antidiagonal: A, where A is the sum of the elements m[i][N-1-i]. Then Symmetric: YES or Symmetric: NO. Finally comes the line Transpose:, followed by N lines holding the rows of the transposed matrix.
Exact format. On the Rows: and Columns: lines, every value is preceded by exactly one space. This includes the first value, so the space separates it from the colon. On the rows of the transpose, values are separated by a single space, with no space at the start or the end. Every line ends with a newline.
Requirements. Structure the program as functions and use no global variables. Write one function to read the matrix, one for the sum of a row, one for the sum of a column, one for the trace and one for the antidiagonal. Add one function that builds the transpose in a second matrix, and one that decides whether the matrix is symmetric. The sample case shown with this statement is a non-symmetric grid of order 3. Work out its report by hand before you write any code, then compare your result with the output shown next to it.
Sample input
3
5 -2 7
0 4 1
3 6 -1Expected output
Rows: 10 5 8
Columns: 8 8 7
Trace: 8
Antidiagonal: 14
Symmetric: NO
Transpose:
5 0 3
-2 4 6
7 1 -1- Reads N and the matrix, checks the return value of scanf, and prints both error messages exactly as specified
- 0.5
- Correct row and column sums, each computed in its own function with the accumulator reset
- 0.75
- Trace and antidiagonal computed with a single loop each and correct indices
- 0.5
- Transpose built in a second matrix, and a symmetry check that stops at the first mismatch
- 0.5
- Exact output format: spaces, line order and line breaks
- 0.25
Hints
Hint 1 · What relation do the indices of each diagonal satisfy?
On the main diagonal the row and the column are equal (i == j). On the antidiagonal they add up to N-1, so the column is N-1-i. One loop over i is therefore enough for each diagonal. Visiting all N² cells with two nested loops and an if also works, but it does N times more work, and an examiner will mark it down as clumsy.
Hint 2 · How does walking a row differ from walking a column?
To add up row i, you keep i fixed and move j. To add up column j, you keep j fixed and move i. The transpose uses the same swap of roles: element m[i][j] goes to t[j][i]. For symmetry, you only need to compare m[i][j] with m[j][i] for the cells where j > i. As soon as one pair differs, you know the answer.
Hint 3 · How do you get the exact format without special cases?
On the sum lines, print the label first ("Rows:") and then each value with the format " %d". Every value gets a leading space, and the first value's space is exactly the one required after the colon. The transpose rows follow a different rule, because the space only goes between values. Print it before every value whose index is greater than zero. For the errors, check what scanf returns, and handle reading N separately from reading the matrix.
Solution
Explained solution
The solution puts each calculation in a small function that receives the matrix and its actual order n. The matrix is declared with the maximum size MAXN, but every loop stops at n. As a result, the program never touches uninitialised cells, and it works for any order from 1 to 10.
main only validates the input, calls the functions and prints the results. This division of work is what a midterm usually rewards. Each function can be reasoned about and tested on its own, and all formatting decisions live in one place.
#include <stdio.h>
#define MAXN 10
/* Reads n*n integers row by row. Returns 1 if all of them were read
and 0 if the input ends early. */
static int readMatrix(int m[MAXN][MAXN], int n)
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (scanf("%d", &m[i][j]) != 1) {
return 0;
}
}
}
return 1;
}
static int rowSum(int m[MAXN][MAXN], int n, int i)
{
int sum = 0;
for (int j = 0; j < n; j++) {
sum += m[i][j];
}
return sum;
}
static int columnSum(int m[MAXN][MAXN], int n, int j)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m[i][j];
}
return sum;
}
static int trace(int m[MAXN][MAXN], int n)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m[i][i];
}
return sum;
}
static int antidiagonal(int m[MAXN][MAXN], int n)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m[i][n - 1 - i];
}
return sum;
}
static void transpose(int m[MAXN][MAXN], int n, int t[MAXN][MAXN])
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
t[j][i] = m[i][j];
}
}
}
static int isSymmetric(int m[MAXN][MAXN], int n)
{
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (m[i][j] != m[j][i]) {
return 0;
}
}
}
return 1;
}
int main(void)
{
int m[MAXN][MAXN];
int t[MAXN][MAXN];
int n;
if (scanf("%d", &n) != 1 || n < 1 || n > MAXN) {
printf("Invalid N\n");
return 0;
}
if (!readMatrix(m, n)) {
printf("Incomplete data\n");
return 0;
}
printf("Rows:");
for (int i = 0; i < n; i++) {
printf(" %d", rowSum(m, n, i));
}
printf("\n");
printf("Columns:");
for (int j = 0; j < n; j++) {
printf(" %d", columnSum(m, n, j));
}
printf("\n");
printf("Trace: %d\n", trace(m, n));
printf("Antidiagonal: %d\n", antidiagonal(m, n));
printf("Symmetric: %s\n", isSymmetric(m, n) ? "YES" : "NO");
transpose(m, n, t);
printf("Transpose:\n");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j > 0) {
printf(" ");
}
printf("%d", t[i][j]);
}
printf("\n");
}
return 0;
}Validation. The first condition in main is scanf("%d", &n) != 1 || n < 1 || n > MAXN. On empty input, scanf returns EOF, which is not 1. Thanks to short-circuit evaluation, n is never examined unless it was actually read. That is why the "Empty input" and "N out of range" (N = 11) cases print Invalid N and nothing else. When N is valid, main calls readMatrix, which returns 0 as soon as any scanf fails. This happens in "Incomplete matrix", where N = 2 is announced but only three values follow, so the program prints Incomplete data.
Passing the matrix to functions. Every function receives int m[MAXN][MAXN], but C does not copy the matrix. It passes a pointer to the first row, of type int (*)[MAXN]. The second dimension is mandatory, because the compiler finds m[i][j] by skipping i*MAXN + j integers from the start. For the same reason, when transpose writes into t, main sees the change. If you want to compare with a language that hides these details, see the Python version of transpose, diagonals and row sums.
Row and column sums. rowSum fixes i and moves j, and columnSum does the opposite. In both functions the accumulator sum is a local variable that starts at 0 on every call, so one row's total cannot leak into the next. In the "Sample 3x3" case, the rows are 5 -2 7, 0 4 1 and 3 6 -1. The row sums are 10, 5 and 8, and the column sums are 8, 8 and 7. These are exactly the first two lines of the expected output.
Diagonals. trace adds m[i][i], and antidiagonal adds m[i][n - 1 - i], each with a single loop. In the sample, the trace is 5 + 4 + (-1) = 8 and the antidiagonal is 7 + 4 + 3 = 14. The step-by-step trace for this post shows 24 steps on that matrix. There are nine steps for the rows, nine for the columns, three for the main diagonal and three for the antidiagonal. Each step highlights the visited cell, so you can watch sum grow.
Symmetry. isSymmetric visits only the upper triangle (j starts at i + 1) and compares each cell with its mirror image. The diagonal never needs checking, because each diagonal cell always equals itself. In the sample, the very first comparison finds that m[0][1] is -2 and m[1][0] is 0. The function returns 0 and the output says NO. In "Symmetric 4x4", all six pairs match, so the answer is YES. As expected, the printed transpose is identical to the input matrix.
Transpose and format. transpose assigns t[j][i] = m[i][j], so row i of t is column i of m. In the sample, the first row of the transpose is 5 0 3. The sum lines use " %d", and the transpose rows print a space only when j > 0. These are the two formatting rules from the statement. The "Single element" case covers the edge N = 1. Its only value, -7, is at once a row, a column, the trace and the antidiagonal, and the matrix is trivially symmetric.
Step-by-step trace · generated by running the code
| Step | phase | i | j | value | sum | Cell |
|---|---|---|---|---|---|---|
| 1 | row | 0 | 0 | 5 | 5 | (0,0) |
| 2 | row | 0 | 1 | -2 | 3 | (0,1) |
| 3 | row | 0 | 2 | 7 | 10 | (0,2) |
| 4 | row | 1 | 0 | 0 | 0 | (1,0) |
| 5 | row | 1 | 1 | 4 | 4 | (1,1) |
| 6 | row | 1 | 2 | 1 | 5 | (1,2) |
| 7 | row | 2 | 0 | 3 | 3 | (2,0) |
| 8 | row | 2 | 1 | 6 | 9 | (2,1) |
| 9 | row | 2 | 2 | -1 | 8 | (2,2) |
| 10 | column | 0 | 0 | 5 | 5 | (0,0) |
| 11 | column | 1 | 0 | 0 | 5 | (1,0) |
| 12 | column | 2 | 0 | 3 | 8 | (2,0) |
| 13 | column | 0 | 1 | -2 | -2 | (0,1) |
| 14 | column | 1 | 1 | 4 | 2 | (1,1) |
| 15 | column | 2 | 1 | 6 | 8 | (2,1) |
| 16 | column | 0 | 2 | 7 | 7 | (0,2) |
| 17 | column | 1 | 2 | 1 | 8 | (1,2) |
| 18 | column | 2 | 2 | -1 | 7 | (2,2) |
| 19 | trace | 0 | 0 | 5 | 5 | (0,0) |
| 20 | trace | 1 | 1 | 4 | 9 | (1,1) |
| 21 | trace | 2 | 2 | -1 | 8 | (2,2) |
| 22 | antidiagonal | 0 | 2 | 7 | 7 | (0,2) |
| 23 | antidiagonal | 1 | 1 | 4 | 11 | (1,1) |
| 24 | antidiagonal | 2 | 0 | 3 | 14 | (2,0) |
Test cases
| Case | Input | Expected output | Actual output | Result |
|---|---|---|---|---|
| Sample 3x3 | 3
5 -2 7
0 4 1
3 6 -1 | Rows: 10 5 8
Columns: 8 8 7
Trace: 8
Antidiagonal: 14
Symmetric: NO
Transpose:
5 0 3
-2 4 6
7 1 -1 | Rows: 10 5 8
Columns: 8 8 7
Trace: 8
Antidiagonal: 14
Symmetric: NO
Transpose:
5 0 3
-2 4 6
7 1 -1 | OK |
| Symmetric 4x4 | 4
1 2 3 4
2 0 -5 6
3 -5 7 8
4 6 8 -2 | Rows: 10 3 13 16
Columns: 10 3 13 16
Trace: 6
Antidiagonal: -2
Symmetric: YES
Transpose:
1 2 3 4
2 0 -5 6
3 -5 7 8
4 6 8 -2 | Rows: 10 3 13 16
Columns: 10 3 13 16
Trace: 6
Antidiagonal: -2
Symmetric: YES
Transpose:
1 2 3 4
2 0 -5 6
3 -5 7 8
4 6 8 -2 | OK |
| Single element | 1
-7 | Rows: -7
Columns: -7
Trace: -7
Antidiagonal: -7
Symmetric: YES
Transpose:
-7 | Rows: -7
Columns: -7
Trace: -7
Antidiagonal: -7
Symmetric: YES
Transpose:
-7 | OK |
| N out of range | 11 | Invalid N | Invalid N | OK |
| Empty input | (empty) | Invalid N | Invalid N | OK |
| Incomplete matrix | 2
1 2 3 | Incomplete data | Incomplete data | OK |
Actual outputs: code compiled with gcc 14.4.0 (C17) and run in an isolated container on 5 October 2026.
Complexity
Time. Reading the input visits all N² cells. The N calls to rowSum cost N operations each, N² in total, and the column sums cost the same. The trace and the antidiagonal are linear, O(N). transpose is O(N²), and isSymmetric makes at most N(N-1)/2 comparisons, which is also O(N²). The total is O(N²), which is linear in the size of the input. You cannot do better, because every value must be read at least once.
Memory. The program uses two fixed 10×10 integer matrices, 200 int values or about 800 bytes of stack, plus a few scalar variables. Because the maximum order is bounded, this memory is constant. With dynamically sized matrices it would be O(N²). The matrix t doubles the storage. The first variant removes it by transposing in place, so only one temporary variable is needed on top of m.
Common mistakes
- Writing the antidiagonal as
m[i][n - i]. Wheni = 0this reads columnn, which does not exist. C reports no error: the program reads garbage or a cell from another row. - Using
MAXNinstead ofnas the loop bound. The sums then include uninitialised cells, and the result can change from one run to the next. - Declaring a single accumulator outside the row loop and never resetting it, so each row carries over the total of the rows before it. A local variable inside
rowSummakes this mistake impossible. - Returning 1 from inside the symmetry loop as soon as one pair matches. You can only claim the matrix is symmetric after checking every pair and finding no mismatch.
- Declaring the parameter as
int m[][]. This does not compile, because the compiler needs the second dimension to locatem[i][j]. - Ignoring the return value of
scanf. With empty or truncated input, the program works on indeterminate values instead of printingInvalid NorIncomplete data.
Variants
Transpose in place, without a second matrix
Swap m[i][j] with m[j][i], but only for j > i. If the inner loop started at 0, every pair would be swapped twice and the matrix would end up unchanged. The original matrix no longer exists after the swap, so all sums and the symmetry check must be computed before transposing. The extra memory shrinks to one temporary variable, tmp. The program below replaces transpose with transposeInPlace and prints the transposed m. It is compiled and run on the same six tests and produces the same output as the reference solution.
#include <stdio.h>
#define MAXN 10
static int readMatrix(int m[MAXN][MAXN], int n)
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (scanf("%d", &m[i][j]) != 1) {
return 0;
}
}
}
return 1;
}
static int rowSum(int m[MAXN][MAXN], int n, int i)
{
int sum = 0;
for (int j = 0; j < n; j++) {
sum += m[i][j];
}
return sum;
}
static int columnSum(int m[MAXN][MAXN], int n, int j)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m[i][j];
}
return sum;
}
static int trace(int m[MAXN][MAXN], int n)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m[i][i];
}
return sum;
}
static int antidiagonal(int m[MAXN][MAXN], int n)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m[i][n - 1 - i];
}
return sum;
}
static int isSymmetric(int m[MAXN][MAXN], int n)
{
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (m[i][j] != m[j][i]) {
return 0;
}
}
}
return 1;
}
static void transposeInPlace(int m[MAXN][MAXN], int n)
{
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int tmp = m[i][j];
m[i][j] = m[j][i];
m[j][i] = tmp;
}
}
}
int main(void)
{
int m[MAXN][MAXN];
int n;
if (scanf("%d", &n) != 1 || n < 1 || n > MAXN) {
printf("Invalid N\n");
return 0;
}
if (!readMatrix(m, n)) {
printf("Incomplete data\n");
return 0;
}
printf("Rows:");
for (int i = 0; i < n; i++) {
printf(" %d", rowSum(m, n, i));
}
printf("\n");
printf("Columns:");
for (int j = 0; j < n; j++) {
printf(" %d", columnSum(m, n, j));
}
printf("\n");
printf("Trace: %d\n", trace(m, n));
printf("Antidiagonal: %d\n", antidiagonal(m, n));
printf("Symmetric: %s\n", isSymmetric(m, n) ? "YES" : "NO");
transposeInPlace(m, n);
printf("Transpose:\n");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j > 0) {
printf(" ");
}
printf("%d", m[i][j]);
}
printf("\n");
}
return 0;
}Report which row has the largest sum
Reuse rowSum. Take row 0 as the reference, with best = rowSum(m, n, 0) and row = 0. Then loop over rows 1 to n-1, and update both variables only when the new sum is strictly greater, so the first row wins a tie. The classic mistake is to initialise best to 0. This statement allows negative values, so with an all-negative grid no row would beat 0 and the answer would be wrong. The column version is identical but uses columnSum.
Produced with AI support and reviewed by the newsroom



Comentarios
Publicar un comentario