While (abs(a) > e) do begin

n:=n+1;

a:=-a*x/n;

s:=s+a;

end;

y:=exp(-x);

Memo1.Lines.Add('при x='+FloatToStrF(x,ffFixed,6,2)+' сумма ='

+ FloatToStrF(s,ffFixed,8,4)+’ y ='

+ FloatToStrF(y,ffFixed,8,4)+' N ='+IntToStr(n));

x:=x+h;

untilx>(xk+h/2) // (xk+h/2) применяется для исключения

end; // потери последнего x

 

end.

3.4. Выполнение индивидуального задания

По указанию преподавателя выберите вариант задачи. Нарисуйте схему алгоритма. Спроектируйте панель диалога и напишите текст программы.

Вывести на экран таблицу значений функции y(x) и ее разложения в ряд s(x) для x изменяющихся от xn до xk с заданным количеством шагов M ( ) и точностью e. Близость значений S(x) и Y(x) во всем диапазоне значений x указывает на правильность вычисления S(x) и Y(x).

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

 

Таблица 3.1.
S(x) e Y(x)
  1.   0.1     0.001  
      Окончание табл. 3.1
  2.   0.1     0.0001
  3.   0.1     0.001
  4.   0.1     0.01  
  5.   0.1   0.7   0.001
  6.   0.1     0.0001
  7.   0.2     0.001  
  8.   0.1   0.7   0.0001  
  9.   0.3     0.001
  10.   0.1   0.5   0.0001  
  11.   0.2     0.001
  12.   0.1       0.0001  
  13.   -2   -0.1   0.01
  14.   0.2   0.8   0.0001
  15.   0.1   0.8   0.001  

 


 

Тема 4. Обработка исключительных ситуаций. Программирование с использованием массивов

Цель лабораторной работы: изучить свойства компонента TStringGrid. Написать программу с использованием массивов.

4.1. Обработка исключительных ситуаций

Под исключительной ситуацией понимается некое ошибочное состояние, возникающее при выполнении программы и требующее выполнения определённых действий для продолжения работы или корректного ее завершения. Стандартный обработчик (метод TApplication.HandleException), вызываемый по умолчанию, информирует пользователя о возникновении ошибки и завершает выполнение программы. Для защиты от завершения в языке Object Pascal используется оператор try, который перехватывает исключительную ситуацию и дает возможность разработчику предусмотреть определенные действия при ее возникновении.

Конструкция блокаtry… finally:

Try

<операторы, выполнение которых может привести

к возникновению исключительной ситуации>

Finally

<операторы, выполняемые всегда, вне зависимости

от возникновения исключительной ситуации>

end;

При возникновении исключительной ситуации в одном из операторов управление сразу передается первому оператору блока finally.

Данная конструкция позволяет корректно завершить выполнение программы вне зависимости от возникающей исключительной ситуации. Обычно в блок finallyпомещают операторы, закрывающие открытые файлы, освобождающие выделенную динамическую память. Недостатком такой конструкции является то, что программа не информирует о том, возникала ли исключительная ситуация и следовательно не позволяет пользователю ее скорректировать.

Конструкция блокаtry…except:

Try

<операторы, выполнение которых может привести

к возникновению исключительной ситуации>

Except

<операторы, выполняемые только в случае

возникновения исключительной ситуации>

end;

При возникновении исключительной ситуации управление сразу передается в блок except,в противном случаеблокexcept пропускается. Такая конструкция позволяет определить причину возникшей проблемы и рекомендовать пользователю определенные действия для ее исправления. В простейшем случае в разделе except пишутся операторы, выполняемые при возникновении любой исключительной ситуации. Для определения типа возникшей ошибки в разделе except используется конструкция, работающая по схеме оператора case:

on<тип исключительной ситуации 1> do <оператор 1>;

on<тип исключительной ситуации 2> do <оператор 2>;

else<операторы, выполняемые если не определен

тип исключительной ситуации >;

Выполняется только оператор, стоящий после do для реализуемой исключительной ситуации. Некоторые из возможных типов исключительных ситуаций представлены в таблице 4.1.

Таблица 4.1.

Тип исключительной ситуации Причина
EAbort Намеренное прерывания программы, генерируемое процедурой Abort
EArrayError Ошибка при операциях с массивами: использование ошибочного индекса массива, добавление слишком большого числа элементов в массив фиксированной длины (для использования требует подключения модуля mxarrays)
EConvertError Ошибка преобразования строки в другие типы данных
EDivByZero Попытка целочисленного деления на ноль
ERangeError Целочисленное значение или индекс вне допустимого диапазона (при включенной директиве проверки границ массива {$R+})
EIntOverflow Переполнение при операции с целыми числами (при включенной директиве {$Q+ })
EInvalidArgument Недопустимое значение параметра при обращении к математической функции
EZeroDivide Деление на ноль числа с плавающей точкой
EOutOfMemory Недостаточно памяти
EFileNotFound Файл не найден
EInvalidFileName Неверное имя файла
EInvalidOp Неправильная операция с плавающей точкой
EOverFlow Переполнение при выполнении операции с плавающей точкой
EAssertionFailed Возникает при намеренной генерации исключительной ситуации с помощью процедуры Assert (при включенной директиве { $С+ })

Для отладки программы, содержащей обработку исключительных ситуаций, надо отключить опцию Stop on Delphi Exceptions находящуюся в Tools – Debbuger Options … , закладка Language Exceptions (для Delphi 3надо отключить опциюBreak on exception,находящуюся вTools – Environment Options,закладкаPerferences).

Возникновение исключительной ситуации может быть инициировано преднамеренно. Для этого можно использовать процедуры Abort, Assert (b : Boolean)а также с ключевое слово raise:

Raise(<тип исключения>).Create(<текст сообщения>);

4.2. Использование функций ShowMessage и MessageDlg.

Для вывода сообщений полезно использовать функции ShowMessage и MessageDlg, Функция ShowMessage(Msg: string) отображает диалоговое окно с заданным в Msg сообщением и кнопкой OK, для закрытия окна. В заголовке окна отображается имя выполняемой программы. Функция MessageDlg(const Msg: WideString; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Word отображает диалоговое окно с заданными кнопками. Параметр Msg содержит текст сообщения. Параметр DlgType определяет вид отображаемого окна (Таблица 4.2).

  Таблица 4.2.
mtWarning Заголовок: “Warning”. Знак: желтый треугольник с восклицательным знаком внутри
mtError Заголовок: “Error”. Знак: красный круг с перечеркиванием внутри
mtInformation Заголовок: “Information”. Знак: символ “i” на голубом поле.
mtConfirmation Заголовок: “ Confirmation ”. Знак: символ “?” на зеленом поле.
mtCustom Заголовок соответствует имени выполняемого файла. Без знака.

Параметр Buttons указывает, какие кнопки будут находится в окне (Таблица 4.3). Список необходимых кнопок заключается в квадратные скобки.

Таблица 4.3.
mbYes Кнока “Yes” mbRetry Кнока “Retry”
mbNo Кнока “No” mbIgnore Кнока “Ignore”
mbOK Кнока “OK” mbAll Кнока “All”
mbCancel Кнока “Cancel” mbHelp Кнока “Help”
mbAbort Кнока “Abort”    

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

Результатом выполнения функции является значение, соответствующее нажатой кнопке. Возвращаемое значение имеет имя, состоящее из букв mr и имени кнопки, например: mrYes, mrOK, mr Help.

4.3. Работа с массивами

Массив есть упорядоченный набор однотипных элементов, объединенных под одним именем. Каждый элемент массива обозначается именем, за которым в квадратных скобках следует один или несколько индексов, разделенных запятыми, например: a[1], bb[I], c12[I,j*2], q[1,1,I*j-1]. В качестве индекса можно использовать любые порядковые типы за исключением LongInt.

Тип массива или сам массив определяются соответственно в разделе типов (Type) или переменных (Var) с помощью следующей конструкции:

Array[описание индексов] of <тип элемента массива>;

Примеры описания массивов:

Const N=20; // Задание максимального значения индекса;

Type TVector=array[1..N] of word; // Описание типа одномерного массива;

Var a:TVector; // А – массив типа TVector;

Ss:array[1..10] of integer; // Ss – массив из десяти целых чисел;

Y:array[1..5,1..10] of char; // Y – двумерный массив символьного типа.

Элементы массивов могут использоваться в выражениях так же, как и обычные переменные, например:

F:=2*a[3]+a[ss[4]+1]*3;

a[n]:=1+sqrt(abs(a[n-1]));

4.4. Компонент TStringGrid

При работе с массивами ввод и вывод информации на экран удобно организовывать в виде таблиц. Компонент TStringGrid предназначен для отображения информации в виде двумерной таблицы, каждая ячейка которой представляет собой окно однострочного редактора (аналогично окну TEdit). Доступ к информации осуществляется с помощью свойства Cells[ACol : Integer; ARow : Integer] : String, где ACol, ARow - индексы элемента двумерного массива. Свойства ColCount и RowCount устанавливают количество столбцов и строк в таблице, а свойства FixedCols и FixedRows задают количество столбцов и строк фиксированной зоны. Фиксированная зона выделена другим цветом, и в нее запрещен ввод информации с клавиатуры.

4.5. Пример написания программы

Задание: создать программу для определения вектора , где А – квадратная матрица размерностью NxN, а , – одномерные массивы размерностью N.

Элементы вектора определяются по формуле . Значения N вводить в компонент TEdit, А и B – в компонент TStringGrid. Результат, после нажатия кнопки типа TButton, вывести в компонент TStringGrid.

4.5.1. Настройка компонента TStringGrid

Для установки компонента TStringGrid на форму необходимо на странице Additional меню компонентов щелкнуть мышью по пиктограмме . После этого щелкните мышью в нужном месте формы. Захватывая кромки компонента, отрегулируйте его размер. В инспекторе объектов значения свойств ColCount и RowCount установите 4 (четыре строки и четыре столбца), а FixedCols и FixedRows установите 1 (один столбец и одна строка с фиксированной зоной). Т.к. компоненты StringGrid2 и StringGrid3 имеют только один столбец, то у них: ColCount= 1, RowCount=4, FixedCols=0 и FixedRows=1. По умолчанию в компонент TStringGrid запрещен ввод информации с клавиатуры, поэтому для компонентов StringGrid1 и StringGrid2 необходимо в инспекторе объектов раскрыть раздел Options (нажав на знак “+”, стоящий слева от Options) и свойство goEditing установить в положение True.

Панель диалога приведена на рис. 4.1.

 

Рис. 4.1.

Текст программы приведен на Листинге 4.1.

Листинг 4.1.

unitUnit4;

Interface

Uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, StdCtrls, mxarrays;

Type

TForm1 = class(TForm)

Edit1: TEdit;

Edit2: TEdit;

Label1: TLabel;

Label2: TLabel;

Button1: TButton;

StringGrid1: TStringGrid;

StringGrid2: TStringGrid;

Button2: TButton;

StringGrid3: TStringGrid;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure Button2Click(Sender: TObject);

Private

{ Private declarations }

Public

{ Public declarations }

end;

 

Const

Nmax=10; // Максимальный размер массива

Type

Mas2 = array[1..Nmax,1..Nmax] of extended; // Объявление типа

//двухмерного массива размерностью Nmax

Mas1 = array[1..Nmax] of extended; // Объявление типа

//одномерного массива размерностью Nmax

Var

Form1: TForm1;

A : Mas2; // Объявление двухмерного массива

B, Y : Mas1; // Объявление одномерных массивов

N, M, i, j : integer;

 

Implementation

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

Begin

N:=3; // Число строк в массиве

M:=3; // Число столбцов в массиве

Edit1.Text:=FloatToStr(N);

Edit2.Text:=FloatToStr(M);

{Задание числа строк и столбцов в таблицах}

StringGrid1.RowCount:=N+1;

StringGrid1.ColCount:=M+1;

StringGrid2.RowCount:=N+1;

StringGrid3.RowCount:=N+1;

{Ввод в левую верхнюю ячейку таблицы названия массива}

StringGrid1.Cells[0,0]:='Массив A:';

StringGrid2.Cells[0,0]:='Массив B:';

StringGrid3.Cells[0,0]:='Массив Y:';

{Заполнение верхнего и левого столбцов поясняющими подписями}

for i:=1 to N do begin

StringGrid1.Cells[0,i]:=' i= '+IntToStr(i);

StringGrid1.Cells[i,0]:=' j= '+IntToStr(i);

end;

end;

 

procedure TForm1.Button1Click(Sender: TObject); // Изменить размер

begin// таблицы

N:=StrToInt(Edit1.Text);

M:=StrToInt(Edit2.Text);

{Задание числа строк и столбцов в таблицах}

StringGrid1.RowCount:=N+1;

StringGrid1.ColCount:=M+1;

StringGrid2.RowCount:=N+1;

StringGrid3.RowCount:=N+1;

{Заполнение верхнего и левого столбцов поясняющими подписями}

for i:=1 to N do StringGrid1.Cells[0,i]:=' i= '+IntToStr(i);

for i:=1 to M do StringGrid1.Cells[i,0]:=' j= '+IntToStr(i);

end;

 

procedure TForm1.Button2Click(Sender: TObject);

Begin

{$R+}

Try

{Заполнение массива А элементами из таблицы StringGrid1}

for i:=1 to N do

for j:=1 to M do

A[i,j]:=StrToFloat(StringGrid1.Cells[j,i]);

{Заполнение массива B элементами из таблицы StringGrid2}

for i:=1 to N do

B[i]:=StrToFloat(StringGrid2.Cells[0,i]);

Except

on ERangeError do begin ShowMessage('Выход за пределы

массива. Уменьшите размер массива'); Exit; end;

on EConvertError do begin ShowMessage('В ячейке отсутствует

значение, либо число введено не правильно'); Exit; end;

else begin ShowMessage('Возникла неизвестная

исключительная ситуация!'); Exit; end;

end;

Try

{Умножение массива А на массив В}

for i:=1 to N do begin

Y[i]:=0;

for j:=1 to M do Y[i]:=Y[i]+A[i,j]*B[j];

end;

Except

on EInvalidOp do begin MessageDlg('Неправильная операция с плавающей точкой',mtError,[mbCancel],0);Exit; end;

on EOverFlow do begin MessageDlg('Переполнение при выполнении операции с плавающей точкой',mtError,[mbCancel],0); Exit; end;

else begin MessageDlg(‘Возникла неизвестная исключительная ситуация! ',mtError,[mbCancel],0); Exit; end;

end;

{Вывод результата в таблицу StringGrid3}

for i:=1 to N doStringGrid3.Cells[0,i]:=FloatToStrf(y[i],fffixed,6,0);

end;

End.

4.6. Выполнение индивидуальные задания

По указанию преподавателя выберите вариант задачи. Нарисуйте схему алгоритма. Во всех заданиях переменные вводить и выводить с помощью компонента TEdit, массивы – c помощью компонента TStringGrid, в котором 0-й столбец и 0-ю строку использовать для отображения индексов массивов. Вычисления выполнять, после нажатия кнопки типа TВutton. В местах возможного возникновения ошибок использовать конструкции для обработки исключительных ситуаций.

1. Задана матрица размером NxM. Получить массив B, присвоив его k-му элементу значение 0, если все элементы k-го столбца матрицы нулевые, и значение 1в противном случае.

2. Задана матрица размером NxM. Получить массив B, присвоив его k-му элементу значение 1, если элементы k–й строки матрицы упорядочены по убыванию, и значение 0в противном случае.

3. Задана матрица размером NxM. Получить массив B, присвоив его k-му элементу значение 1, если k-я строка матрицы симметрична, и значение 0в противном случае.

4. Задана матрица размером NxM. Определить количество “особых” элементов матрицы, считая элемент “особым”, если он больше суммы остальных элементов своего столбца.

5. Задана матрица размером NxM. Определить количество “особых” элементов матрицы, считая элемент “особым”, если все элементы строки, находящиеся слева от него, меньше его, а справа – больше.

6. Дана матрица размером NxM. Упорядочить ее строки по возрастанию их первых элементов.

7. Дана матрица размером NxM. Упорядочить ее строки по возрастанию суммы их элементов.

8. Дана матрица размером NxM. Упорядочить ее строки по возрастанию их наибольших элементов.

9. Определить, является ли заданная квадратная матрица n-го порядка симметричной относительно побочной диагонали.

10. Задана матрица A, размером NxM. Получить массив B, присвоив его k-му элементу значение максимального элемента в k–от столбце матрицы А.

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

12. В матрице размером NxM поменять местами строку, содержащую элемент с наибольшим значением со строкой, содержащей элемент с наименьшим значением.

13. Из матрицы n-го порядка получить матрицу порядка n-1 путем удаления из исходной матрицы строки и столбца, на пересечении которых расположен элемент с наибольшим по модулю значением.

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

15. Дана матрица размером NxM. Поменять местами все четные и нечетные строки матрицы.


 

ТЕМА 5. Указатели и их использование при работе C динамическими массивАМИ

Цель лабораторной работы: изучить способы работы с динамическими массивами данных.

5.1. Динамическое распределение памяти

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

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

Type

Pukaz=^<тип переменной>;

Pint = ^integer;

TMas = array[1..4] of integer

PMas = ^TMas;

Var

Uk : Pukaz;

a, b : PInt; // Типизированные указатели

p, q : pointer; // Нетипизируемые указатели

U : Pmas; // Указатель на одномерный массив

C : array[1..2,1..2] of integer; // Обычный двумерный массив

Begin

...

U:=Addr(C); // Указателю U присваивается

// адрес статической переменной C

a:=p; // Адрес указателя p комируется в указатель a

p:=Nil; // Очистка адреса

...

Каждая переменная типа указатель (a, b, p, q, u) занимает 4 байта памяти, и сожержит адрес первого байта некоторого участка оперативной памяти, данные на котором интерпретируются в соответствии с объявленным типом. С помощью указателя (адреса) реализуется доступ к данным, расположенным в ячейке с этим адресом, например u^[2]:=3. Более того, появляется возможность интерпретации данных разного пипа, например одномерного массива, как двумерного:

...

c[1,2]:=5; с[2,1]:=8;

u:=@c; // Указателю u присваивается адрес С (@ эквивалентно Addr);

Write(u[2],u[3]); // Распечатается 5 и 8

...

Организация динамического распределния памяти осуществляется в свободной от загруженных программ области оперативной памяти, называемой кучей (heap). Для этого используются процедуры New, Dispose или GetMem, FreeMem.

Процедура

New(var P: Pointer);

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

Dispose(var P: Pointer);

После освобождения адрес в указателе P остается, однако доступ к ячейке с этим адресом запрещен.

Например:

Var a, b : PInt;

Begin

New(a);

b:=a;

a^:=9;

b^:=5

Write(a); // Распечатается 58

Dispose(b);

Здесь выделена память под переменную типа integer. Указать b стал указывать на ту же область памяти, что и указатель a . В выделенную область сначала занесено значение, равное 9, затем туда же значение равное 5. Для освобождения памяти можно использовать как Dispose(b) так и Dispose(a).

ПроцедураGetMem используется при работе как с типизированными, так и с нетипизированными указателями, поэтому задается не только имя указателя, но и объем необходимой памяти в байтах:

GetMem(P:pointer;size:Word);

Процедура

FreeMem(P:pointer;size:Word);

освобождает область памяти, связанную с указателем Р, и имеющую размер, равный size.

Для определения размера, который требуется выделить под переменную обычно пользуются функцией sizeof(<имя типа>).

5.2. Организация динамических массивов

Обычно динамическое выделение и освобождение памяти используется при работе с большими массивами данных.

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

type Tmas = array[1..1000, 1..2000] of byte;

Pmas = ^Tmas

var B : Pmas // Указатель на динамический массив

begin

New(B); .. Выделение памяти

<работа с массивом>

Dispose(B); // Освобождение памяти

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

С помощью процедур Getmem и Freemem можно создавать массивы с изменяемым размером – динамические массивы. Для этого определим тип указателя на массив с небольшим размером, а затем выделим памяти столько, сколько необходимо:

type

Tmas=array[1..1] of extended;

Pmas=^Tmas; // Указатель на массив

Var a : Pmas;

mt, n : word;

begin

mt:=sizeof(extended); // Определение количества байт,

// которое занимает указанный тип данных

GetMem(a,mt*n); // Выделение памяти под n чисел

<работа с массивом размерности n>

FreeMem(a, mt*n); // Освобождение памяти

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

Организация двумерного динамического массива реализуется следующим образом:

Type

TMas = array[1..1] of integer;

PMas = ^TMas;

TMas2 = array[1..1] of PMas;

PMas2 = ^TMas2;

Var

a : PMas2;

N,M,i,j : integer;

Begin

GetMem(a,4*M);

for i:=1 to M do GetMem(a[i],N*sizeof(integer));

// Работа с массивом а[i,j], 1≤i≤M, 1≤j≤N

for i:=1 to M do FreeMem(a[i],N*sizeof(integer));

FreeMem(a,4*M);

5.3. Компонент TBitBtn

Компонент TBitBtn расположен на странице Additonal палитры компонентов и представляет собой разновидность стандартной кнопки TButton. Его отличительная особенность – наличие растрового изображения на поверхности кнопки, которое определяется свойством Clyph. Кроме того, имеется свойство Kind, которое задает одну из 11 стандартных разновидностей кнопок. Кнопка bkClose закрывает главное окно и завершает работу программы.

5.4. Пример написания программы

Задание: Дан массив, состоящий из семи цифр. Упорядочить элементы массива по возрастанию. Панель диалога приведена на рис. 5.1.

 

Рис. 5.1.

Текст программы приведен на Листинге 5.1.

Листинг 5.1.

unit Unit5;

Interface

Uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, Buttons, Grids;

Type

TForm1 = class(TForm)

StringGrid1: TStringGrid;

StringGrid2: TStringGrid;

Label1: TLabel;

Label2: TLabel;

BitBtn1: TBitBtn;

BitBtn2: TBitBtn;

procedure FormCreate(Sender: TObject);

procedure BitBtn1Click(Sender: TObject);

Private

{ Private declarations }

Public

{ Public declarations }

end;

 

const N=7;

 

Type

TMas = array[1..1] of integer;

PMas = ^TMas;

Var

Form1: TForm1;

a : PMas;

i,j,t : integer;

Implementation

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

Begin

Randomize;

for i:=1 to N do

StringGrid1.Cells[i-1,0]:=IntToStr(Random(100));

end;

 

procedure TForm1.BitBtn1Click(Sender: TObject);

Begin

GetMem(a,N*sizeof(integer));

 

for i:=1 to N do

a[i]:=StrToInt(StringGrid1.Cells[i-1,0]);

 

for i:=1 to N-1 do

for j:=i+1 to N do