Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа №11_по функциям в си+.doc
Скачиваний:
2
Добавлен:
17.11.2018
Размер:
182.27 Кб
Скачать

5.3. Определение переменных программы (вариант 1)

   

варианта

Содержание задания

Иллюстрация

30

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

 Программа будет состоять из двух функций - main() и fill(). В соответствии с принципом модульности желательно, чтобы функции имели минимальное количество общих переменных, и здесь мы имеем возможность обойтись совсем без них. Все переменные, с которыми работают наши функции, будут локальными переменными функций или параметрами.

    Переменные для функции main().

    Указатель на начало линейного массива, в котором размещаются данные матрицы:

int *Ar;

    Размерность массива:

int S;

    Общее количество элементов массива (его использование будет видно из текста программы):

int size;

    Указатель на текущий элемент массива при его выводе:

int *Cr;

    Счетчик выведенных элементов:

int i;

    Параметры для функции fill().

    Указатель на начало линейного массива, в котором размещаются данные матрицы:

int *A;

    Размерность массива:

int s;

    Переменные для функции fill().

    Указатель на текущий элемент массива при его обработке:

int *C;

    Номера строки и столбца:

short l, r;

    Текущий член линейной последовательности:

int k=1;

5.4. Разработка текста программы (вариант 1)

    Текст программы начинаем с включения файлов: stdio.h, stdlib.h (в последнем определены макросы max и min).

    Включаем описание функции fill() и открываем главную функцию. В главной функции объявляем ее локальные переменные, выводим приглашение и вводим значение размерности матрицы S. Размерность сравнивается с нижней и с верхней границей и, если она выходит за границы, выводится соответствующее сообщение и программа завершается (функцией exit()). Если S удовлетворяет установленным условиям, его значение выводится на экран.

    Потом выделяется память для размещения матрицы. Для этого используется операция new. Она возвращает с присваиванием переменной **Ar (указатель на указатель) указательна массив из S указателей, который нужен для размещения S2 элементов типа int. Таким образом, в Ar содержится значение указателя на выделенную область памяти (это будет указатель на начало массива, в котором разместятся данные матрицы).

ЗАМЕЧАНИЕ!!!!!. В динамической области памяти можно создавать двумерные массивы с помощью операции new или функции mallос. Остановимся на первом варианте, поскольку он более безопасен и прост в использовании.

При выделении памяти сразу под весь массив количество строк (самую левую размерность) можно задавать с помощью переменной или выражения, а количество столбцов должно быть константным выражением, то есть явно определено до выполнения программы. После слова new записывается тип создаваемого массива, а затем _ его размерности в квадратных скобках (аналогично описанию «обычных», нединамических массивов), например:

int n;

const int m = 5;

cin » n;

int (*a)[m] = new int [n][m]; // 1

int ** b = (int **) new int [n][m]; // 2

В этом фрагменте показано два способа создания динамического массива. В операторе 1 адрес начала выделенного с помощью new участка памяти присваивается переменной а, определенной как указатель на массив из m элементов типа int. Именно такой тип значения возвращает в данном случае операция new. Скобки необходимы, поскольку без них конструкция интерпретировалась бы как массив указателей. Всего выделяется n элементов.

В операторе 2 адрес начала выделенного участка памяти присваивается переменной b, которая описана как «указатель на указатель на int», поэтому перед присваиванием требуется выполнить преобразование типа.

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

int ** b = reinterpret_cast<int **> (new int [n][m]);

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

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

int nrow, ncol;

cout « " Введите количество строк и столбцов :";

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 (рис. 4.2).

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

ВНИМАНИЕ

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

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

Оператор:

fill(Ar,S);

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

    После возврата управления из функции fill() уже готовая матрица выводится на экран. При выводе матрица рассматривается как линейный массив из S2 элементов. Счетчик i меняется от 0 до S2-1. Но обращение к элементам матрицы в этом цикле ведется через указатель Cr. В начальных установках этот указатель устанавливается на начало массива, а после каждой итерации увеличивается на 1, т.е. сдвигается на следующий элемент массива. Счетчик i используется для определения момента выхода из цикла, а также для перехода на новую строку экрана после вывода каждых S элементов - для этого проверяется условие: i%S==S-1.

    Последним действием в функции main() является освобождение с помощью функции delete [] выделенной ранее памяти под массив данных и под массив указателей.

    Функция fill() получает параметры - указатель на начало массива и размерность матрицы. Тело функции начинается с объявления ее локальных переменных, переменная k получает начальное значение при объявлении.

    Далее в функции организуются вложенные циклы для перебора строк и столбцов. Но номера строки и столбца используются не для обращения к элементам матрицы, а только для проверки, попадает ли элемент в нулевую или ненулевую область (в точном соответствии условиям, приведенным в п.5.2). Обращение к элементам матрицы ведется через указатель C, который указывает на текущий элемент матрицы. Этот указатель устанавливается на начало массива в начальных установках внешнего цикла и увеличивается на 1 в конце каждой итерации внутреннего цикла.

    Полный текст программы приведен ниже.

/***************************************************/

/* Лабораторная работа 11 */

/* Функции */

/* Пример выполнения. Вариант ╧30. */

/* Вариант реализации 2 */

/***************************************************/

#include <iostream>

#include <iomanip>

#include <stdio.h>

#include <conio.h>

#include <math.h>

#include <stdlib.h>

using namespace std;

void fill(int **, int);

/*** главная функция ***/

int main()

{

int **Ar; /* указатель на массив указателей */

//int a;

int i, j; /* строка и столбец */

const int S=9; /* размерность матрицы */

/* выделение памяти для массива указателей */

Ar=new int* [S];

/* выделение памяти для каждой строки

и заполнение массива указателей */

for (i=0; i<S; i++)

Ar[i]=new int[S];

/* обращение к функции заполнения матрицы */

fill(Ar,S);

/* вывод матрицы */

for (i=0; i<S; i++) {

for (j=0; j<S; cout<<setw(5)<<Ar[i][j++]);

cout<<endl;

}

/* освобождение памяти строк */

for ( i=0; i<S; delete Ar[i++] );

/* освобождение памяти массива указателей */

delete [] Ar;

getch();

return 0;

}

/*** функция заполнения матрицы ***/

/* параметры: A - указатель на массив указателей

s - размерность матрицы */

void fill(int **A, int s) {

int l, r; /* строка и столбец */

short k=1; /* текущий член ЛП */

for (l=0; l<s; l++) /* перебор строк */

for (r=0; r<s; r++) /* перебор столбцов */

/* условие нулевого значения */

if ((r>=max(l,s-l-1))||(r<=min(l,s-l-1)))

A[l][r]=0;

else A[l][r]=k++;

/* конец перебору строк */

/* конец перебору столбцов */

}

}