Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник Емельянов.doc
Скачиваний:
12
Добавлен:
03.11.2018
Размер:
3.25 Mб
Скачать

Динамические массивы

Динамический массив, в отличие от статического, объявляется как ссылка на некоторый адрес, по которому будут размещаться данные, напри­мер, Var V = array of real; VI = array of integer;.

Каждая из объявленных переменных (v или vi) может иметь значение какого-то адреса. Прежде чем располагать данные, этот адрес переменная

68

должна получить. Память под данные выделяется процедурой SetLength: SetLength(V,5); SetLength(VI,10);.

В данном случае объявлено 5 элементов одномерного массива вещест­венных чисел v и 10 элементов массива целых чисел vi. Нужное количество памяти выделится процедурой SetLength, эта же процедура присвоит кон­кретные значения адресов переменным v и vi.

Имеются особенности в использовании динамических массивов. Первая -нумерация индекса всегда начинается с нуля. Вторая особенность касается правил выполнения операции присваивания, например, пусть объявлено: lype Vekt = array of real; Var VI,V2:Vekt;. Присваивание VI :=V2; для статических массивов означает, что содержимое памяти VI за­меняется содержимым памяти V2 (элементы массива VI получили значения элементов V2). Если учесть, что в случае с динамическими массивами vi и V2 являются ссьшками (адресами), адрес VI заменяется на адрес V2. Таким образом, присваивание vi: =V2; привело к тому, что VI и V2 ссылаются те­перь на один и тот же участок памяти, т.е. элементы массива VI равны эле­ментам V2, но потерялся адрес vi, соответственно потерялся и выделенный участок памяти, начиная с адреса VI.

Освободить память, выделенную под VI, можно, вызвав перед операцией присваивания vi :=V2; процедуру Finalize: Finalize (VI); или просто при­своив VI:=nil;.

Динамические массивы могут быть и многомерными, например объявив Var W:array of array of real;. Далее в программе можно задать раз­мерности массива SetLength (W, 5,10) ;.

Динамические массивы позволяют, например, создавать треугольные матрицы, имеющие различные размерности индексов. Интерес к таким мас­сивам в вычислительной математике очень большой. Для создания таких массивов сначала нужно задать размерность по первому индексу, например Для объявленного выше двумерного массива W так: SetLength (w,3) ;. Это означает, что массив будет состоять из 3 строк. Теперь длину каждой строки зададим отдельно: SetLength(W[0] ,1) ; SetLength(W[l] ,2) ; SetLength (w[2] ,3) ;• Если требуется освободить память из-под такого массива, то используется один вызов процедуры Finalize или одно при­сваивание W:=nil;.

Начальный и конечный индексы динамического одномерного массива v Можно определять функциями Low (V) (равно 0) и High (V) . Так, например, в следующем операторе For i: =Low (v) to High (V) do . . . ; целесо­образно не указывать непосредственно верхнюю границу для циклических вычислений, поскольку в программе можно неоднократно менять размер­ность динамических массивов.

69

ПРИМЕР ПРИЛОЖЕНИЯ 8

Задан одномерный массив чисел X = (0,2; 0,7; 1,8; 3,1; 4,2). Получить таблицу косинусов для этих чисел, т.е. рассчитать cos(0,2), cos(0,7), cos(4,2). На рис. 23 представлен вариант решения этого примера.

Рис.23

Для решения задачи был использован новый компонент TStringGrid (таблица строк), который находится на странице Additional палитры компо­нентов. Данный компонент представляет собой двумерную таблицу. Число строк задается свойством RowCount, а число столбцов - ColCount. Размеры одной ячейки таблицы на экране задаются свойствами DefaultColHeight и DefaultRowWidth в пикселах. Компонент может использоваться для имита­ции чего-либо похожего на таблицу. Доступ к отдельной ячейке таблицы осуществляется с помощью свойства Cells[ij], где i - номер столбца, j - но­мер строки. Отсчет номеров столбца и строки начинается с нуля. Часть строк и столбцов, используемых в таблице, можно зафиксировать. Тогда они будут недоступны пользователю. Для этого нужно задать свойство FixedRows и FixedCols (фиксированное число строк и столбцов). Фиксированные колон­ки и строки закрашиваются в другой цвет. Используются они для заголов­ков. С помощью свойства goEdit можно запретить или разрешить редакти­рование ячеек таблицы.

В данном примере для StringGridl установлено: ScroIIBars = ssNone, RowCount = 6, ColCount = 3, FixedRows = 1, FixedCols = 1, GoEdit = false. Ниже приводится программа для данного примера.

unit prim8; interface

uses Windows, Messages, SysUtils,Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, Grids;

70

type

TForm1 = class(TForm)

Panel1: TPanel;

Button1: TButton;

BitBtnl: TBitBtn;

StringGridl: TStringGrid;

procedure Button1Click(Sender: TObnect);

end;

Form1: TForm1; implementation

Procedure TForm1.Button1Click(Sender: TObject) ;

,3.1,4.2);

x:array [l..n] of real =(0.2,0.7,1 var i:integer;

begin

for i:=l to n do

StringGridl.Cells[0,i]:=IntToStr(i)+’ элемент’;

StringGridl.Cells[1,0]: = ' x’;

StringGridl.Cells[2,0]: = ' x’;

for i:=l to n-do begin

StringGridl.Cells[l,i]: =

FormatFloat(' StringGridl.Cells[2,i] : = FormatFloat(' 0.0000’, cos(x[i]));

end; end; end.

СТРОКИ

В Delphi существует 5 типов строк:

  • ShortString - короткая строка;

  • AnsiString - длинная строка;

  • WideString - длинная строка в кодировке UNICODE;

  • String - универсальная строка;

  • PChar - строка, оканчивающаяся нулевым кодом (#0), введена для со­ вместимости с другими языками программирования (такие строки исполь­ зуются в C++ и Windows).

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

71

получает ее в процессе выполнения программы, а не на этапе компиляцщ! (статическая память). Переменная типа PChar - это ячейка памяти, содержа! щая адрес строки. По этому адресу записываются необходимые данные. Компилятор выделяет под переменную PChar всего 4 байта, а сама строка. которая размещается по адресу, записанному в эти 4 байта, может быть лю­бой длины. Если строки не существует, а переменная PChar объявлена, то J эту переменную необходимо записать 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 strl: string; str2: PChar; и выполнены присваивания: I strl:=' Pascal' ; str2:= ' Pascal' ; тогда atr[l] представляет символ! ЧР', a str2 [1] -символ *а'.

Co строками возможны операции конкатенации (сложения) и сравнения. Складываются строки, используя знак '+'. При сравнении строк действия выполняются слева направо в соответствии с ANSI-кодами отдельных сим­волов. Например, код А меньше, чем а. Если строки разной длины, то корот­кая строка дополняется справа, причем код, который участвует в дополнении строки, меньше кода любого символа, существующего в ANSI-кодировке.

Если в операциях участвуют строки разного типа, то очень часто необ­ходимо явное преобразование типов.

Для выполнения различных операций над строками существует множе­ство подпрограмм (табл. 11).

72

Таблица 11

Операшя

Описание

copy(S, Pos, len)

Возвращает подстроку длиной len символов из строки S начиная с символа номер pos

lenght(S)

Возврашает фактическую (динамическую) длину строки S

Pos(substr, S)

Возвращает позицию первого вхождения подстроки substr в строку S

SetLenght(S, newlen)

Задает новую гитну newlen строке S

StringOfChar(Ch, Count)

Возвращает строку, заполненную символом Ch в количестве Count

Trim(s)

Возвращает строку без начальных и конечных пробелов

UpperCase(S)

Возвращает строку с прописными буквами

ПРИМЕР ПРИЛОЖЕНИЯ 9

Провести исследование различных видов диалоговых окон вывода со­общений. Для отображения сообщений существует пять основных диалого­вых окон.

ShowMessage отображает статические сообщения. Это диалоговое окно отображает в центре экрана строку текста и кнопку "ОК" (рис. 24). Вызыва­ется посредством использования процедуры ShowMessage(S), где S - строка типа String.

ShowMessagePos (рис. 25) предназначено для тех же целей, что и ShowMessage. При вызове, кроме строки текста, процедуре необходимо пе­редать экранные координаты X и Y расположения этого окна.

Рис. 25

Ряс. 24

В отличие от предыдущих диалоговых окон, MessageBox (рис. 26) по­зволяет задавать две строки: заголовок окна и поясняющий текст. Про­граммно вызов оформлен в виде функции. Эта функция возвращает то зна­чение, на какой кнопке щелкнул пользователь. Число отображаемых кнопок может быть одна или более и задается с помощью аргумента, представляю­щего собой набор предопределенных констант. Передаваемые в функцию строки заголовка и текста должны иметь тип PChar. Если эти строки типа String, то необходимо использовать преобразование типов, записывая Р = =PChar(S), где Р типа PChar, a S - String

MessageDlg (рис. 27) отличается от MessageBox тем, что заголовок этого окна предопределен.

Рис. 26 Рис. 27

Функция MessageDlg имеет 4 аргумента: первый передает текст в виде

строки типа String, второй - вариант заголовка, третий - какие кнопки будут отображаться, четвертый позволяет организовать связь с файлом подсказки Help.

Рис. 28

Как и в случае предыдущего окна, функция возвращает, на какой кнопке щелкнул пользователь. Окно Mes­sageDlg располагается в центре экрана. MessageDlgFos (рис. 28) является вариантом MessageDlg с той лишь разни­цей, что этому виду диалогового окна необходимо передавать координаты X и Y его расположения на экране.

Форма примера 9 представлена на рис. 29.

Рис. 29

Для реализации локального меню выбора варианта диалогового окна ис­пользовался компонент TRadioGroup - группа взаимосвязанных переклю­чателей TRadioButton.

С помощью свойства Items создается список взаимоисключающих аль­тернатив, в данном случае из пяти строк, для каждой из которых создаете* переключатель. При выборе мышью (или стрелками) того или иного пере­ключателя в списке фиксируется строка и ее номер, который позволяет в

74

программе обеспечить выполнение того или иного кода. Выбранный номер чаписывается в свойстве Itemlndex. Нумерация переключателей задается от ля. Переключатели можно располагать не только в один, но и в несколько столбцов. Число столбцов задается в свойстве Columns. С помощью свойст­ва Caption можно задавать заголовок всей группе взаимозависимых пере­ключателей.

Строки меню заносятся в список. Вызывая в инспекторе объектов свой­ство Items, можно набрать пять строк, а значение Itemlndex установить, на­пример, равным 3. Для данного компонента необходимо создать обрабочик OnCHck.

Текст программы приводится ниже. В данном примере имя формы (Name) выбрано MainForm, соответственно порождающий эту форму класс имеет имя TMainForm.

unit Prim9;

interface

uses SysUtils, Windows, Messages, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Buttons;

type TMainForm = class (TForm)

RadioGroupl: TRadioGroup; Bevell: TBevel; Label1: TLabel; BitBtnl: TBitBtn;

procedure RadioGrouplClick(Sender: TObject); end;

var MainForm: TMainForm; imp1ementation {$R *.DFM}

procedure TMainForm.RadioGrouplClick(Sender: TObject); const sde=’Демонстрация '; sbi='Было выбрано’; var TheText,TheCaption: String;

S: String[6]; W: Word; X, Y: Integer; begin

case RadioGroupl.Itemlndex of 0 : ShowMessage(sde+'ShowMessage'); 1:begin

X := 50; Y := 60;

ShowMessagePos(sde+'ShowMessagePos',X,Y); end; 2: begin

TheText := 'Текст-пояснение к MessageBox'; TheCaption :- sde+'MessageBox '; if Application.MessageBox(PChar(TheText), PChar(TheCaption),MB_DEFBUTTON1 +

75

MB_ICONEXCLAMATION + MB_OKCANCEL) = IDOK

then ShowMessage(sbi+'OK') else ShowMessage(sbi+'Cancel'); end; 3:begin

W := MessageDlg(sde+'MessageDlg'

[mbYes, mbNo, mblgnore],0); case W of

mrYes: S := 'Yes'; mrNo: S := 'No'; mrlgnore: S := 'Ignore1; . end; {case} ShowMessage(sbi + S); end; ;

4:begin

X := 50; Y := 75;

W := MessageDlgPos(sde+'MessageDlgPos', mtWarning,mbAbortRetryIgnore, 0, X, Y) ; case W of

mrAbort: S := 'Abort'; mrRetry: S := 'Retry'; mrlgnore: S := 'Ignore'; end; {case} ShowMessage(sbi + S) ; end;

end; {case} end; end.

В программе при объявлении строки s задана максимальная длина при-сваимого ей значения, равная 6 символам. Аргумент функции MessageDlg, заданный в квадратных скобках, означает, что с помощью конструктора множества передается некоторое заданное множество.

ЗАПИСИ (ОБЪЕДИНЕНИЯ)

С помощью зарезервированного слова "record" в единой структуре можно объединить данные разных типов. Общий синтаксис объявления та­кого объединения следующий:

Туре <имя типа> = Record <СПисок полей>: <тип>; <Список полей>:

End;.

Поля записи (или объединения) могут быть любого типа, число их не ог­раничено. Например,

{Тип комплексных чисел}

туре

Complex = record

Re, Im: real;

end;

{Тип - дата рождения}

Data = record

Year:word;

Month: 1..12;

{Тип - сведения о сотруднике}

Day: 1..31; end; Person = record

Name: string[40];

Age: word;

Adres: string[80]; end;.

Количество памяти, выделяемой под запись, может быть различным в зависимости от директивы {$А} (выравнивание). Если установлено {$А+}, то поля выравниваются по четным адресам - уменьшается время доступа к переменной в памяти. По умолчанию установлено {$А-}. Перед ключевым словом "record" можно добавить слово "Packed". В этом случае под запись выделяется минимальное количество байт, причем директива {$А} игнори­руется.

После объявления типа можно объявить переменные или типизирован­ные константы, например,

Var Z: Data;

X: Complex; Const

Birthday:Data=(Year:197 4;Month:7;Day: 12) ; Petrov:Person=(Name:'Иван';Age:22;

Adres:'Новомосковск,Мира,20,3');

Доступ к полям записи в программе осуществляется следующим способом:

2.Year:=1969; {Z - селектор записи; Year - поле}. Z.Month:=7; Z.Day:=13; X.Re: 0.8; X.Im: 2.1; Z.Month:= Z.Day div 5+2;

Тип данных запись может иметь так называемую вариантную часть. Ва­риантная часть позволяет трактовать по-разному занимаемую полями одну и ту же память.

Туре

pigure=(Square,Triangle,Circle);

e a Record

integer;

76

77

Year:= 1971; Month:=5; Day:=28;

god;

ПРИМЕР ПРИЛОЖЕНИЯ 10

Пусть требуется рассчитать зарплату 3, премию П и итоговую сумму И явум сотрудникам в соответствии с табл. 12.

Case fig: Figure of

Square: (Side: integer);

Triangle: (Sidel,Side2,Angle: integer);

Circle: (Radius: integer); end;

В данном случае задан перечисляемый тип для обозначения трех геомet рических фигур: квадрата, треугольника и окружности. Далее вводится о&ь единение: х, Y - координаты привязки этих фигур на некоторой плоскости Side (сторона) определяет квадрат, sidel, Side2, Angle (угол) определяю* треугольник, Radius - окружность. Начиная с ключевого слова case, запц, сывается вариантная часть. Память выделяется одна. Трактовать ее можно! данном случае так: в памяти находится или одна величина Side, или тря величины Sidel, Side2, Angle, или одна величина Radius. Когда и ка* трактовать память, выбирает программист.

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

Case Figure of

Square: (Side: integer); Triangle: (Sidel,Side2,Angle: integer); Circle: (Radius: integer);.

Как замечено выше, память под вариантную часть выделяется одна и та же. В данном случае для Triangle требуется записать три величины типа integer, больше, чем для других фигур. Поэтому под вариантную часть будет выделено 12 байт памяти (по 4 байта на каждую величину).

Далее выберем две переменные и запишем данные в эти переменные:

Var MySquare: G; MyCircle: G;

…………………………

MySquare.Side:= 5; MyCircle.Radius: = 10;

Как можно заметить, отличий в записи информации в вариантные поля от обычных полей на этом уровне не существует. Если попытаться в примере выше прочитать значение MySquare. Side, то оно будет равно 10, так как последняя запись в общую память была именно такой (MyCircle.Radius: - 10;).