Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ситкин. Информатика. Программирование в DELPHI

.pdf
Скачиваний:
142
Добавлен:
18.07.2019
Размер:
1.49 Mб
Скачать

начало

nx = число элементов i = 0

нет

i nx 1

да

ввод xi

i = i + 1

произведение эл-ов Px

вывод Px

конец

Рис. 8.5

implementation

{$R *.dfm}

procedure M(var P:real; m:array of real);

var k:byte;

begin

P:=1;

for k:=0 to high(m) do P:=P*m[k];

end;

procedure TForm1.Button1Click(Sender:TObject);

var x:array of real; nx, i:byte; Px:real;

begin

nx:= Memo1.Lines.Count; //число строк (т.е. эл-ов)

SetLength(x, nx); //выделение памяти под массив х for i:=0 to nx-1 do //в цикле один оператор

x[i]:=StrToFloat(Memo1.Lines[i]);//конец цикла

M(Px, x); //вызов процедуры с передачей ей массива

Label3.Caption:=FloatToStr(Px);

SetLength(x,0); //высвобождение памяти

end;

Вторая процедура TForm1.Button2Click аналогична TForm1.Button1Click.

Целесообразность выделения памяти под массивы

Выше говорилось, что, при написании проектов для работы с массивами, целесообразно использовать динамические массивы для рационального расходования памяти. Но в некоторых случаях хра-

нить в памяти в виде массива набор однотипных переменных, над ко-

торыми выполняются одинаковые действия, не нужно и вовсе.

101

В примере 8.1 массив, в который считывались числа из компонента Memo, можно не объявлять, т.к. в условиях поставленной задачи нет необходимости хранить в памяти все числа одновременно. Для реализации алгоритма (рис. 8.2) достаточно объявить отдельную переменную x, в которую в цикле будет записываться очередной элемент из Memo, затем x проверяется на отрицательность и выводится в компонент Label3. На следующей итерации переменная x получит новое значение, старое при этом потеряется, но оно уже было выведено

вLabel3 на предыдущей итерации, хранить его в памяти не нужно. Т.е.

втексте вместо x[i] писать x, а массив array[1..m] of real не объявлять.

Однако в примере 8.2 в обеих процедурах TForm1.Button1Click и TForm1.Button2Click память под массивы выделить нужно. Это связано с тем, что каждый из массивов значений, введённых с компонентов

Memo, передаётся целиком в процедуру вычисления произведения.

Контроль синтаксиса элементов массива

Контролировать синтаксис массива чисел, вводимого, например, с компонента Memo, конструкциями, рассмотренными в работе № 6, нельзя, т.к. чисел несколько, запятых и знаков минуса допускается несколько в компоненте. В таких случаях полезна стандартная процедура Val(S, V, Cod), она преобразовывает строку S (тип String) в число, возвращаемое в параметре V (тип Integer или Real). Если в числе нет синтаксических ошибок, то Cod возвращает значение ноль, иначе код ошибки. В качестве десятичного разделителя в процедуру Val

нужно передавать символ «.». Следует в цикле подставить в Val каждое число из строки Memo, в случае ошибки (Cod 0) досрочно завершить процедуру, если ошибки нет, то число будет записано в память.

102

Задание

Разработать проект для ввода двух массивов и для каждого

1.Найти наименьший элемент и указать его положение.

2.Найти суммы отрицательных и положительных элементов.

3.Найти сумму и число чётных элементов целочисленного массива. 4.Удвоить нечётные элементы целочисленного массива, сосчитать их.

5.Найти среднее арифметическое значение элементов.

6.Пронормировать элементы относительно наибольшего элемента.

7.Умножить чётные элементы целочисленного массива на задаваемое пользователем число.

8.Найти сколько положительных и отрицательных элементов.

9.Определить положение заданной фамилии.

Использовать динамические массивы и подпрограмму с откры-

тым массивом для выполнения типового действия с массивами.

Содержание отчёта

цель работы и задание;

блок-схема алгоритма типового вычисления;

блок-схема алгоритма выполнения основных действий;

текст модуля проекта;

пример работы приложения с указанием компонентов формы;

выводы по работе.

Контрольные вопросы

1.Что такое массив, каковы его характеристики и способы описания?

2.Чем отличается динамический массив от обычного (статического)?

3.Что понимают под словами «эффективное расходование памяти»?

4.Каково назначение открытого параметра-массива подпрограммы?

103

Лабораторная работа № 9

МНОГОМЕРНЫЕ МАССИВЫ. ВЛОЖЕННЫЕ ЦИКЛЫ

Цель работы приобретение умений разработки и программной реализации алгоритмов обработки многомерных массивов с использованием конструкций вложенных циклов.

Объявление многомерных массивов

Всё сказанное относительно описания одномерных массивов справедливо и для многомерных, с учётом изменения в количестве индексов. Рассмотрим примеры объявления двумерных массивов.

1. Через объявление переменной

var x:array[1..10, 1..10] of byte; //массив из ста элементов целого типа

2. Через объявление типа данных и переменной этого типа type mass = array[1..5, 1..7] of integer;

var x:mass; //массив из тридцати пяти элементов целого типа

3. С использованием имён констант const m=0; n=5;

type matr = array[m..n, n..n] of single;

var x:matr; //массив из 66-ти вещественных переменных (элементов)

4. Динамический массив var x:array of array of real;

или

type dyn_matr = array of array of real; var x:dyn_matr;

Как и в случае одномерных массивов, память под динамический двумерный массив выделяется во время работы программы процедурой

104

SetLength( имя_массива , число строк , число столбцов ); нижний индекс для любого измерения динамического массива равен нулю.

Память может быть выделена под непрямоугольный массив (т.е.

под структуру, неэквивалентной матрице)

SetLength(x, n); //задание размерности по первому индексу (число строк)

SetLength(x[0], n1); //задание длины первой строки (нумерация от нуля)

SetLength(x[1], n2); //задание длины второй строки

……………………

SetLength(x[n 1], nn); //задание длины последней строки

Обращение к элементу массива записывают с указанием имени массива с номерами индексов через запятую в квадратных скобках,

например: x[1,1]; x[i, j]; x[i+1, j] и т.п.

Обработка многомерных массивов

Для обработки многомерных массивов обычно требуется орга-

низовать перебор индексов. При этом при изменении одного индекса,

другие тоже должны пробегать ряд значений. В случае двумерного массива, эквивалентного матрице m n, для каждого из значений пер-

вого индекса от 1 до m, второй также должен последовательно при-

нять ряд значений от 1 до n (рис. 9.1).

 

 

 

 

 

 

 

 

 

В памяти компьютера элементы

 

 

 

второй индекс

 

 

 

 

 

 

 

 

 

 

j =1..n

 

 

многомерного массива располагаются

первыйиндекс =1..i m

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

xm1

 

xm2

 

xm3

xmn

 

 

x11

 

x12

 

x13

x1n

последовательно таким образом, что

 

x21

 

x22

 

x23

x2n

при переходе от одного элемента к со-

 

x31

 

x32

 

x33

x3n

 

 

 

 

 

седнему в первую очередь возрастает

 

 

 

 

 

 

 

 

 

самый правый индекс.

 

 

 

 

 

Рис. 9.1

 

 

 

 

 

 

105

Пример 9.1

Разработаем алгоритм заполнения элементов двумерного масси-

ва размером m n (рис. 9.1) случайными вещественными числами.

На рис. 9.2 изображена схема реализации с оператором цикла с предусловием, вложенным в оператор цикла с предусловием.

начало

m= n=

i = 1

нет

im

да

 

j = 1

 

j n

нет

 

да

xij = случ. вещ. число 0..1

j = j + 1

i = i + 1

const m= ; n= ;

var x:array[1..m, 1..n] of real;

i, j: byte;

begin

randomize;

i:=1; //первая строка

while i<=m do //внешний цикл

begin //перебор строк

j:=1; //переход к 1-му столбцу i-ой строки while j<=n do //внутренний цикл

begin //перебор столбцов

x[i,j]:=random;

j:=j+1; //переход к следующему столбцу end; //конец тела внутреннего цикла i:=i+1; //переход к следующей строке

end; //конец тела внешнего цикла

end; //конец процедуры

{выделенную рамкой часть можно заменить на} for i:=1 to m do //цикл перебора строк, а в нём for j:=1 to n do //цикл перебора столбцов

конец

x[i,j]:=random;

 

Рис. 9.2

{реализует ту же схему, но запись компактнее}

 

106

На рис. 9.3 изображена схема реализации примера с оператором цикла с постусловием, вложенным в оператор цикла с постусловием.

начало

m= n=

i = 1

j = 1

xij = случ. вещ. число 0..1

const m= ; n= ;

var x:array[1..m, 1..n] of real; i, j: byte;

begin randomize;

i:=1; //первая строка

repeat //внешний цикл перебор строк j:=1; //первый столбец i-ой строки

repeat //внутренний цикл перебор столбцов

x[i,j]:=random;

 

 

 

j:=j+1; //переход к след. столбцу i-ой строки

 

 

j = j + 1

 

 

until j>n; //конец внутреннего цикла

 

 

 

 

 

 

i:=i+1; //переход к следующей строке

 

 

 

нет

j n

until i>m; //конец внешнего цикла

 

 

 

 

 

 

 

да

end; //конец процедуры

 

 

i = i + 1

Во всех вариантах, после того как пере-

 

 

 

 

 

 

браны все элементы строки (т.е. все столб-

 

 

 

нет

i m

цы), происходит выход из внутреннего цикла

 

 

 

 

 

да

и переход к следующей итерации внешнего

 

 

 

 

 

конец

цикла с увеличением первого индекса на

 

 

 

 

 

Рис. 9.3

единицу, т. е. переход к новой строке. И при

 

 

 

этом в начале новой итерации внешнего цикла второй индекс прини-

мает значение единица, чтобы переход был к началу этой новой стро-

ки. Отметим также, что рассматривался статический массив, память под его элементы выделялась во время компиляции.

107

Компонент StringGrid

вкладка additional

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

вания двумерных массивов. Пиктограмма компонента расположена на вкладке Additional палитры компонентов. Основные свойства компонента StringGrid представлены в табл. 9.1.

 

 

 

 

 

Таблица 9.1

 

Основные свойства компонента StringGrid

 

 

 

 

 

 

 

 

Свойство

 

 

Описание

 

 

Name

 

Имя компонента. Используется для доступа к

 

 

компоненту и его свойствам

 

 

 

 

 

 

ColCount

 

Количество столбцов

 

 

RowCount

 

Количество строк

 

 

 

 

Ячейка таблицы на пересечении столбца номер

 

Cells

 

Col и строки номер Row, определяется элемен-

 

 

том Cells[Col, Row]. Нумерация столбцов и

 

 

 

 

 

 

строк в компоненте осуществляется от нуля

 

FixedCols

 

Количество зафиксированных слева столбцов

 

FixedRows

 

Количество зафиксированных сверху строк

 

+Options.goEditing

 

True/False Возможность редактирования со-

 

 

 

держимого ячеек во время работы приложения

 

.goTabs

 

True/False Возможность использования кла-

 

 

 

виши Tab для перемещения курсора

 

DefaultColWidth

 

Ширина столбцов

 

 

DefaultRowHeight

 

Высота строк

 

 

 

GridLineWidth

 

Ширина линий, разделяющих ячейки

 

+ Font

 

Характеристики шрифта текста

 

 

ParentFont

 

True/False

Наследование

характеристик

 

 

шрифта текста формы

 

 

 

 

 

 

Enabled

 

True/False Доступность компонента

 

Visible

 

True/False Видимость компонента

Матрица, введённая с компонента StringGrid по схеме Cells[i, j] x[i, j] будет транспонирована в памяти относительно компонента, т.к.

в свойстве Cells[Col, Row] первым указывается номер столбца.

108

кнопка обработки массива доступна
конец
ошибка
или n 2 нет
число столбц.= n число строк = n таблица видна
ввод размера n матрицы c проверк. синтаксиса
начало
кнопка обработки массива недоступна
ошибка ввода размера матрицы
Enabled

Продемонстрируем алгоритм считывания элементов из компонента StringGrid в память в виде двумерного массива, а также органи-

зацию вывода его элементов на форму следующим примером.

Пример 9.2

Разработаем проект для удвоения элементов главной диагонали и транспонирования квадратной матрицы задаваемого размера.

Разобьём задачу на две части: ввод размера матрицы (компонент

Edit1) с формированием в соответствии с ним таблицы для ввода значений элементов массива (событие Button1Click) и его обработку с выводом результатов (событие Button2Click). Разместим на форме компонент StringGrid, число фиксированных строк и столбцов назначим по нулям. Для возможности ввода и редактирования значений элементов во время работы приложения установим значение True свойства Options.goEditing. Назначим значения False свойств Visible для StringGrid и

для Button2. Это значит, что после запуска приложения, таблица StringGrid на форме будет визуально отсутствовать, а кнопка Button2 недо-

ступна. Это исключит возможность

ввода элементов массива и его обра-

да

ботки до программного изменения этих значений на True. Произведём их по-

сле ввода пользователем допустимого размера матрицы в Edit1 и щелчка по Button1. На рис. 9.4 представлена блок-

схема алгоритма выполнения первой

части задачи (событие Button1Click).

Рис. 9.4

109

начало

 

 

 

1

 

Во второй части (событие But-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ton2Click) введённые в компонент

номер строки

 

 

 

ошибка

 

 

 

 

 

 

 

 

 

 

i = 0

 

 

 

синтаксиса

StringGrid

элементы

в

конструкции

 

 

 

 

в матрице

 

 

 

 

 

 

 

 

 

 

 

 

вложенных циклов считываются в

i n 1

 

нет

 

 

 

память после проверки синтаксиса

 

 

 

 

да

 

 

 

 

каждого

элемента

во

вложенном

номер столбца

 

 

 

конец

цикле (рис. 9.5). Затем происходит

j = 0

 

 

 

 

 

 

 

 

 

удвоение элемента,

если он лежит

 

 

нет

 

j n 1

 

 

на главной диагонали, вывод эле-

 

 

 

 

да

 

 

 

 

мента,

например,

в

компонент

 

 

 

 

 

 

 

 

 

 

 

 

ввод xij эл-та

 

 

 

 

Label2, для которого

установим

c проверкой

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

синтаксиса

 

 

 

 

значение

True

свойства

AutoSize,

ошибка

да

1

т.к. заранее размер матрицы неиз-

синтакси-

 

 

 

 

 

 

 

 

 

 

са

 

 

 

 

вестен. После выхода из вложенно-

нет

 

 

 

 

 

 

 

 

 

 

 

i = j

нет

 

го цикла, при переходе к следую-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

да

 

 

 

 

щей

строке,

выполним

перевод

 

 

 

 

 

 

 

 

 

 

 

xij = 2xij

 

 

 

 

строки вывода в компоненте Label2

 

 

 

 

для сохранения матричной струк-

 

 

 

 

 

 

 

 

 

 

туры

представления

результата.

вывод xij

 

 

 

 

 

 

 

i = i + 1

 

 

 

Поскольку значение переменной n,

 

 

 

 

 

содержащей размер матрицы, ис-

 

 

 

 

перевод

j = j + 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

строки

пользуется в обеих процедурах, её

 

 

 

 

вывода

 

 

 

 

 

 

 

 

 

 

 

 

следует объявить как глобальную,

Рис. 9.5

 

 

т.е. вне процедур. На рис. 9.6 и 9.7

представлены примеры работы приложения.

IMPLEMENTATION

{$R *.dfm}

var n:integer; //объявлена как глобальная (внутри модуля) переменная

110