Перейти к содержанию

Лекция 13: Двумерные массивы

"Я не боюсь того, кто учит 10 тысячам строкам кода на C
Я боюсь геморроидального узла"
— Уильям Дефо


Введение в двумерные массивы

Массив — это структура данных, состоящая из элементов одного типа, которые хранятся последовательно в памяти.

Одномерные массивы представляют линейные структуры данных (например, векторы), тогда как двумерные массивы используются для работы с более сложными структурами данных, такими как матрицы, таблицы или экраны.

В языке C двумерный массив — это по сути массив одномерных массивов, где каждый элемент массива имеет два индекса: номер строки и номер столбца.

О понятии двумерного массива

В общем случае, двумерный массив — понятие гораздо более широкое, чем матрица, поскольку он может быть и не прямоугольным, и не числовым.


Объявление двумерных массивов

Двумерный массив объявляется следующим образом:

<тип данных> <имя массива>[количество строк][количество столбцов];

Пример:

int matrix[3][4];

Здесь matrix — массив целых чисел, состоящий из 3 строк и 4 столбцов.

  • Первый индекс указывает номер строки.
  • Второй индекс — номер столбца.
Примечание

В C индексы начинаются с 0.


Инициализация двумерных массивов

Двумерные массивы можно инициализировать сразу при объявлении:

int matrix[2][2] = {{1, 2}, {3, 4}};

Также можно инициализировать массив, опуская первый размер:

int matrix[][2] = {{1, 2}, {3, 4}};

Компилятор определит размерность массива, исходя из количества элементов.


Доступ к элементам массива

Элементы массива можно изменять и читать по индексам:

matrix[1][1] = 5;  // Записывает значение 5 во второй строке, втором столбце
int value = matrix[0][1];  // Читает значение из первой строки, второго столбца

Работа с массивами с помощью циклов

Для обработки всех элементов двумерного массива удобно использовать вложенные циклы:

const int rows = 3;
const int cols = 4;
int matrix[rows][cols];

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        matrix[i][j] = i * j;  // Пример заполнения массива
    }
}

Здесь внешний цикл проходит по строкам, а внутренний — по столбцам каждой строки.


Низкоуровневая абстракция

В языке C массивы по сути являются указателями на свой первый элемент. Например, для двумерного массива matrix[3][4] имя matrix указывает на начало первой строки. Элементы можно также получать через указательную арифметику:

*(*(matrix + i) + j);  // Эквивалент matrix[i][j]

Каждый элемент двумерного массива хранится последовательно в памяти. Адрес элемента matrix[i][j] вычисляется по формуле:

\[ address = \textit{base\_address} + (i \times\ \textit{num\_columns} + j) \times\ sizeof(int) \]

Пример представления массива в памяти

int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};
Адрес Значение Индексы
0x100 1 matrix[0][0]
0x104 2 matrix[0][1]
0x108 3 matrix[0][2]
0x10C 4 matrix[0][3]
0x110 5 matrix[1][0]
0x114 6 matrix[1][1]
0x118 7 matrix[1][2]
0x11C 8 matrix[1][3]
0x120 9 matrix[2][0]
0x124 10 matrix[2][1]
0x128 11 matrix[2][2]
0x12C 12 matrix[2][3]

Каждый элемент занимает 4 байта, и адрес следующего увеличивается на 4 байта. Адрес matrix[i][j] рассчитывается по формуле:

\[ address = \textit{base\_address} + (i \times\ \textit{num\_columns} + j) \times\ sizeof(int) \]

Например, элемент matrix[2][1] будет по адресу:

\[ 0x120 + (2 \times 4 + 1) \times 4 = 0x124 \]

Это пример построчного размещения: элементы массива идут подряд, строка за строкой, начиная с первой.


Примеры операций с массивами

Сумма всех элементов

int sum = 0;
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        sum += matrix[i][j];
    }
}

Заполнение массива случайными числами

#include <stdlib.h>
#include <time.h>

srand(time(NULL));  // Инициализация генератора случайных чисел
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        matrix[i][j] = rand() % 10;  // Случайное число от 0 до 9
    }
}

Сумма элементов главной диагонали

int sum = 0;
for (int i = 0; i < N; i++) {
    sum += matrix[i][i];
}

Перестановка строк

for (int j = 0; j < cols; j++) {
    int temp = matrix[1][j];
    matrix[1][j] = matrix[3][j];
    matrix[3][j] = temp;
}

Сортировка методом пузырька

for (int i = 0; i < rows * cols - 1; i++) {
    for (int j = 0; j < rows * cols - i - 1; j++) {
        if (matrix[j / cols][j % cols] > matrix[(j + 1) / cols][(j + 1) % cols]) {
            int temp = matrix[j / cols][j % cols];
            matrix[j / cols][j % cols] = matrix[(j + 1) / cols][(j + 1) % cols];
            matrix[(j + 1) / cols][(j + 1) % cols] = temp;
        }
    }
}

Применение двумерных массивов

  • Графика и таблицы: Хранение значений для графического интерфейса, например, пикселей изображения.
  • Матрицы в линейной алгебре: Операции над матрицами, такие как сложение, умножение и нахождение детерминанта.
  • Игровые доски: Хранение состояния, например, шахматной доски.

Заключение

Двумерные массивы — мощный инструмент для организации данных в языке C. Они позволяют эффективно обрабатывать данные, хранящиеся в табличном формате, и активно используются в графике, вычислениях и других областях программирования.


Nothing to prove, nothing to say
Nothing to lose, nothing to gain
Nothing to feel, nothing to hate
Nothing is real, it's all too late