Лабораторная работа 9
Обработка и печать числовой матрицы.
Содержание работы:
— создание двухмерных динамических массивов;
-использование файлов для хранения матриц (на примере приведенной ниже программы сортировки строк матрицы);
— передача двумерных массивов в функцию через параметры;
— форматированный вывод матриц на экран;
— доступ к элементам матрицы через указатели и с помощью индексов;
— освоение технологии структурного программирования (разобрать и выполнить приведенную в описании работы программу сортировки строк матрицы).
Задание. Создать квадратную матрицу A размером N*N (где N вводится с клавиатуры), и заполнить её следующими значениями:
— все элементы главной диагонали равны 1;
— элементы, лежащие выше главной диагонали, вычисляются по формуле
A i,j = xi / (j!)i ,
а элементы, лежащие ниже главной диагонали, по формуле
A i,j = (-x)i / (j!)i, где i,j =1,2,…,N; x=1.
Для вычисления значений элементов матрицы использовать рекуррентные соотношения.
Реализовать алгоритм заполнения матрицы в виде функции.
В зависимости от размера матрицы и ширины поля вывода элемента матрицы, обеспечить удобное для пользователя отображение матрицы на экране. Оформить вывод матрицы размером N*M на экран в виде функции с целью использования ее в
последующих лабораторных работах для распечатки двумерных массивов.
Матрица должна передаваться в разрабатываемые функции через параметры.
Не изменяя кода функции вывода матрицы, распечатать матрицу в «научном» формате и в формате с фиксированной точкой с точностью 8 знаков после запятой.
Распечатать с помощью разработанной функции, используя вспомогательный массив указателей на строки, матрицу размером B[10][10], заданную с помощью оператора описания (нединамическую). Значение элементов матрицы В определяется соотношением: B[i][j]=i*10+j.
Объясните, как передаются матрицы A и В в функцию вывода матриц на экран.
Вставьте в программу и объясните результаты выполнения следующих операторов
для матрицы В[10][10]:
cout
cout
cout
cout
cout
Прежде чем приступать к выполнению задания прочитайте приведенный ниже текст и разберите и выполните пример программы сортировки строк матрицы.
.
Создание двухмерных динамических массивов.
В динамической области памяти можно создавать двумерные массивы с помощью операции new или функции mаllос. Остановимся на первом варианте, поскольку он более безопасен и прост в использовании.
Обращение к элементам динамических массивов производится точно так же, как к элементам «обычных», с помощью конструкции вида a[i ][j].
Универсальный способ выделения памяти под двумерный массив, когда обе его размерности задаются на этапе выполнения программы, приведен ниже:
int nrow, ncol;
cout
cin nrow ncol;
int **a = new int *[nrow]; // 1
for(int i = 0; i nrow; i++) // 2
a[i] = new int [ncol]; // 3
Для того чтобы понять, отчего динамические массивы описываются именно так, нужно разобраться в механизме индексации элемента массива. Поскольку для доступа к элементу массива применяется две операции разадресации, то переменная, в которой хранится адрес начала массива, должна быть указателем на указатель.
В операторе 1 объявляется переменная типа «указатель на указатель на int» и выделяется память под массив указателей на строки массива (количество строк — nrow). В операторе 2 организуется цикл для выделения памяти под каждую строку массива. В операторе 3 каждому элементу массива указателей на строки присваивается адрес начала участка памяти, выделенного под строку двумерного массива. Каждая строка состоит из ncol элементов типа int (рис. 1).
Освобождение памяти из-под массива с любым количеством измерений выполняется с помощью операции delete [],например: delete [] a;
Рис. 1. Схема динамической области памяти, выделяемой под массивы
Передача многомерного массива в функцию с помощью параметров.
При необходимости передать в функцию многомерный массив с помощью параметра возникают неудобства, связанные с отсутствием в Си++ и Си объектов типа многомерный массив. Если мы описываем массив с несколькими индексами, например,
double arr[6][4][2];
то это не трехмерный массив, а одномерный массив с именем arr, состоящий из 6 элементов, каждый из которых имеет тип double [4][2]. В свою очередь, каждый из этих элементов есть одномерный массив из четырех элементов типа double [2]. И, наконец, каждый из этих элементов является массивом из двух элементов типа double.
Очевидное и неверное решение при попытке передать в функцию матрицу – определить её заголовок следующим образом:
void func(double x[][], int n)
Здесь n – предполагаемый порядок квадратной матрицы; double x[][] – попытка определить двухмерный массив с заранее неизвестными параметрами. На такую попытку транслятор ответит сообщением об ошибке:
Error…: Size of type is unknown or zero.
Вспомним – массив всегда одномерный, а его элементы должны иметь известную и фиксированную длину. В массиве double x[][]не только неизвестно количество элементов одномерного массива (это допустимо и их можно передать параметром int n),
но ничего не известно о размерах этих элементов. Допустимое с точки зрения синтаксиса языка Си++ решение — void func(double x[][4], int n).
Нежизненность такого решения – необходимость фиксации второй размерности матрицы.
Указанные ограничения на возможность применения многомерных массивов в качестве параметров функции можно обойти двумя путями.
Первый путь – подмена многомерного массива, например, double x[3][4]одномерным double x[12]и имитация внутри функции доступа к нему как к многомерному массиву.
Второй путь – использование вспомогательных одномерных массивов указателей на массивы. Такой массив указателей на строки матрицы используется при создании динамических массивов.
Помните, что если размерность массива явно не указана, то в функцию с помощью параметров можно передавать только одномерные массивы.