Написать программу, которая матрично умножает две матрицы.

Пусть даны две прямоугольные матрицы $A$ и $B$ размерности $l \times m$ и $m \times n$ соответсвенно.

$A = \begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1m} \\ a_{21} & a_{22} & \cdots & a_{2m} \\ \vdots & \vdots & \ddots & \vdots \\ a_{l1} & a_{l2} & \cdots & a_{lm} \end{bmatrix},\;\;\; B =
\begin{bmatrix} b_{11} & b_{12} & \cdots & b_{1n} \\ b_{21} & b_{22} & \cdots & b_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ b_{m1} & b_{m2} & \cdots & b_{mn} \end{bmatrix}.$

Тогда матрица $C$ размерностью $l \times n$: $C = \begin{bmatrix} c_{11} & c_{12} & \cdots & c_{1n} \\ c_{21} & c_{22} & \cdots & c_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ c_{l1} & c_{l2} & \cdots & c_{ln} \end{bmatrix},$

в которой: $c_{ij} = \sum_{r=1}^m a_{ir}b_{rj} \;\;\; \left(i=1, 2, \ldots l;\; j=1, 2, \ldots n \right).$ называется их произведением.

Операция умножения двух матриц выполнима только в том случае, если число столбцов в первом сомножителе равно числу строк во втором; в этом случае говорят, что матрицы согласованы. В частности, умножение всегда выполнимо, если оба сомножителя — квадратные матрицы одного и того же порядка.

Пример произведения строки на столбец:

#include "stdio.h"
#include "test.h"

#define L 3
#define M 4
#define N 2

static int c[L][N];

// matmul - матричное произведение двух матриц.
// формула: <https://ru.wikipedia.org/wiki/Умножение_матриц>
// Результат произведения нужно положить в глобальную переменную c;
// PS: обычно, глобальные переменные для такого не используют,
// но здесь мы так делаем, чтобы не начинать тему про указатели.
// Функции в си не могу вернуть двумерный массив.
void matmul(int a[L][M], int b[M][N]) {
  // TODO: напиши меня!
  c[0][0] = a[0][0] * b[0][0];  // удали меня
}

void cli() {
  // 1. Введите матрицы через консоль.
  // 2. Напечататйте красиво в консоль результат произведения матриц.
  // TODO: напиши меня

  // int a[L][M];
  // int b[M][N];
  printf("Введите матрицы A[%d][%d] и B[%d][%d].\\n", L, M, M, N);
  // hint: используйте scanf и printf
}

void test(void) {
  // Это тесты. НЕ УДАЛЯЙТЕ ИХ!
  // Преподаватель будет грустить, если вы удалите тесты T_T.
  // Тесты проверяют, что ваш код работает правильно.
  // Если задача решена неправильно,
  // то в консоли вы увидите ошибку и пояснение.
  // Сдавайте лабу, когда устраните все ошибки в тестах.
  // Если возникли трудности, то попросите преподавателя вам помочь ^_^.

  {
    int c_res[L][N] = {{50, 60}, {114, 140}, {110, 140}};
    int a[L][M] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 8, 7, 6}};
    int b[M][N] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
    matmul(a, b);
    for (int i = 0; i < L; i++) {
      for (int j = 0; j < N; j++) {
        ASSERT_INT(c_res[i][j], ==, c[i][j]);
      }
    }
  }
}

int main(void) {
  test();
  cli();
  return 0;
}

Кстати, если транспонировать матрицу, то можно УСКОРИТЬ вычисления во много раз. Как думаете почему? (Ответ связан с тем, как работает кэш и в какие инструкции компилируется программа)