8. Обработка и печать числовой матриц
Алиас: печать матрицы.
Цель работы
При выполнении лабораторной работы изучить следующие вопросы:
- создание двухмерных динамических массивов;
- обработка матриц;
- использование файлов для хранения матриц;
- передача двумерных массивов в функцию через параметры;
- форматированный вывод матриц на экран;
- доступ к элементам матрицы через указатели и с помощью индексов;
- освоение технологии структурного программирования.
Задание
Часть первая
Создать динамическую матрицу размера и заполнить её следующими значениями:
- все элементы главной диагонали равны ;
- элементы, лежащие выше главной диагонали, вычисляются по формуле , а элементы, лежащие ниже главной диагонали, по формуле , где , и .
В зависимости от размера матрицы и ширины поля вывода элемента матрицы, обеспечить удобное для пользователя отображение матрицы на экране (с этим связано одно из требований функции вывода массива).
Требования к первой части
Обратите внимание, что для выполнения первой части необходимо создать указанные ниже функции и учесть для них определенные требования:
- Универсальная функция выделения памяти для двухмерного динамического массива размера ( - количество строк, - количество столбцов).
- Функция заполнения матрицы :
- Для вычисления значений элементов матрицы использовать рекуррентные соотношения.
- Универсальная функция вывода двухмерного динамического массива размера .
- Функция должна быть реализована в самостоятельном модуле
mprinter: объявление сигнатуры должно находиться вmprinter.h, а ее реализация - вmprinter.cилиmprinter.cpp(в зависимости от языка программирования). - Отображение строки массива не должно превышать рекомендуемую длину строки, описанную в руководстве Google по стилю C++, а именно не более
80символов. Рекомендуемое значение задать в виде константы в модулеmprinter. Если строка выходит за пределы, то необходимо обеспечить перенос непомещающихся столбцов так, как показано в примере ниже. Учесть, что длина столбцов не имеет ограничений. - Матрица и другие двухмерные массивы должны передаваться в функцию вывода через параметры.
- Функция вывода двумерного массива в качестве аргументов должна принимать признак того, в каком формате распечатывать значения элементов матрицы: в экспоненциальном формате (например,
1.23E+10) и в формате с фиксированной точкой с точностьюprecision. Заданную точность также передавать в качестве аргумента.
- Функция должна быть реализована в самостоятельном модуле
- Универсальная функция освобождения памяти, выделенной для двухмерного динамического массива размера .
Значения N, M и precision () устанавливается генератором случайных чисел из диапазонов:
- ;
- ;
- .
Пример вывода двухмерного массива
Ниже представлен пример вывода двухмерного массива , с точностью 7 знаков после запятой.
Обратите внимание, что:
- тут демонстрируется каким образом необходимо переносить столбцы, которые не помещаются в рекомендуемое ограничение на длину строки. Конечный вид вывода определяется исполнителем задания.
- перенос столбцов может потребоваться несколько раз. Иными словами, если на одной строке помещается
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
================================================================================
Часть вторая
Распечатать с помощью разработанной функции, используя вспомогательный массив указателей на строки, матрицу размером , заданную с помощью оператора описания (нединамическую). Значение элементов матрицы определяется соотношением: .
Обратите внимание, что - динамическая матрица, а - нединамическая матрица (задана с помощью оператора описания).
Объясните, как передаются матрицы и в функцию вывода матриц на экран.
Вставьте в программу и объясните результаты выполнения операторов для матрицы , представленных ниже.
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;
Требования к второй части
Обратите внимание, что:
- для выполнения второй части необходимо создать указанные ниже функции:
- Функция заполнения нединамической матрицы .
- Функция получения вспомогательного массива указателей на строки матрицы .
- матрицу необходимо выводить в консоль с помощью вспомогательного массива указателей и разработанной функции вывода из модуля
mprinter.
Формат вывода в консоли
Обратите внимание, что здесь не дается явных указаний того, как должен выглядеть консольный вывод. Тут представлены только требования того, что должно быть отображено в выводе.
В выводе консоли должна быть отображена следующая информация:
- Значения
N,Mиprecision; - Вывод сгенерированной матрицы в экспоненциальном формате и с заданной точностью;
- Вывод сгенерированной матрицы с заданной точностью;
- Вывод значений для матрицы , которые указаны во второй части задания.
Указания по выполнению работы
Прежде чем приступать к выполнению задания прочитайте приведенный ниже текст и представленные примеры программ.
Основные правила работы с двухмерными массивами
- В массивах, определенных с помощью операторов описания, обе размерности должны быть константами или константными выражениями.
- Массив хранится по строкам, каждая строка хранится в непрерывной области памяти.
- Первый индекс всегда представляет собой номер строки, второй – номер столбца. Каждый индекс может изменяться от
0до значения соответствующей размерности, уменьшенной на единицу. - При описании массива можно в фигурных скобках задать начальные значения его элементов.
- Для выделения динамической памяти под массив, в котором все размерности переменные, используются циклы.
Освобождение динамической памяти из-под массива
C
Основано на ответе C: Correctly freeing memory of a multi-dimensional array.
Чтобы освободить память, которая была выделена с помощью malloc(), вы просто вызываете free() именно тот указатель, который вам был предоставлен malloc().
Итак, для этого кода:
int **a = malloc(m * sizeof(int *));
вам нужно сопоставление:
free(a);
и для этой строки:
a[i] = malloc(n * sizeof(int));
вам нужно сопоставление:
free(a[i]);
внутри аналогичного цикла.
C++
Освобождение динамической памяти из-под массива с любым количеством измерений выполняется с помощью операции delete [] А, где А – имя массива.
Рекомендации по порядку создания программы
- Выбрать тип и способ хранения в программе исходных данных, результатов и промежуточных величин.
- Записать алгоритм сначала в общем виде, стремясь разбить его на простую последовательность шагов, а затем детализировать каждый шаг.
- Написать программу. При написании программы рекомендуется:
- давать переменным понятные имена;
- не пренебрегать содержательными комментариями;
- использовать промежуточную печать вычисляемых величин в удобном формате;
- при написании вложенных циклов следить за отступами;
- операторы инициализации накапливаемых в цикле величин задавать непосредственно перед циклом, в котором они вычисляются.
- Параллельно с написанием программы задать тестовые примеры, которые проверяют все ветви алгоритма и возможные диапазоны значений исходных данных.
- Исходные данные удобнее формировать в файле (по крайней мере, при отладке), не забывая проверять в программе успешность его открытия.
Проверка задания
Подготовленная программа для решения задания проверяется вручную преподавателем (визуальный контроль).