Перейти к основному содержимому

8. Обработка и печать числовой матриц

Алиас: печать матрицы.

Цель работы

При выполнении лабораторной работы изучить следующие вопросы:

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

Задание

Часть первая

Создать динамическую матрицу AA размера NMN*M и заполнить её следующими значениями:

  • все элементы главной диагонали равны 11;
  • элементы, лежащие выше главной диагонали, вычисляются по формуле Ai,j=xi(j!)iA_{i,j}=\cfrac{x^i}{(j!)^i} , а элементы, лежащие ниже главной диагонали, по формуле Ai,j=(x)i(j!)iA_{i,j}=\cfrac{(-x)^i}{(j!)^i}, где i=1,2,...,Ni=1,2,...,N, j=1,2,...,Mj=1,2,...,M и x=1x=1.

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

Требования к первой части

Обратите внимание, что для выполнения первой части необходимо создать указанные ниже функции и учесть для них определенные требования:

  1. Универсальная функция выделения памяти для двухмерного динамического массива размера NMN*M (NN - количество строк, MM - количество столбцов).
  2. Функция заполнения матрицы AA:
    1. Для вычисления значений элементов матрицы использовать рекуррентные соотношения.
  3. Универсальная функция вывода двухмерного динамического массива размера NMN*M.
    1. Функция должна быть реализована в самостоятельном модуле mprinter: объявление сигнатуры должно находиться в mprinter.h, а ее реализация - в mprinter.c или mprinter.cpp (в зависимости от языка программирования).
    2. Отображение строки массива не должно превышать рекомендуемую длину строки, описанную в руководстве Google по стилю C++, а именно не более 80 символов. Рекомендуемое значение задать в виде константы в модуле mprinter. Если строка выходит за пределы, то необходимо обеспечить перенос непомещающихся столбцов так, как показано в примере ниже. Учесть, что длина столбцов не имеет ограничений.
    3. Матрица AA и другие двухмерные массивы должны передаваться в функцию вывода через параметры.
    4. Функция вывода двумерного массива в качестве аргументов должна принимать признак того, в каком формате распечатывать значения элементов матрицы: в экспоненциальном формате (например, 1.23E+10) и в формате с фиксированной точкой с точностью precision. Заданную точность также передавать в качестве аргумента.
  4. Универсальная функция освобождения памяти, выделенной для двухмерного динамического массива размера NMN*M.
предупреждение

Значения N, M и precision (N,M,precisionZ{N, M, precision} \in \mathbb{Z}) устанавливается генератором случайных чисел из диапазонов:

  • N[8,15]N \in [8, 15];
  • M[8,15]M \in [8, 15];
  • precision[3,8]precision \in [3, 8].

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

Ниже представлен пример вывода двухмерного массива 9149*14, с точностью 7 знаков после запятой.

Обратите внимание, что:

  1. тут демонстрируется каким образом необходимо переносить столбцы, которые не помещаются в рекомендуемое ограничение на длину строки. Конечный вид вывода определяется исполнителем задания.
  2. перенос столбцов может потребоваться несколько раз. Иными словами, если на одной строке помещается 5 столбцов, а в массиве их 14, то в начале вам необходимо отобразить столбцы с 1 по 5, затем 6 по 10 и в конце с 11 по 14. В данном примере это и демонстрируется.
================================================================================
1.0000000 1.0000000 0.3333333 0.0833333 0.0166667
4.0000000 1.0000000 0.1111111 0.0069444 0.0002778
-8.0000000 -1.0000000 1.0000000 0.0005787 0.0000046
16.0000000 1.0000000 0.0123457 1.0000000 0.0000001
-32.0000000 -1.0000000 -0.0041152 -0.0000040 1.0000000
64.0000000 1.0000000 0.0013717 0.0000003 0.0000000
-128.0000000 -1.0000000 -0.0004572 -0.0000000 -0.0000000
256.0000000 1.0000000 0.0001524 0.0000000 0.0000000
-512.0000000 -1.0000000 -0.0000508 -0.0000000 -0.0000000
--------------------------------------------------------------------------------
0.0027778 0.0003968 0.0000496 0.0000055 0.0000055
0.0000077 0.0000002 0.0000000 0.0000000 0.0000055
0.0000000 0.0000000 0.0000000 0.0000000 0.0000055
0.0000000 0.0000000 0.0000000 0.0000000 0.0000055
0.0000000 0.0000000 0.0000000 0.0000000 0.0000055
1.0000000 0.0000000 0.0000000 0.0000000 0.0000055
-0.0000000 1.0000000 0.0000000 0.0000000 0.0000055
0.0000000 0.0000000 1.0000000 0.0000000 0.0000055
-0.0000000 -0.0000000 -0.0000000 1.0000000 0.0000055
--------------------------------------------------------------------------------
0.0027778 0.0003968 0.0000496 0.0000055
0.0000077 0.0000002 0.0000000 0.0000000
0.0000000 0.0000000 0.0000000 0.0000000
0.0000000 0.0000000 0.0000000 0.0000000
0.0000000 0.0000000 0.0000000 0.0000000
1.0000000 0.0000000 0.0000000 0.0000000
-0.0000000 1.0000000 0.0000000 0.0000000
0.0000000 0.0000000 1.0000000 0.0000000
-0.0000000 -0.0000000 -0.0000000 1.0000000
================================================================================

Часть вторая

Распечатать с помощью разработанной функции, используя вспомогательный массив указателей на строки, матрицу размером B[10][10]B[10][10], заданную с помощью оператора описания (нединамическую). Значение элементов матрицы BB определяется соотношением: B[i][j]=i10+jB[i][j]=i*10+j.

к сведению

Обратите внимание, что AA - динамическая матрица, а BB - нединамическая матрица (задана с помощью оператора описания).

Объясните, как передаются матрицы AA и BB в функцию вывода матриц на экран.

Вставьте в программу и объясните результаты выполнения операторов для матрицы B[10][10]B[10][10], представленных ниже.

C

printf("B=%f, B[0]=%f, B[2]=%f", B, B[0], B[2]);
printf("B[0][0]=%f, **B=%f, *B[0]=%f", B[0][0], **B, *B[0]);
printf("*(*(B+1))=%f, *B[1]=%f", *(*(B+1)), *B[1]);
printf("*(B[0]+1)=%f, *(*B+1)=%f", *(B[0]+1), *(*B+1));
printf("B[0][20]=%f, *(B[0]+20)=%f, *B[2]=%f", B[0][20], *(B[0]+20), *B[2]);

C++

cout<<B<<"  "<<B[0]<<"  "<<B[2]<<endl;
cout<<B[0][0]<<" "<<**B <<" "<<*B[0]<<endl;
cout<<*(*(B+1))<<" "<<*B[1]<<endl;
cout<<*(B[0]+1)<<" " <<*(*B+1)<<endl;
cout<<B[0][20]<<" "<<*(B[0]+20)<<" "<<*B[2]<<endl;

Требования к второй части

Обратите внимание, что:

  1. для выполнения второй части необходимо создать указанные ниже функции:
    1. Функция заполнения нединамической матрицы BB.
    2. Функция получения вспомогательного массива указателей на строки матрицы BB.
  2. матрицу BB необходимо выводить в консоль с помощью вспомогательного массива указателей и разработанной функции вывода из модуля mprinter.

Формат вывода в консоли

к сведению

Обратите внимание, что здесь не дается явных указаний того, как должен выглядеть консольный вывод. Тут представлены только требования того, что должно быть отображено в выводе.

В выводе консоли должна быть отображена следующая информация:

  1. Значения N, M и precision;
  2. Вывод сгенерированной матрицы AA в экспоненциальном формате и с заданной точностью;
  3. Вывод сгенерированной матрицы BB с заданной точностью;
  4. Вывод значений для матрицы BB, которые указаны во второй части задания.

Указания по выполнению работы

Прежде чем приступать к выполнению задания прочитайте приведенный ниже текст и представленные примеры программ.

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

  1. В массивах, определенных с помощью операторов описания, обе размерности должны быть константами или константными выражениями.
  2. Массив хранится по строкам, каждая строка хранится в непрерывной области памяти.
  3. Первый индекс всегда представляет собой номер строки, второй – номер столбца. Каждый индекс может изменяться от 0 до значения соответствующей размерности, уменьшенной на единицу.
  4. При описании массива можно в фигурных скобках задать начальные значения его элементов.
  5. Для выделения динамической памяти под массив, в котором все размерности переменные, используются циклы.

Освобождение динамической памяти из-под массива

C

к сведению

Чтобы освободить память, которая была выделена с помощью malloc(), вы просто вызываете free() именно тот указатель, который вам был предоставлен malloc().

Итак, для этого кода:

int **a = malloc(m * sizeof(int *));

вам нужно сопоставление:

free(a);

и для этой строки:

a[i] = malloc(n * sizeof(int));

вам нужно сопоставление:

free(a[i]);

внутри аналогичного цикла.

C++

Освобождение динамической памяти из-под массива с любым количеством измерений выполняется с помощью операции delete [] А, где А – имя массива.

Рекомендации по порядку создания программы

  1. Выбрать тип и способ хранения в программе исходных данных, результатов и промежуточных величин.
  2. Записать алгоритм сначала в общем виде, стремясь разбить его на простую последовательность шагов, а затем детализировать каждый шаг.
  3. Написать программу. При написании программы рекомендуется:
    • давать переменным понятные имена;
    • не пренебрегать содержательными комментариями;
    • использовать промежуточную печать вычисляемых величин в удобном формате;
    • при написании вложенных циклов следить за отступами;
    • операторы инициализации накапливаемых в цикле величин задавать непосредственно перед циклом, в котором они вычисляются.
  4. Параллельно с написанием программы задать тестовые примеры, которые проверяют все ветви алгоритма и возможные диапазоны значений исходных данных.
  5. Исходные данные удобнее формировать в файле (по крайней мере, при отладке), не забывая проверять в программе успешность его открытия.

Проверка задания

Подготовленная программа для решения задания проверяется вручную преподавателем (визуальный контроль).

Методический материал

  1. Требования к отчету
  2. Примеры программ:
    1. Создание двухмерных динамических массивов
    2. Передача многомерного массива в функцию с помощью параметров
    3. Программа сортировки строк матрицы
  3. Контрольные вопросы:
    1. Для потока на С
    2. Для потока на С++