Использование процедур break и continue
В циклах For, While и Repeat можно использовать две стандартные процедуры Break и Continue. Процедура Break позволяет досрочно выйти из цикла, не дожидаясь выполнения условия выхода. Процедура Continue позволяет начать новую итерацию цикла, даже если предыдущая не завершена.
ПРИМЕР 7
Пусть с помощью генератора случайных чисел генерируется некоторый ряд чисел k в диапазоне –n <= k <= n. Организовать список чисел до первого сгенерированного отрицательного числа включительно. Форма для этого примера приводится на рис. 22.
Рис. 22 Форма к примеру 7.
На этой форме в виде трёх чёрных прямоугольничков изображена метка, с помощью которой отображается ситуация, когда не задан диапазон n. Все остальные размещённые на форме компоненты указаны в тексте программы, который приводится ниже.
В примере используется новый компонент TComboBox – свернутый список. Этот элемент представляет собой свернутый TListBox. Для того, чтобы просмотреть список необходимо раскрыть его, например, с помощью мыши. Список TComboBox состоит собственно из списка и редактируемого поля. В редактируемом поле может находиться либо какая-нибудь строка из списка или какая-нибудь строка, которую необходимо поместить в список. Доступ к строке редактирования осуществляется с помощью свойства Text. Доступ к любому элементу списка осуществляется с помощью Items.Strings (свойство Items, Strings задаёт тип этого свойства), а для указания номера строки i используются квадратные скобки [i].
Генерирование числа осуществляется с помощью функции Random(L) – функция генерирует случайные числа от 0 до L-1. Для инициализации генератора случайных чисел используется процедура Randomize. Она инициализирует генератор, т. е. дает точку отсчета для случайных чисел.
unit prim7;
Interface
uses Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs,
StdCtrls, Buttons, ExtCtrls;
Type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
BitBtn1: TBitBtn;
Bevel1: TBevel;
Label1: TLabel;
Label2: TLabel;
Edit1: TEdit;
ComboBox1: TComboBox;
Label3: TLabel;
procedure Edit1KeyPress(Sender: TObject;
var Key: Char);
procedure Button1Click(Sender: TObject);
procedure Edit1Exit(Sender: TObject);
end;
var Form1: TForm1;
Implementation
{$R *.DFM}
procedure TForm1.Edit1KeyPress(Sender: TObject;
var Key: Char);
begin
if not (key in ['0'..'9',#8]) then key:=#0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var k,i,n:integer;
begin
if Length(Edit1.Text)=0 then Edit1.Text:='0';
if Edit1.Text='0' then begin
Label3.Caption:='Нет диапазона n';
ComboBox1.Visible:=false;
end else begin
ComboBox1.Visible:=true;
ComboBox1.Clear;
Label3.Caption:='';
n:=StrToInt(Edit1.Text);
Randomize;
i:=0;
While true do begin
k:=Random(2*n + 1) - n ;
inc(i);
ComboBox1.Items.Add(IntToStr(i)+'-е число= '+
IntToStr(k));
if k>=0 then Continue else begin
ComboBox1.Text:=ComboBox1.Items.Strings[i-1];
Break;
end;
end;
end;
end;
procedure TForm1.Edit1Exit(Sender: TObject);
begin
if Abs(StrToInt(Edit1.Text))>100 then
if Application.MessageBox('Введите число X','
Число |X| < 100 ',MB_OK)=IDOK then Edit1.SetFocus;
end;
End.
В данном случае используется бесконечный цикл While true…. Если очередное полученное число k неотрицательно, то осуществляется переход на начало цикла – процедура Break не выполняется. Если значение k станет отрицательным, то сначала в заголовок интерфейсного элемента ComboBox1 заносится последнее значение числа k (так как нумерация строк в списке начинается с 0, последняя строка имеет номер i-1), а затем уже выполняется процедура выхода из цикла Break.
В данной программе приведен пример использования свойства Visible. Если значение этого свойства равно false (ComboBox1.Visible:=false), то соответствующий объект не отображается на экране. Чтобы вернуть его изображение, надо свойству Visible присвоить true.
Назначение обработчика Edit1Exit – вернуть фокус на ввод числа n, если не соблюдается условие примера n £ 100. Оформлен он так же, как и соответствующий обработчик в примере 6.
МАССИВЫ
Массив представляет собой фиксированное количество однотипных компонентов, снабженных индексами. Массивы соответствуют, например, векторам (одномерный массив), матрицам (двумерный массив)и др.
СТАТИЧЕСКИЕ МАССИВЫ
Тип статического массива объявляются следующим образом: Type <Имя> = Array[<тип индекса>] of <тип элеметов>;Например, Type Vekt = Array [1..10] of byte;
В данном случае задан одномерный массив (вектор) состоящий из 10-ти элементов целого типа byte. Отдельные элементы этого массива в программе определяются с помощью индексов, например, если объявлено Var X: vekt;,то в выражениях можно использовать X[1], X[2], ... , X[10].В квадратных скобках указывается значение индекса, т.е. номер компонента в массиве. Отсчет номеров ведется так, как указано в индексе при объявлении. Пусть объявлено: Var Z: array [-2..2] of integer;- это значит заданы элементы Z[-2], Z[-1], Z[0], Z[1], Z[2] целого типа integer.
В общем случае тип индекса может быть любым порядковым типом. Так, в примере Var Y: array [‘A’..’Z’] of integer;объявлено 26 элементов (по количеству букв в английском алфавите): Y[‘A’], Y[‘B’], ..., Y[‘Z’], выделено 26 ячеек памяти, в которые можно записывать данные типа integer, например Y[‘C’]:=5;. Информацию можно также считывать из этих ячеек памяти - A:=cos(PI + Y[‘C’]);.
Индекс можно определять и таким способом: Var Y:array[Char] of single;,т.е. определено 256 ячеек памяти, в которые можно записывать вещественные числа. Однако имеется ограничение при объявлении массивов: размер памяти, занимаемый одним массивом не должен превышать 2 Гбайта. Так объявление var X:array[LongInt] of integer;синтаксически верно, но превышен размер памяти, который должен быть выделен для этого массива (более 2 Гбайт).
Аналогичные правила действуют и для двумерных массивов, – например, объявление Var A: array[1..2, 1..3] of double;определяет двумерный массив (матрицу), который содержит 2 строки и 3 столбца (всего 6 элементов). Эти элементы записываются в памяти следующим образом: A[1,1], A[1,2], A[1,3], A[2,1], A[2,2], A[2,3], т.е. сначала первая строка матрицы, а затем вторая. Этот массив можно определить и так: A: array[1..2] of array[1..3] of real; или
Type Vekt = array[1..3] of real;
Var A: array[1..2] of vekt;
Разрешается объявлять и использовать многомерные массивы (до семимерных включительно).
Для массивов можно задавать типизированные константы, т.е. задавать начальные значения элементам массива. Например, требуется задать в памяти значения элементов вектора q= (5.2, 6.0, -3.1, 0.8). Это можно осуществить следующим образом: Const q:array[1..4] of real=(5.2,6.0,-3.1,0.8);.
Начальные значения для двумерного массива, например матрицы , можно задать следующим способом:
Type Matr= array[1..2, 1..3] of byte;
Var R:Matr=((3, 7, 5), (8, 11, 6));
При задании значения индекса для элемента какого-либо массива можно использовать выражение соответствующего типа, указанного при объявлении. При этом необходимо следить, чтобы значение этого выражения не выходило за объявленные границы. Например, для элемента объявленной выше матрицы R можно записать R[Succ(i),Pred(j)] (табл. 2), необходимо лишь, чтобы выполнялись для заданной матрицы R условия: 1 £ Succ(i) ³ 2 и 1 £ Pred(j) ³ 3.
Если задан массив символов, то типизированную константу можно определять следующим образом:
Const C: array[1..5] of Char= ‘abcde’;
Если два или более массивов имеют один тип, т.е. объявлены с помощью одного описания, то эти массивы можно присваивать друг другу. Например, если объявлено
Type V= array[1..5] of real;
Var A,B:V;, то можно записывать A:=B;.
Однако при следующем описании тех же переменных A и B
Var A:= array[1..5] of real; B:= array[1..5] of real;
записывать A:= B; нельзя.
ДИНАМИЧЕСКИЕ МАССИВЫ
Динамический массив, в отличие от статического, объявляется как ссылка на некоторый адрес, по которому будут размещаться данные, например,
Var V = array of real; VI = array of integer;
Каждая из объявленных переменных (V или VI) может иметь значение какого-то адреса. Прежде чем располагать данные, этот адрес переменная должна получить. Память под данные выделяется процедурой SetLength: SetLength(V,5);
SetLength(VI,10);
В данном случае объявлено 5 элементов одномерного массива вещественных чисел V и 10 элементов массива целых чисел VI. Нужное количество памяти выделится процедурой SetLength, эта же процедура присвоит конкретные значения адресов переменным V и VI.
Имеются особенности в использовании динамических массивов. Первая – нумерация индекса всегда начинается с нуля. Вторая особенность касается правил присваивания, например, пусть объявлено: Type Vekt = array of real; Var V1,V2:Vekt;Присваивание V1:=V2; для статических массивов означает, что содержимое памяти V1 заменяется содержимым памяти V2 (элементы массива V1 получили значения элементов V2). Если учесть, что в данном случае V1 и V2 являются ссылками (адресами), поэтому адрес V1 заменяется на адрес V2. Таким образом, для динамических массивов присваивание V1:=V2; означает, что V1 и V2 ссылаются теперь на один и тот же участок памяти, т.е. элементы массива V1 равны элементам V2, но потерялся адрес V1, соответственно потерялся и выделенный участок памяти, начиная с адреса V1. Освободить память, выделенную под V1 можно, вызвав перед операцией присваивания V1:=V2;процедуру Finalize: Finalize(V1);или просто, присвоив V1:=nil;.
Динамические массивы могут быть и многомерными, например, объявив Var VV:array of array of real;.Далее в программе можно задать размерности массива SetLength(VV,5,10);
Динамические массивы позволяют, например, создавать треугольные матрицы, имеющие различные размерности индексов. Интерес к таким массивам в вычислительной математике очень большой. Для создания таких массивов сначала нужно задать размерность по первому индексу, например для объявленного выше двумерного массива VV так: SetLength(VV,3);.Это означает, что массив будет состоять из 3 строк. Теперь длину каждой строки зададим отдельно:
SetLength(VV[0],1); SetLength(VV[1],2);
SetLength(VV[2],3);
Если требуется освободить память из-под такого массива, то используется один вызов процедуры Finalize или одно присваивание VV:=nil;
Начальный и конечный индексы динамического одномерного массива V можно определять функциями Low(V) (равно 0) и High(V), как, например, в следующем операторе
For i:=Low(V) to High(V) do . . . ;
ПРИМЕР 8
Задан одномерный массив чисел X = (0,2; 0,7; 1,8; 3,1; 4,2). Получить таблицу косинусов для этих чисел, т.е. рассчитать cos(0,2), cos(0,7), ... cos(4,2). На рис. 23 представлен вариант решения этого примера.
Рис. 23 Форма с вариантом решения примера 8.
Для решения задачи был использован новый компонент TStringGrid (таблица строк), который находится на странице Additional палитры компонентов. Данный компонент представляет собой двумерную таблицу строк. Количество строк задается свойством RowCount, а количество столбцов - ColCount. Размеры одной ячейки таблицы на экране задаются свойствами DefaultColHeightи DefaultRowWidth в пикселах. Компонент может использоваться для имитации чего-либо похожего на таблицу. Доступ к отдельной ячейке таблицы осуществляется с помощью свойства Cells[i,j], где i-номер столбца, j-номер строки. Отсчет номеров столбца и строки начинается с нуля. Часть строк и столбцов, используемых в таблице, можно зафиксировать. Тогда они будут недоступны пользователю. Для этого нужно задать свойство FixedRows и FixedCols (фиксированное количество строк и столбцов). Фиксированные колонки и строки закрашиваются в другой цвет. Используются они для заголовков. С помощью свойства goEdit можно запретить или разрешить редактирование ячеек таблицы.
В данном примере для StringGrid1 установлено: ScrollBars = ssNone, RowCount = 6, ColCount = 3, FixedRows = 1, FixedCols = 1, GoEdit = false.Ниже приводится программа решения данного примера 8.
unitprim8;
Interface
uses Windows, Messages, SysUtils,Classes,
Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons, ExtCtrls, Grids;
Type
TForm1= class(TForm)
Panel1: TPanel;
Button1: TButton;
BitBtn1: TBitBtn;
StringGrid1: TStringGrid;
procedure Button1Click(Sender: TObject);
end;
var Form1: TForm1;
Implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
const n=5;
x:array [1..n] of real =(0.2,0.7,1.8,3.1,4.2);
var i:integer;
begin
for i:=1 to n do
StringGrid1.Cells[0,i]:=IntToStr(i)+' элемент';
StringGrid1.Cells[1,0]:=' x';
StringGrid1.Cells[2,0]:=' cos(x)';
for i:=1 to n do begin
StringGrid1.Cells[1,i]:=
FormatFloat(' 0.0',x[i]);
StringGrid1.Cells[2,i]:=
FormatFloat(' 0.0000',cos(x[i]));
end;
end;
End.
СТРОКИ
В Delphi существует 5 типов строк:
¨ ShortString – короткая строка;
¨ AnsiString – длинная строка;
¨ WideString – длинная строка в кодировке UNICODE;
¨ String – универсальная строка;
¨ PChar – строка, оканчивающаяся нулевым кодом (#0), введена для совместимости с другими языками программирования (такие строки используются в С++ и Windows).
Переменная PChar – это ссылка на строку. Строки типа PChar размещаются в динамической памяти. Динамическая память – это свободная память, которая остается после загрузки программ и данных. Программный элемент получает её в процессе выполнения программы, а не на этапе компиляции (статическая память). Переменная типа PChar – это ячейка памяти, содержащая адрес строки. По этому адресу записываются необходимые данные. Компилятор выделяет под переменную PChar всего 4 байта, а сама строка, которая размещается по адресу, записанному в эти 4 байта, может быть любой длины. Если строки не существует, а переменная PChar объявлена, то в эту переменную необходимо записать nil (пустой адрес).
Переменные типа AnsiString содержат динамические строки символов в ANSI кодировке. Соответственно переменные типа WideString содержат динамические строки символов в кодировке UNICODE. Динамические – это означает, что переменные указанных типов, как и тип PChar, являются адресами, т.е. ссылками на память с соответствующим типом данных.
ShortString – это фактически массив: array [0..255] of char.Память в данном случае выделяется в 256 байт, а строка размещается динамически, т.е. через адрес. Символы строки содержатся в байтах с первого по 255. В байте с номером 0 содержится символ, порядковый номер которого представляет собой число фактически имеющихся в строке символов. Данный тип ShortString введён для совместимости с более ранними версиями языка Pascal.
Строка String в зависимости от директивы компилятора {$Н} может совпадать с AnsiString ({$H+} установлено по умолчанию), или с ShortString({$H-}).
Для строки String можно задавать максимальное количество символов с помощью следующего объявления: var str: String[25];,т.е. строка str может содержать не более 25 символов и в памяти она занимает 26 байт (не считая “накладные расходы”).
Доступ к строке может осуществляться посимвольно, так как все символы в строке проиндексированы. В строке PChar символы нумеруются, начиная с 0, в остальных строках, - начиная с 1. Например, пусть объявлено:
Var str1: String; str2: PChar;и выполнены присваивания: str1:=’Pascal’; str2:= ’Pascal’; - тогдаstr[1] представляет символ ‘P’, а str2[1] – символ ‘a’.
Со строками возможны операции конкатенации (сложения) и сравнения. Складываются строки, используя знак ‘+’. При сравнении строк действия выполняются слева направо в соответствии с ANSI кодами отдельных символов. Например код А меньше чем а. Если строки разной длины, то короткая строка дополняется справа, причем код, который участвует в дополнении строки, меньше кода любого символа, существующего в ANSI кодировке.
Для выполнения различных операций над строками существует множество подпрограмм (табл. 11).
Таблица 11