Двумерные массивы
Двумерный массив — это таблица
Если одномерный массив — полка с ячейками, то двумерный — шкаф: несколько полок, на каждой
одинаковое число ячеек. Элемент задаётся двумя индексами: a[строка][столбец].
#define MAX_SIZE 20
int a[MAX_SIZE][MAX_SIZE]; /* максимум 20 × 20 */
int b[3][4]; /* 3 строки, 4 столбца — 12 элементов */
столбец 0 столбец 1 столбец 2
строка 0 1 2 3
строка 1 4 5 6
Важно. Первый индекс — строка, второй — столбец. Путаница с порядком индексов — ошибка №1 при работе с матрицами.
Заполнить матрицу можно и при объявлении:
int m[2][3] = {
{ 1, 2, 3 },
{ 4, 5, 6 },
};
В лабораторной работе №2 многомерный массив хранится в статическом массиве
int a[MAX_SIZE][MAX_SIZE]; динамическое выделение памяти (malloc) не используется.
Размеры вводит пользователь: 1 ≤ N, M ≤ MAX_SIZE.
Чтение матрицы с клавиатуры
Сначала N и M (строки и столбцы), затем N × M чисел. Размеры обязательно проверяем:
int n, m;
int a[MAX_SIZE][MAX_SIZE];
printf("Введите N и M: ");
if (scanf("%d %d", &n, &m) != 2)
{
printf("Ошибка: размеры должны быть целым числом\n");
return 1;
}
if (n < 1 || m < 1 || n > MAX_SIZE || m > MAX_SIZE)
{
printf("Ошибка: размеры должны быть от 1 до %d\n", MAX_SIZE);
return 1;
}
for (int i = 0; i < n; i++) /* строки */
{
for (int j = 0; j < m; j++) /* столбцы */
{
if (scanf("%d", &a[i][j]) != 1)
{
printf("Ошибка: ожидалось целое число\n");
return 1;
}
}
}
Строки и столбцы можно вводить как в одну строку, так и построчно — scanf пропускает пробелы
и переводы строк.
Вывод таблицей
Матрицу печатают вложенными циклами, а для выравнивания используют ширину поля %4d:
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%4d", a[i][j]);
}
printf("\n"); /* перевод строки после каждой строки матрицы */
}
Обход: вложенные циклы
Внешний цикл идёт по строкам, внутренний — по столбцам. Для матрицы нужны два вложенных цикла:
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
/* работаем с a[i][j] */
}
}
Типовые задачи
Сумма всех элементов
int sum = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
sum += a[i][j];
}
}
printf("Сумма всех элементов: %d\n", sum);
Сумма строки i
int sum = 0;
for (int j = 0; j < m; j++)
{
sum += a[i][j];
}
Сумма столбца j
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += a[i][j];
}
Диагонали квадратной матрицы
int main_diag = 0, side_diag = 0;
for (int i = 0; i < n; i++)
{
main_diag += a[i][i]; /* главная: i == j */
side_diag += a[i][n - 1 - i]; /* побочная: i + j == n - 1 */
}
Диагонали существуют только у квадратной матрицы (N == M). Если матрица прямоугольная,
выводим сообщение — это один из граничных случаев.
Транспонирование
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++) /* только выше диагонали */
{
int t = a[i][j];
a[i][j] = a[j][i];
a[j][i] = t;
}
}
Минимум (максимум) с координатами
int mi = 0, mj = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (a[i][j] < a[mi][mj])
{
mi = i;
mj = j;
}
}
}
printf("минимум %d в строке %d, столбце %d\n", a[mi][mj], mi + 1, mj + 1);
Среднее арифметическое
Среднее — дробное число, поэтому нужен double и приведение типа, иначе деление будет целым:
double avg = (double)sum / (n * m);
Граничные случаи
В лабораторной работе отдельно проверяют:
- матрица
1 × 1— циклы должны работать без особых условий; - прямоугольная матрица (
N ≠ M) — диагонали и симметрия только для квадратной; - нет искомых элементов (например, нет отрицательных) — выводим понятное сообщение;
- при вставке и удалении строк/столбцов не выходим за границы массива
MAX_SIZE × MAX_SIZEи не забываем менятьNилиM.
Память и размеры
- Двумерный массив хранится по строкам: сначала вся строка 0, потом строка 1 и т. д.
- Поэтому обход «по строкам» (внешний цикл —
i, внутренний —j) быстрее, чем наоборот.
Частые ошибки
| Ошибка | Что не так |
|---|---|
a[j][i] вместо a[i][j] | перепутаны строка и столбец |
for (i = 0; i <= n; i++) | выход за границы массива |
int sum = 0; внутри двойного цикла | сумма сбрасывается на каждом шаге |
(double)sum / (n * m) не поставили | целочисленное деление вместо дробного |
Что запомнить
- Первый индекс — строка, второй — столбец.
- Для обхода нужны два вложенных цикла.
- Диагонали и симметрия — только для квадратной матрицы.
- Среднее считаем через
double. - Программа в ЛР2 обязательно разбивается на функции — об этом в следующей теме.