7 - Обработка и печать числовой матрицы

Лабораторная работа 7 для студентов курса “Основы программирования” 1 курса кафедры ИУ5 МГТУ им Н.Э. Баумана.

Содержание

Цель работы

На примере разработки функции печати числовой матрицы освоить следующие приемы программирования:

Начало работы

Зайдите в свою локальную директорию с репозиторием для выполнения лабораторных работ. Заберите ветку с соответствующей лабораторной работой из общего репозитория (в лабораторной работе 0 был отмечен меткой upstream):

git pull upstream

или

git pull upstream lab_7

Переключитесь на ветку с текущей лабораторной работой:

git checkout lab_7

Свяжите ветку локального репозитория с вашим удаленным репозиторием:

git push --set-upstream origin lab_7

Задание

Часть первая

  1. Создать матрицу twoDimensionalDynamicMatrix размером numberOfRows * numberOfColumns и заполнить её значениями:
    • все элементы главной диагонали равны 1;
    • элементы, лежащие выше главной диагонали, вычисляются по формуле: ai,j = xi / (j!)i;
    • элементы, лежащие ниже главной диагонали, по формуле : ai,j = (-x)i / (j!)i;
    • где

      • i = 1, 2, …, numberOfRows;
      • j = 1, 2, …, numberOfColumns;
      • x = 1.
  2. Распечатать матрицу в научном или фиксированном формате.

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

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

  1. Функция выделения памяти для двухмерного динамического массива размером numberOfRows * numberOfColumns, где numberOfRows - количество строк, numberOfColumns - количество столбцов.
  2. Функция заполнения матрицы twoDimensionalDynamicMatrix.
      Для вычисления значений элементов матрицы, необходимо использовать рекуррентные соотношения.
  3. Функция вывода двухмерного динамического массива размером numberOfRows * numberOfColumns в качестве аргументов должна принимать
    • точность вывода ai,j(precision),
    • признак того, в каком формате распечатывать значения элементов матрицы: в экспоненциальном формате ( 1.230000E-04 ) или в формате с фиксированной точкой ( 0.000123 );
    • функция должна быть реализована в самостоятельном модуле.
    • отображение строки массива не должно превышать рекомендуемую длину строки, описанную в руководстве Google по стилю C++, а именно не более 80 символов. Если строка выходит за пределы, то необходимо обеспечить перенос не помещающихся столбцов ниже.
    • матрица или другие двухмерные массивы должны передаваться в функцию вывода через параметры.
  4. Функция освобождения памяти, выделенной для двухмерного динамического массива размером numberOfRows * numberOfColumns

Часть вторая

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

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

Создание двухмерных динамических массивов

В динамической области памяти можно создавать двухмерные массивы с помощью операции new или функции mаllос. Остановимся на первом варианте, поскольку он более безопасен и прост в использовании.

Обращение к элементам динамических массивов производится точно так же, как к элементам «обычных», с помощью конструкции вида a[i][j].

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

int nrow, ncol;
std::cout << "Введите количество строк и столбцов :";
std::cin >> nrow >> ncol;
int **a = new int *[nrow];
for(int i = 0; i < nrow; ++i){
    a[i] = new int [ncol];
}

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

В операторе 1 объявляется переменная типа "указатель на указатель на int" и выделяется память под массив указателей на строки массива (количество строк — nrow).

В операторе 2 организуется цикл для выделения памяти под каждую строку массива.

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

Каждая строка состоит из ncol элементов типа int (рис. 1).

Рис. 1. Схема динамической области памяти, выделяемой под массивы
Рис. 1. Схема динамической области памяти, выделяемой под массивы

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

Передача многомерного массива в функцию с помощью параметров.

При необходимости передать в функцию многомерный массив с помощью параметра возникают неудобства, связанные с отсутствием в С++ и Си объектов типа многомерный массив. Если мы описываем массив с несколькими индексами, например:

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);

Нежизненность такого решения – необходимость фиксации второй размерности матрицы.

Указанные ограничения на возможность применения многомерных массивов в качестве параметров функции можно обойти двумя путями.

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

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

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